From df4fcfc659ce91094106692eda8fad08db231c8d Mon Sep 17 00:00:00 2001 From: Jeff Smith Date: Sun, 19 Apr 2026 18:01:58 -0600 Subject: [PATCH] feat(ci): Forgejo Actions deploy workflow for home-ctr-onyx (#30) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On push to main, the homelab runner (container mode, docker socket mounted) builds the image, pushes it to the Forgejo registry tagged with the commit SHA and latest, then runs docker compose pull + up -d directly against the host Docker daemon — no SSH hop, since the runner already lives on the deploy host. Finishes with one curl -u admin:... against https://quartermaster.unbiasedgeek.com/healthz to catch TLS, Traefik routing, and basic-auth regressions in a single probe. Two repo-scoped secrets required: REGISTRY_TOKEN for docker login and QUARTERMASTER_SMOKE_PASSWORD for the public healthz probe. Co-Authored-By: Claude Opus 4.7 (1M context) --- .forgejo/workflows/deploy.yml | 62 +++++++++++++++++++++++++++++++++++ README.md | 31 ++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 .forgejo/workflows/deploy.yml diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml new file mode 100644 index 0000000..2a006f0 --- /dev/null +++ b/.forgejo/workflows/deploy.yml @@ -0,0 +1,62 @@ +name: deploy + +on: + push: + branches: + - main + +jobs: + build-push-deploy: + runs-on: homelab + env: + REGISTRY: forgejo.labbity.unbiasedgeek.com + IMAGE: forgejo.labbity.unbiasedgeek.com/archeious/quartermaster/quartermaster + COMPOSE_PROJECT_NAME: quartermaster + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Forgejo registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: archeious + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: | + ${{ env.IMAGE }}:${{ github.sha }} + ${{ env.IMAGE }}:latest + + - name: Deploy + run: | + set -euo pipefail + printf 'QUARTERMASTER_TAG=%s\n' '${{ github.sha }}' > .env + docker compose pull + docker compose up -d + + - name: Smoke test + env: + SMOKE_PASSWORD: ${{ secrets.QUARTERMASTER_SMOKE_PASSWORD }} + run: | + set -eu + for attempt in 1 2 3 4 5 6 7 8 9 10; do + code=$(curl -sS -o /dev/null -w '%{http_code}' \ + -u "admin:$SMOKE_PASSWORD" \ + https://quartermaster.unbiasedgeek.com/healthz || echo "000") + if [ "$code" = "200" ]; then + echo "smoke OK after $attempt attempt(s)" + exit 0 + fi + echo "attempt $attempt: got $code, retrying" + sleep 3 + done + echo "smoke FAILED — last code $code" + exit 1 diff --git a/README.md b/README.md index ba7d9e6..bc9fb77 100644 --- a/README.md +++ b/README.md @@ -167,3 +167,34 @@ editing the checked-in compose file. path. Three would resolve relative to the working directory, and the SQLite file would NOT land on the bind mount (on next restart the database would be empty). + +## CI/CD + +Push to `main` triggers `.forgejo/workflows/deploy.yml` on the +`homelab` runner. That runner lives on home-ctr-onyx itself in +container mode with the host's Docker socket mounted — so the +workflow talks to the same Docker daemon that hosts the production +container and no SSH round-trip is needed. + +The workflow: checks out the repo, builds the image, pushes it to +the Forgejo registry tagged with the commit SHA and `latest`, +writes `QUARTERMASTER_TAG=` to a `.env` file next to the +checked-out `compose.yml`, runs `docker compose pull && docker +compose up -d`, and finishes with one +`curl -fsS -u admin:… https://quartermaster.unbiasedgeek.com/healthz` +against the public URL — catching TLS, Traefik routing, and the +basic-auth middleware in a single probe. + +The workflow reads two Forgejo Actions secrets (repo-scoped under +`archeious/quartermaster`): + +* `REGISTRY_TOKEN` — archeious Forgejo personal token with + `write:package` scope; used as the docker-login password. +* `QUARTERMASTER_SMOKE_PASSWORD` — plaintext basic-auth password + for the `admin` user, delivered to the tenant out-of-band by the + platform team. + +Rollback is manual for v1: `git checkout` the previous SHA, set +`QUARTERMASTER_TAG` in `.env` to that SHA, and `docker compose up -d` +from a clone of the repo (or let the previous commit be the `main` +tip and the deploy workflow will roll it out).