Selective CI runs a subset of checks based on the files or targets affected by a change. It reduces latency only if the impact map is accurate. Shared libraries, generated schemas, build scripts, lockfiles, and configuration can affect code outside their directory. A missing base revision or a rename can also make a diff incomplete. The safe contract is explicit: uncertainty triggers the complete suite before the change becomes releasable.
Selective CI: default to full verification when impact is uncertain
Operational decision
A repository has receipt and payout services. A receipt-only edit can run a focused service suite, but changes to shared/, schemas/, ci/, or the dependency lock must run the complete suite. The Bash fragment checks that the base commit exists, then uses a conservative path rule. In a real pipeline, derive BASE_REVISION from the event's trusted base SHA and verify the checkout has enough history; do not let a pull-request script supply an arbitrary value that bypasses checks. Test the selector with a shared API rename, a deleted file, and a missing base commit. Compare focused and full results for a sampled set of changes over several weeks. Keep one required result whose completion means the selected checks actually ran; a skipped workflow can leave a required status pending, and an optional check that never starts is not evidence of success.
set -euo pipefail
base_revision=${BASE_REVISION:?missing trusted base revision}
if ! git cat-file -e "${base_revision}^{commit}" 2>/dev/null; then
./ci/run-all-tests.sh
exit 0
fi
if ! changed_paths=$(git diff --no-renames --name-only "$base_revision" HEAD); then
./ci/run-all-tests.sh
exit 0
fi
if [[ -n "$changed_paths" ]] && ! grep -Eqv '^receipt/' <<< "$changed_paths"; then
./ci/run-receipt-tests.sh
else
./ci/run-all-tests.sh
fiCost and verification
Targeted checks save runner minutes but require continuous maintenance of the impact graph. A conservative rule spends more CPU on ambiguous changes; an aggressive rule saves minutes while letting faults cross service boundaries unseen. Measure full-suite sampling failures, selector fallback frequency, and false-negative incidents. Keep the full suite scheduled and available on demand. The fragment is a narrow illustration for a two-service repository; it must be expanded when new shared paths or generated outputs are introduced.
Common Mistakes
- Do not treat a path filter as proof that unaffected code cannot break.
- Do not silently skip tests when the base revision is unavailable.
- Do not mark a required gate green when no test command ran.
Connected lessons
- DevOps: delivery, infrastructure, and reliable operations
- Continuous integration: test the merge candidate
- Git change control: small merges and protected branches
- CI dependency caches: speed without hidden build inputs
- API compatibility windows: release consumers and producers safely
