ci: skip the heavy jobs when nothing but documentation changed

Every push and PR paid the full four-minute job — fmt, clippy, the offline
suite, a release-profile build and the dependency audit — even when the diff
was a README or AGENTS edit, and every master push built and published an
image for a commit that cannot have changed it.

`ci.yml` gains a `changes` gate job: a push or PR whose *entire* diff is
markdown skips `test`, which then reports as *skipped* instead of missing —
the reason this is a gate job and not a workflow-level `paths` filter, which
leaves a required status check waiting for a check run that will never appear.
Anything non-markdown (and an empty diff, e.g. a re-run of the same commit)
runs the full job, so a new directory of code cannot slip through a stale
allowlist. `schedule`/`workflow_dispatch`, which have no `before` commit, also
run it.

`docker.yml`'s `should-build` gate now also skips a branch push that touched
none of the image's inputs (`Dockerfile`, `docker-entrypoint.sh`,
`.dockerignore`, the manifests, `Cargo.lock`, this workflow, anything under
`crates/`); tag pushes always build.

Checked against this repo's real ranges: the docs-only commit 667f523
(AGENTS.md) → `code=false` (test skipped) and skip, a workflow commit →
`code=true` and build, the h2 bump (Cargo.lock) → build.
This commit is contained in:
2026-09-21 15:54:39 +08:00
parent 74ffe66884
commit 9eb865bb02
2 changed files with 67 additions and 6 deletions
+19 -6
View File
@@ -75,6 +75,7 @@ jobs:
- id: check
shell: bash
run: |
zero=0000000000000000000000000000000000000000
if [ "$GITHUB_REF_TYPE" = "branch" ]; then
# A branch run can start before the release tag for its commit
# reaches the remote — pushing master first is the usual way to hit
@@ -87,13 +88,25 @@ jobs:
# pushing the branch and the tag together
# (`git push origin master vX.Y.Z`) removes it.
git fetch --tags --force --quiet origin
if git tag --points-at "$GITHUB_SHA" | grep -q .; then
echo "commit already tagged; the tag run builds the image"
echo "build=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# Nothing the image is made of changed — a documentation or
# workflow-only commit — so there is no new image to publish. The
# PR trigger's path list plus the crate sources, which the image
# compiles into the binary.
before="${{ github.event.before }}"
if [ -n "$before" ] && [ "$before" != "$zero" ] \
&& ! git diff --name-only "$before..$GITHUB_SHA" \
| grep -qE '^(Dockerfile|docker-entrypoint\.sh|\.dockerignore|Cargo\.toml|Cargo\.lock|\.github/workflows/docker\.yml|crates/)'; then
echo "no build input changed; skipping the image build"
echo "build=false" >> "$GITHUB_OUTPUT"
exit 0
fi
fi
if [ "$GITHUB_REF_TYPE" = "branch" ] && git tag --points-at "$GITHUB_SHA" | grep -q .; then
echo "commit already tagged; the tag run builds the image"
echo "build=false" >> "$GITHUB_OUTPUT"
else
echo "build=true" >> "$GITHUB_OUTPUT"
fi
echo "build=true" >> "$GITHUB_OUTPUT"
# No `actions/checkout` here on purpose: `docker/build-push-action` defaults
# to the Git context (`https://github.com/<owner>/<repo>.git#<ref>`), so