From 950d116e536144ab66326b1b780ab1ea01a03f5c Mon Sep 17 00:00:00 2001 From: Aneurin Barker Snook Date: Sat, 5 Sep 2026 12:38:05 +0100 Subject: [PATCH] Add image build/push workflows, scoped to test/build/push only Builds and pushes to Gitea's container registry on push to main ("latest"/"previous", to avoid accumulating per-commit tags) and on git tag push (tagged to match). Deployment is intentionally out of scope here -- that work is being split into a separate project. Co-Authored-By: Claude Sonnet 5 --- .gitea/workflows/build.yml | 60 ++++++++++++++++++++++++++++++++++++ .gitea/workflows/release.yml | 50 ++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 .gitea/workflows/build.yml create mode 100644 .gitea/workflows/release.yml diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..cbf0412 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,60 @@ +name: Build + +# Builds the image on every push to main and pushes it to Gitea's container +# registry as "latest" (after first re-tagging the current "latest" as +# "previous", for a one-step-back rollback point -- no-ops on the very first +# run, when there's no existing "latest" to promote). Deliberately just +# "latest"/"previous", not per-commit tags, to avoid accumulating history. +# See release.yml for tagged releases (git tag -> matching image tag). +# +# This project's CI/CD scope is intentionally just test/build/push -- +# deployment is being split into a separate project. +# +# Requires secrets.GITEA_TOKEN (auto-injected by Gitea Actions; needs the +# "packages" permission scope to push images). + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + build-and-push: + runs-on: ubuntu-latest + # Assumes the runner forwards the host's Docker socket into job + # containers -- if this job fails to reach a daemon, add + # container.options: -v /var/run/docker.sock:/var/run/docker.sock + # (and allow that path in valid_volumes) to the runner's config.yaml. + container: + image: docker:cli + options: -v /var/run/docker.sock:/var/run/docker.sock + steps: + # actions/checkout is a JS action; docker:cli is Alpine-based and has + # no node on PATH by default (same issue fixed in ci.yml). + - name: Install Node + run: apk add --no-cache nodejs + + - uses: actions/checkout@v4 + + - name: Log in to the container registry + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: echo "$GITEA_TOKEN" | docker login code.aneur.in -u "${{ gitea.actor }}" --password-stdin + + - name: Promote the current "latest" to "previous" + run: | + IMAGE="code.aneur.in/${{ gitea.repository }}" + if docker pull "$IMAGE:latest"; then + docker tag "$IMAGE:latest" "$IMAGE:previous" + docker push "$IMAGE:previous" + fi + + - name: Build and push "latest" + run: | + IMAGE="code.aneur.in/${{ gitea.repository }}:latest" + docker build -t "$IMAGE" . + docker push "$IMAGE" diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..5e32314 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,50 @@ +name: Release + +# Builds and pushes an image tagged to match the git tag that triggered this +# run -- e.g. pushing tag "v1.2.3" produces code.aneur.in//:v1.2.3. +# Separate from build.yml's "latest"/"previous" tracking on push to main. +# This project's CI/CD scope is intentionally just test/build/push -- +# deployment (including how a given tag actually gets deployed) is being +# split into a separate project. +# +# Assumes tags are cut from commits already on main (and so already covered +# by ci.yml's checks) -- this workflow doesn't run the test suite itself. +# +# Requires secrets.GITEA_TOKEN (auto-injected; needs the "packages" +# permission scope to push images). + +on: + push: + tags: ['*'] + +permissions: + contents: read + packages: write + +jobs: + build-and-push: + runs-on: ubuntu-latest + # Assumes the runner forwards the host's Docker socket into job + # containers -- see the matching note in build.yml if this can't reach + # a daemon. + container: + image: docker:cli + options: -v /var/run/docker.sock:/var/run/docker.sock + steps: + # actions/checkout is a JS action; docker:cli is Alpine-based and has + # no node on PATH by default (same issue fixed in ci.yml). + - name: Install Node + run: apk add --no-cache nodejs + + - uses: actions/checkout@v4 + + - name: Log in to the container registry + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: echo "$GITEA_TOKEN" | docker login code.aneur.in -u "${{ gitea.actor }}" --password-stdin + + - name: Build and push the image + run: | + IMAGE="code.aneur.in/${{ gitea.repository }}:${{ gitea.ref_name }}" + docker build -t "$IMAGE" . + docker push "$IMAGE" -- 2.54.0