10 Commits

Author SHA1 Message Date
lyrathorpe 2a1e6dc8a4 Merge pull request 'feat(messages): add initial messages' (#6) from feat/reasons-why into main
Build and publish container / build (push) Successful in 5m59s
Reviewed-on: #6
2026-06-11 21:08:15 +01:00
lyrathorpe 6b19a55655 feat(messages): add initial messages
Build and publish container / build (pull_request) Successful in 4m22s
more added later on
2026-06-11 21:03:31 +01:00
lyrathorpe a2b9d445e4 Merge pull request 'Fix/theme colours' (#5) from fix/theme-colours into main
Build and publish container / build (push) Successful in 6m18s
Reviewed-on: #5
2026-06-11 17:49:40 +01:00
Emma Thorpe a14306cce4 fix: recolour original theme to a cream field with blue text
Build and publish container / build (pull_request) Successful in 4m51s
Use a cream/white background with navy message text and red buttons, so the
original red/white/blue livery presents blue text rather than white text on a
blue field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 17:41:55 +01:00
Emma Thorpe 43f42a8274 fix: use solid theme backgrounds instead of a gradient
Replace the body background gradient with the solid theme colour and remove
the now-unused --bg-accent variables from both colour schemes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 17:36:47 +01:00
lyrathorpe 8376860fb4 Merge pull request 'fix: build multi-arch images for amd64 and arm64' (#4) from fix/multi-arch-build into main
Build and publish container / build (push) Successful in 6m51s
Reviewed-on: #4
2026-06-11 17:26:57 +01:00
Emma Thorpe d1803f06dd fix: build multi-arch images for amd64 and arm64
Build and publish container / build (pull_request) Successful in 5m2s
Add QEMU setup and build for linux/amd64 and linux/arm64 (armv8), publishing
a single multi-arch manifest. The nginx-unprivileged base image provides both
architectures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 17:20:20 +01:00
lyrathorpe ea16d1b21b Merge pull request 'ci: tag images by semver and point latest at newest release' (#3) from ci/image-tagging into main
Build and publish container / build (push) Successful in 3m32s
Reviewed-on: #3
2026-06-11 17:10:26 +01:00
Emma Thorpe 99084cc597 feat: auto-release images from conventional commits on main
Build and publish container / build (pull_request) Successful in 2m58s
On each push to main, derive the next semantic version from the
conventional-commit messages since the last v* tag (feat -> minor,
fix/perf -> patch, \! or BREAKING CHANGE -> major) and, when a release is
warranted, build and publish the image tagged X.Y.Z, X.Y, X and latest,
then record an annotated vX.Y.Z tag for the next computation. Non-release
pushes publish a sha-<short> image only.

Configure Renovate to commit updates as fix(deps): so each merged Renovate
PR registers as a patch change and is released and tagged automatically.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 17:04:40 +01:00
Emma Thorpe d296d88c4c ci: tag images by semver and point latest at newest release
Build and publish container / build (pull_request) Successful in 1m59s
Replace the raw latest-on-default-branch tag, which moved latest on every
main push, with metadata-action's latest=auto flavor so latest follows the
newest non-prerelease v* release. Add a {{major}} tag alongside the
existing version and major.minor semver tags; branch and SHA tags remain
for traceability of non-release builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 16:43:33 +01:00
5 changed files with 145 additions and 39 deletions
+96 -20
View File
@@ -3,29 +3,102 @@ name: Build and publish container
on: on:
push: push:
branches: [main] branches: [main]
tags: ["v*"]
pull_request: pull_request:
branches: [main] branches: [main]
defaults:
run:
shell: bash
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: write
packages: write packages: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
# Full history and tags are required to derive the next version
# from the conventional-commit messages since the last release.
fetch-depth: 0
- name: Determine registry host - name: Determine registry host
run: echo "REGISTRY=${GITHUB_SERVER_URL#*://}" >> "$GITHUB_ENV" run: echo "REGISTRY=${GITHUB_SERVER_URL#*://}" >> "$GITHUB_ENV"
# Derive the release version from conventional commits since the last
# v* tag: feat -> minor, fix/perf -> patch, ! or BREAKING CHANGE -> major.
# Anything else (chore, ci, docs, build) produces no release; those builds
# are published under a sha-<short> tag only.
- name: Compute version and image tags
id: version
run: |
set -euo pipefail
image="${REGISTRY}/${GITHUB_REPOSITORY,,}"
last_tag="$(git tag --list 'v*' --sort=-v:refname | head -n1 || true)"
if [ -n "$last_tag" ]; then
range="${last_tag}..HEAD"
base="${last_tag#v}"
else
range=""
base="0.0.0"
fi
subjects="$(git log ${range} --format='%s')"
bodies="$(git log ${range} --format='%B')"
bump="none"
if printf '%s\n' "$bodies" | grep -qiE 'BREAKING[ -]CHANGE' \
|| printf '%s\n' "$subjects" | grep -qE '^[a-z]+([(][^)]*[)])?!:'; then
bump="major"
elif printf '%s\n' "$subjects" | grep -qE '^feat([(][^)]*[)])?:'; then
bump="minor"
elif printf '%s\n' "$subjects" | grep -qE '^(fix|perf)([(][^)]*[)])?:'; then
bump="patch"
fi
major="${base%%.*}"
rest="${base#*.}"
minor="${rest%%.*}"
patch="${rest##*.}"
release="false"
if [ "${GITHUB_EVENT_NAME}" = "push" ] && [ "$bump" != "none" ]; then
release="true"
case "$bump" in
major) major=$((major + 1)); minor=0; patch=0 ;;
minor) minor=$((minor + 1)); patch=0 ;;
patch) patch=$((patch + 1)) ;;
esac
version="${major}.${minor}.${patch}"
{
echo "tags<<__EOT__"
echo "${image}:${version}"
echo "${image}:${major}.${minor}"
echo "${image}:${major}"
echo "${image}:latest"
echo "__EOT__"
} >> "$GITHUB_OUTPUT"
echo "version=${version}" >> "$GITHUB_OUTPUT"
else
short="$(git rev-parse --short HEAD)"
{
echo "tags<<__EOT__"
echo "${image}:sha-${short}"
echo "__EOT__"
} >> "$GITHUB_OUTPUT"
fi
echo "release=${release}" >> "$GITHUB_OUTPUT"
echo "Computed bump=${bump}, release=${release}, base=${base}"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Buildx - name: Set up Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
# Uses a Personal Access Token with package read/write scope, stored as
# the PACKAGES_TOKEN secret. The auto-provided GITEA_TOKEN does not carry
# container-registry write permission on most Gitea instances.
- name: Log in to the Gitea container registry - name: Log in to the Gitea container registry
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v3 uses: docker/login-action@v3
@@ -34,23 +107,26 @@ jobs:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.PACKAGES_TOKEN }} password: ${{ secrets.PACKAGES_TOKEN }}
- name: Extract image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.version.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
# Record the release as an annotated git tag so the next run computes the
# following version from it. This push does not re-trigger the workflow,
# which only listens on the main branch and pull requests.
- name: Tag the release
if: steps.version.outputs.release == 'true'
run: |
set -euo pipefail
v="v${{ steps.version.outputs.version }}"
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.${REGISTRY}"
git tag -a "$v" -m "$v"
git push origin "$v"
+29 -5
View File
@@ -45,9 +45,10 @@ docker run --rm -p 8080:8080 dlr
## CI ## CI
`.gitea/workflows/build-and-publish.yml` builds the container with Gitea Actions `.gitea/workflows/build-and-publish.yml` builds the container with Gitea Actions
and publishes it to this Gitea instance's container registry on pushes to `main` on every push to `main` and on pull requests. Pull requests build the image but
and on `v*` tags. Pull requests build the image but do not push. The registry do not push. The registry host is derived from the Gitea server URL. Images are
host is derived from the Gitea server URL. built for `linux/amd64` and `linux/arm64` (armv8) and published as a single
multi-arch manifest; the arm64 build runs under QEMU emulation.
Authentication requires a Personal Access Token with package read/write scope, Authentication requires a Personal Access Token with package read/write scope,
because the automatically provided `GITEA_TOKEN` does not carry container because the automatically provided `GITEA_TOKEN` does not carry container
@@ -55,8 +56,27 @@ registry write permission on most Gitea instances. Create the token under an
account with write access to the target package namespace, then store it as a account with write access to the target package namespace, then store it as a
repository Actions secret named `PACKAGES_TOKEN`. repository Actions secret named `PACKAGES_TOKEN`.
The published image is `<gitea-host>/<owner>/<repo>`, tagged by branch, semver ### Automatic releases
(for `v*` tags), commit SHA, and `latest` on the default branch.
The published image is `<gitea-host>/<owner>/<repo>`. Releases are derived from
[Conventional Commits](https://www.conventionalcommits.org/). On each push to
`main`, the workflow inspects the commits since the last `v*` tag and computes
the next version:
- `feat:` → minor bump,
- `fix:` / `perf:` → patch bump,
- `!` or `BREAKING CHANGE` → major bump,
- anything else (`chore`, `ci`, `docs`, `build`) → no release.
When a release is warranted, the image is published with `X.Y.Z`, `X.Y`, `X` and
`latest` tags, and the workflow records an annotated `vX.Y.Z` git tag so the next
release is computed from it. Pushes to `main` that warrant no release are
published under a `sha-<short>` tag only, so `latest` always points at the most
recent release rather than the newest commit.
Recording the release tag requires the workflow's `contents: write` permission;
if the instance forbids the automatic token from pushing, supply a PAT with
repository write scope and push the tag with it instead.
## Dependency updates ## Dependency updates
@@ -77,6 +97,10 @@ CDN, Renovate will track it if it is either annotated with a comment, e.g.
or referenced through a versioned jsDelivr / unpkg npm URL, which is detected or referenced through a versioned jsDelivr / unpkg npm URL, which is detected
automatically. automatically.
Renovate is configured to commit updates as `fix(deps): …`. Each merged Renovate
PR therefore registers as a patch-level change, so the release workflow above
cuts a new patch release and tags the image automatically.
## Files ## Files
| File | Purpose | | File | Purpose |
+9 -4
View File
@@ -11,8 +11,13 @@
*/ */
const MESSAGES = [ const MESSAGES = [
"PLACEHOLDER: write your first reason here", "Maggie came back, she was unimpressed",
"PLACEHOLDER: write another reason here", "They mixed up the B23s and the 2024 tube stock",
// Add as many entries as you like, one per line: "The computer went on strike",
// "Your reason here", "Leaves on the track",
"Escalators broke at Cutty Sark",
"EHRC decided it was woke",
"JK Rowling",
"Kaiju",
"28 Days Later happened",
]; ];
+3
View File
@@ -6,6 +6,9 @@
":semanticCommits" ":semanticCommits"
], ],
"labels": ["renovate"], "labels": ["renovate"],
"semanticCommits": "enabled",
"semanticCommitType": "fix",
"semanticCommitScope": "deps",
"github-actions": { "github-actions": {
"fileMatch": ["^\\.gitea/workflows/[^/]+\\.ya?ml$"] "fileMatch": ["^\\.gitea/workflows/[^/]+\\.ya?ml$"]
}, },
+8 -10
View File
@@ -10,7 +10,6 @@
/* Modern DLR — turquoise/teal */ /* Modern DLR — turquoise/teal */
[data-theme="modern"] { [data-theme="modern"] {
--bg: #00afaa; --bg: #00afaa;
--bg-accent: #007e7a;
--surface: #ffffff; --surface: #ffffff;
--text: #ffffff; --text: #ffffff;
--message: #ffffff; --message: #ffffff;
@@ -20,17 +19,16 @@
--button-active-text: #ffffff; --button-active-text: #ffffff;
} }
/* Original DLR — 1987 red and blue */ /* Original DLR — 1987 red, white and blue */
[data-theme="original"] { [data-theme="original"] {
--bg: #002b5c; --bg: #f5f0e1;
--bg-accent: #c8102e; --surface: #002b5c;
--surface: #f5f0e1; --text: #002b5c;
--text: #f5f0e1; --message: #002b5c;
--message: #f5f0e1;
--button-bg: #c8102e; --button-bg: #c8102e;
--button-text: #f5f0e1; --button-text: #f5f0e1;
--button-active-bg: #f5f0e1; --button-active-bg: #002b5c;
--button-active-text: #002b5c; --button-active-text: #f5f0e1;
} }
* { * {
@@ -44,7 +42,7 @@ body {
flex-direction: column; flex-direction: column;
font-family: var(--font-stack); font-family: var(--font-stack);
color: var(--text); color: var(--text);
background: linear-gradient(135deg, var(--bg) 0%, var(--bg-accent) 100%); background: var(--bg);
transition: background 0.4s ease, color 0.4s ease; transition: background 0.4s ease, color 0.4s ease;
} }