ci: restore bump-prod-compose auto-deploy job on v* release
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 6s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m32s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m44s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Build ErsatzTV Image / Bump prod compose tag (server-management) (pull_request) Has been skipped
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m8s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 9m59s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 7m9s
Build ErsatzTV Image / Bump prod compose tag (server-management) (push) Has been skipped

The auto-pin-to-prod job designed on the unmerged `ci/auto-bump-prod-compose`
branch (3d6ac883) never landed on main — so v* releases (v26.5.0, v26.6.0) did
NOT auto-bump the server-management compose pin (it sat at 26.5.0). The docs
(homelab-docs Docker/ErsatzTV.md, ci-cd.md) described the auto-bump as if live.

Restore the job verbatim (its credentials already exist: the `ersatztv-ci-deploy`
write deploy key, id 5, on server-management + the SERVERMGMT_DEPLOY_KEY secret
here). On a v* tag, after the test-gated image builds, it rewrites the pinned
`ersatztv:<version>` tag in docker/bumblebee/stacks/media-servers/compose.yaml
and pushes to server-management `master` → the Gitea->Komodo webhook redeploys
prod with a pre-deploy backup. Idempotent (no-op if already pinned).

docs/ci-cd.md updated to match (release procedure + the stale ":prod pin" claim,
which was actually an immutable :<version> pin since 2026-07-07).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #275.
This commit is contained in:
2026-07-11 21:44:36 +02:00
co-authored by Claude Opus 4.8
parent 78262ea4cb
commit 0ff21d5b8e
2 changed files with 46 additions and 5 deletions
+38
View File
@@ -341,3 +341,41 @@ jobs:
else
echo "Parity-doc reminder: nothing to flag."
fi
# Prod GitOps deploy: on a v* release, after the test-gated image is built and
# pushed (:prod + :<version>), rewrite the pinned ersatztv tag in the
# server-management media-servers compose so the Gitea->Komodo webhook redeploys
# (its pre-deploy hook backs up first). Keeps prod pinned + backed up rather than a
# floating :prod (see docs/ci-cd.md + homelab-docs/Docker/ErsatzTV.md). Credentials:
# write deploy key `ersatztv-ci-deploy` (id 5) on server-management + the
# SERVERMGMT_DEPLOY_KEY secret here. server-management's default branch is `master`.
bump-prod-compose:
name: Bump prod compose tag (server-management)
runs-on: ubuntu-latest
needs: [build]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Bump ersatztv prod tag in media-servers compose
run: |
set -euo pipefail
VERSION="${GITHUB_REF_NAME#v}"
mkdir -p ~/.ssh
printf '%s\n' "${{ secrets.SERVERMGMT_DEPLOY_KEY }}" > ~/.ssh/id_deploy
chmod 600 ~/.ssh/id_deploy
ssh-keyscan -p 22 192.168.1.95 >> ~/.ssh/known_hosts 2>/dev/null
export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_deploy -o IdentitiesOnly=yes -o UserKnownHostsFile=$HOME/.ssh/known_hosts"
rm -rf /tmp/svrmgmt
git clone --depth 1 ssh://gitea@192.168.1.95:22/timothy/server-management.git /tmp/svrmgmt
cd /tmp/svrmgmt
FILE="docker/bumblebee/stacks/media-servers/compose.yaml"
sed -i -E "s|(image: 192\.168\.1\.95:3000/timothy/ersatztv:)[^[:space:]]+|\1${VERSION}|" "$FILE"
if git diff --quiet "$FILE"; then
echo "media-servers compose already pins ersatztv:${VERSION}; nothing to do"
exit 0
fi
git config user.name "ersatztv-ci"
git config user.email "ci@tblindustries.be"
git add "$FILE"
git commit -m "chore(ersatztv): bump prod chicorytv to ${VERSION} [ci auto-deploy]"
git push origin HEAD:master
echo "Pushed prod bump -> ersatztv:${VERSION}; media-servers webhook will deploy with pre-deploy backup."
+8 -5
View File
@@ -20,7 +20,7 @@ Upstream's final release was **`v26.3.0`** (archived). Our line continues from t
| `v26.3.1` | Upstream 26.3.0 **rebuilt on our infra** (Gitea CI/registry, fork ffmpeg base) — **no application changes**. A patch bump, because nothing functional changed. |
| `v26.4.0` | Reserved for our **first release that carries actual app changes** (e.g. the #1 M3U fix). Later 2026 releases: `26.5.0`, `26.6.0`, …; a new year resets to `27.1.0`. |
**Cutting a release:** push a `vYY.N.P` tag on `main` → CI builds `:prod` + `:<version>` + `:<sha>`; server-management does the prod switch (server-management#481).
**Cutting a release:** push a `vYY.N.P` tag on `main` → CI builds `:prod` + `:<version>` + `:<sha>`, then the **`bump-prod-compose`** job rewrites the pinned `ersatztv:<version>` tag in the server-management media-servers compose (via the `ersatztv-ci-deploy` write deploy key, id 5 on server-management + the `SERVERMGMT_DEPLOY_KEY` secret here) and pushes to its `master` branch → the Gitea→Komodo webhook redeploys prod with a pre-deploy backup. **No manual pin bump needed** (the job is idempotent: a no-op if the compose already pins that version).
**Gotcha:** never put a `[skip ci]` token in a commit you intend to tag — Gitea reads skip-ci from the *tagged* commit and will **suppress the release build**. (Also, `workflow_dispatch` on a tag ref isn't supported on this Gitea version, so the tag *push* must do the triggering.) Release commits, and anything you'll tag, must not contain skip-ci.
@@ -29,7 +29,8 @@ Upstream's final release was **`v26.3.0`** (archived). Our line continues from t
## The workflow: `.gitea/workflows/docker-build.yml`
Single workflow. Gating jobs `test` + `migrations` run in parallel and gate `build`; a
non-blocking `docs-reminder` job runs on PRs only (see below).
non-blocking `docs-reminder` job runs on PRs only (see below); a `bump-prod-compose` job
runs only on `v*` tags (after `build`) to auto-deploy prod (see "Cutting a release").
### Triggers & tags
@@ -40,9 +41,11 @@ non-blocking `docs-reminder` job runs on PRs only (see below).
| push tag `v*` | ✅ | ✅ | `:prod` + `:<version>` + `:<short-sha>` |
| `workflow_dispatch` | ✅ | ✅ | only if ref is `main`/`v*`, else build-only (no push) |
`:latest` is the **test/dev** channel (every `main` commit). Prod pins **`:prod`**,
never `:latest` — enforced in the prod compose (server-management#481). `:prod` is
only produced by pushing a `v*` tag.
`:latest` is the **test/dev** channel (every `main` commit). Prod pins the immutable
**`:<version>`** tag (e.g. `ersatztv:26.7.0`) in the compose — never `:latest`, and no
longer a floating `:prod` (pinned since 2026-07-07) — so a redeploy is reproducible and
gated by the `bump-prod-compose` commit. Both `:prod` and `:<version>` are produced by
pushing a `v*` tag; the `bump-prod-compose` job pins the `:<version>` form.
Concurrency is scoped **per event+ref** (`group: ersatztv-build-${{ github.event_name }}-${{ github.ref }}`,
`cancel-in-progress` for PRs): PR runs parallelize across PRs, a new sync auto-cancels