Skip to content

ci: run only the jobs the changed paths can affect - #47

Merged
rducom merged 1 commit into
mainfrom
ci/run-only-what-a-change-touches
Oct 7, 2026
Merged

rducom merged 1 commit into
mainfrom
ci/run-only-what-a-change-touches

Conversation

@rducom

@rducom rducom commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Until now every pull request ran the whole stack: three test suites, the package job and the cross-check. That happened even when the PR only touched documentation, renovate.json, or a Rust tool CI never builds. A new first job (choose the jobs the change needs) now sorts the changed paths into the jobs that read them:

paths jobs
src/** (packed readmes and analyzer release notes included), tests/**, build config, build.yml, any path not listed all
root README.md, NOTICE (packed into every package) package
tools/conformance-gen/**, spec/** cross-check
bench/**, samples/**, tools/vxdump/**, tools/testimpact/** (in the solution, referenced by no test project) package
tools/native-ref/** (writes the Zstd test data) test
docs/**, other *.md, LICENSE, .gitignore, renovate.json, release-drafter config, issue templates, tools/row-vectors/**, tools/vxbench-rs/**, tools/pmu/**, tools/disasm.sh none
  • Diff used. For a pull request, the job diffs the merge commit against its first parent, which is exactly what the PR changes. For a push to main, it diffs against github.event.before. Releases, workflow_dispatch, a before that cannot be fetched, or a failed diff all run everything.
  • No path filter on the trigger. The branch rule requires build, test and cross-check. A workflow that never starts never reports that check, so the PR would wait forever. The check still runs every time. It now accepts a skipped job only when the first job ran and said the change does not need it.
  • Cost of the extra job. Checkout uses fetch-depth: 2, filter: blob:none and a sparse .github: two commits and their trees, no file contents.

Tested locally against real history: #45 (renovate.json) and #41/#37 (vxbench-rs and row-vectors lockfiles) select no job. #38, #44 and #46 select only the cross-check, and #43 selects everything. The same holds for pull_request mode on refs/pull/{44,46}/merge. The fallbacks (zero before, unfetchable before, release, dispatch) run everything. actionlint and zizmor pass.

This PR touches build.yml, so its own run takes every job.

A pull request that edits documentation, renovate.json, or a Rust tool CI
never builds (row-vectors, vxbench-rs) ran the whole stack: three test
suites, the package job and the cross-check, twenty minutes of runners for
nothing they could catch.

A first job sorts the changed paths into the jobs that read them: src/ and
the tests run everything, README.md and NOTICE the package job that packs
them, tools/conformance-gen and spec/ the cross-check, bench/ and samples/
the package job, documentation nothing. A path the table does not name runs
everything, and so does any run other than a push or a pull request, the
release run first. The trigger filters no path: the branch rule requires the
checks job, and a workflow that never starts would leave it pending forever.
The checks job now accepts a skipped job only when the first job said the
change does not need it.
@rducom
rducom merged commit 518d966 into main Oct 7, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant