diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 1ce92440c..1b73fccc1 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -132,10 +132,24 @@ jobs: echo "::warning::COOLIFY_WEBHOOK or COOLIFY_TOKEN secret missing — skipping auto-deploy. Configure in repo Settings → Secrets to enable." exit 0 fi + # v1.4.22 C3 — force=true tells Coolify to skip its image-cache + # and re-pull the registry digest. If the maintainer's secret + # URL already carries a `?force=` query, leave it alone; + # otherwise append `?force=true` (or `&force=true` if other + # query params are present) so doc-only deploys still trigger + # a registry-digest check. + deploy_url="$COOLIFY_WEBHOOK" + if ! echo "$deploy_url" | grep -q "force="; then + if echo "$deploy_url" | grep -q "?"; then + deploy_url="${deploy_url}&force=true" + else + deploy_url="${deploy_url}?force=true" + fi + fi echo "Triggering Coolify deploy for ref ${{ github.ref_name }} (sha ${GITHUB_SHA::7})" response=$(curl --silent --show-error --max-time 30 \ --write-out "\n__HTTP_STATUS__:%{http_code}" \ - --request GET "$COOLIFY_WEBHOOK" \ + --request GET "$deploy_url" \ --header "Authorization: Bearer $COOLIFY_TOKEN") status="${response##*__HTTP_STATUS__:}" body="${response%__HTTP_STATUS__:*}" diff --git a/.planning/coolify-auto-deploy-howto.md b/.planning/coolify-auto-deploy-howto.md new file mode 100644 index 000000000..d35d7022b --- /dev/null +++ b/.planning/coolify-auto-deploy-howto.md @@ -0,0 +1,65 @@ +# Coolify image-digest auto-deploy — minimal maintainer action + +Status: maintainer-task — the toggle lives in Coolify's UI; neither the +Coolify MCP nor the GitHub workflow can flip it. + +## The problem + +Releases v1.4.19, v1.4.20, and v1.4.21 all required a host-side `docker +tag :latest` + `docker compose up -d --no-deps` fallback after +GHCR pushed the new image. Coolify pulled `:latest` from its local +cache without re-checking the GHCR registry digest, so the freshly +published image never reached production until the maintainer SSH'd +into the host and forced the retag. + +Longer history: `docs/audit/v1416-auto-deploy-fix.md` documents the +v1.4.15 partial fix (workflow-side webhook trigger) and why it +half-solved the problem. + +## The minimal change + +In the Coolify UI for the HealthLog application: + +1. Open **Configuration → Source** (or equivalent tab depending on the + Coolify version — the option may also live under "General" or + "Deploy"). +2. Enable the **"Watch image registry for new digests"** / + **"Image-digest auto-deploy"** checkbox. Coolify v4 names it + slightly differently across point-releases; the one that triggers a + pull when the registry digest changes (not when a git push lands) + is the one we want. +3. Save. The next time GHCR pushes a new `:latest` digest, Coolify + will pull and recreate the container without a host-side retag. + +## Why not solve it in the workflow + +Two non-options were ruled out: + +- **Push the explicit version tag in `docker-compose.yml`** — would + require a workflow edit on every release to bump `image:` to the new + tag. Worse than the current state (a manual host-side step) because + the release author has to remember the second commit. +- **Pre-deployment `docker pull` hook in the Coolify app config** — + duplicates what the registry-digest auto-deploy already does, but + worse: the pull runs on every deploy trigger (including doc-only + pushes) instead of only when the digest changed. + +The workflow file (`.github/workflows/docker-publish.yml`) already +pings Coolify's webhook with `?force=true` after the GHCR push, so the +trigger half of the contract is in place — the missing half is the +registry-digest check, which is a Coolify-side feature. + +## Verification + +Push a new release tag. The expected sequence is: + +1. `docker-publish.yml` builds, signs, pushes to GHCR. +2. Coolify webhook fires; Coolify pulls the new digest because + "Watch image registry" is enabled. +3. `https://healthlog.bombeck.io/api/version` returns the new version + string within ~60s of the GHCR push — without SSH. + +If step 3 still requires a host-side retag, the checkbox is in the +wrong place in the UI for that Coolify version — open the audit doc +above and the v1.5 deferral note for the alternative +(GHCR-tag-promoted-by-workflow path).