thermograph/.forgejo
Emi Griffith fc455a0473
All checks were successful
PR build (required check) / changes (pull_request) Successful in 9s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
secrets-guard / encrypted (pull_request) Successful in 7s
shell-lint / shellcheck (pull_request) Successful in 9s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 2s
ci: collapse the eight deploy and build-push workflows into two
The six deploy workflows were one file written six times, differing only in a
branch name, a paths filter, a concurrency group, the service name, its
*_IMAGE_TAG variable and a secret prefix. The two build-push workflows were the
same file twice, differing only in the domain string. The contract into
infra/deploy/deploy.sh (SERVICE + BACKEND_IMAGE_TAG/FRONTEND_IMAGE_TAG) was
already fully parameterised, so the duplication bought nothing and cost eight
files to keep in step.

deploy.yml: branch selects the environment (main -> beta, release -> prod), a
matrix covers backend and frontend, and each leg decides whether this push
actually touched its domain before rolling anything. The workflow-level paths
filter only says backend OR frontend moved; without the per-leg refinement a
backend-only push would also roll the frontend and lose the independent-deploy
property the FE/BE split exists for.

build-push.yml: the same shape for images. Images stay separate and
independently deployable; nothing about the published artefacts changes.

The two *-deploy-dev.yml workflows are deleted rather than ported. They were
already documented as inert -- they call a monorepo path on the LAN box whose
~/thermograph-dev is still a split-era thermograph-infra checkout. LAN dev is a
local `make dev-up` concern, not a CI environment.

Deliberately boring expressions throughout. No dynamic matrix (fromJSON), and
the *_IMAGE_TAG selection is done in shell rather than with a
`matrix.service == 'x' && a || b` ternary. Those are GitHub idioms a Forgejo/act
runner may evaluate differently, and the failure mode is silent: an empty
*_IMAGE_TAG makes deploy.sh fall back to the tag already running, so the job
goes green having deployed nothing. Beta and prod get two explicit, mutually
exclusive steps rather than a ternary over secrets, where an empty host would be
worse still.

Everything load-bearing is preserved: fetch-depth 0 and the domain-keyed 12-hex
tag (the branch tip is often another domain's commit), per-service per-ref
concurrency with cancel-in-progress false, separate PROD_SSH_* credentials, the
v*.*.* both-images exception, and appleboy/ssh-action by full URL.

pr-build.yml is untouched. Its workflow name and `gate` job are the required
status check branch protection is configured against, and renaming that context
makes every PR unmergeable with fully green CI. secrets-guard.yml and
shell-lint.yml are likewise left alone: they are the only other consolidation
candidates that run on pull_request, and the branch-protection API needs
credentials this could not read, so merging them was not worth the risk for two
files.

Logic verified by replaying the plan step against real history: an infra-only
push rolls nothing, a backend-only push rolls backend and leaves frontend
alone, and a run with no usable before-sha defaults to deploying rather than
silently skipping. The computed frontend tag for a backend-only push is
sha-ca84e0ce95f0 -- exactly the tag live on beta -- so the derivation matches
what the old workflows produced.

15 workflows -> 9, 1365 lines -> 1019. Docs naming the deleted files are
updated in the same commit, per the rule the root CLAUDE.md now carries.
2026-07-25 00:47:41 -07:00
..
workflows ci: collapse the eight deploy and build-push workflows into two 2026-07-25 00:47:41 -07:00