fix(ci): gate docker publish on the offline test suite

docker.yml pushed the image for tags and master without waiting for the
test job, so a red commit could still be published. ci.yml is now also a
workflow_call target; docker depends on its result. The gate run has its
own concurrency group and never cancels a superseded run, so a docs-only
follow-up cannot drop the image of the code commit before it. The live
job is skipped for the gate call.
This commit is contained in:
2026-10-14 22:10:35 +08:00
parent a7d4d1af8c
commit 7fbe144b57
3 changed files with 28 additions and 6 deletions
+12 -3
View File
@@ -34,6 +34,15 @@ on:
# Weekly probe of the live endpoints, so external API changes surface.
- cron: '0 3 * * 1'
workflow_dispatch:
# Called by docker.yml as the publish gate. `gate` marks that call: its
# concurrency group is separate from the standalone run on the same ref, and
# it never cancels a superseded run, because each gate run carries its own
# commit's image (a docs-only follow-up must not drop the code commit's).
workflow_call:
inputs:
gate:
type: boolean
default: false
permissions:
contents: read
@@ -41,8 +50,8 @@ permissions:
# A newer push to the same ref supersedes the older run; without this every
# intermediate commit of a PR branch keeps a runner busy to completion.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
group: ci-${{ inputs.gate && 'gate-' || '' }}${{ github.ref }}
cancel-in-progress: ${{ !inputs.gate }}
env:
# Panicking tests print their backtrace; free when nothing fails.
@@ -134,7 +143,7 @@ jobs:
live:
needs: test
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v')
if: ${{ !inputs.gate && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v')) }}
runs-on: ubuntu-latest
timeout-minutes: 30
continue-on-error: true
+15 -2
View File
@@ -111,14 +111,27 @@ jobs:
fi
echo "build=true" >> "$GITHUB_OUTPUT"
# The publish gate: the offline suite CI runs (fmt, clippy, tests, release
# build, audit), reused rather than copied, so no image is pushed for a
# commit whose tests are red. Pull requests skip it: their own CI run covers
# the code, and the docker job there only proves the image still builds.
ci:
needs: should-build
if: needs.should-build.outputs.build == 'true' && github.event_name != 'pull_request'
uses: ./.github/workflows/ci.yml
with:
gate: true
# No `actions/checkout` here on purpose: `docker/build-push-action` defaults
# to the Git context (`https://github.com/<owner>/<repo>.git#<ref>`), so
# BuildKit clones the repo itself and authenticates with the automatic
# github.token. Adding `context: .` below without a checkout step would hand
# BuildKit an empty workspace.
docker:
needs: should-build
if: needs.should-build.outputs.build == 'true'
needs: [should-build, ci]
# `always()`: a skipped `ci` (pull requests) must not skip this job; only a
# failed or cancelled gate does.
if: always() && needs.should-build.outputs.build == 'true' && (github.event_name == 'pull_request' || needs.ci.result == 'success')
runs-on: ubuntu-latest
timeout-minutes: 60
steps: