Cancel superseded CI runs and skip image builds PRs cannot affect - #855
Merged
Conversation
Modern agent-driven development ("vibe-coding") produces many PRs, and
CI minutes scale with them: in zoya, a production project running this
template's CI shape, GitHub Actions alone began costing ~$100/month.
The two biggest line items were superseded runs of the same PR
completing pointlessly, and every PR building all three Docker images
even when nothing image-affecting changed.
Port both cost guards from zoya:
- A concurrency group per workflow and ref, in both the template repo's
own CI and the CI generated projects inherit, cancelling in-progress
runs only for pull requests — a push to master is never cancelled.
- In the generated project's workflow, the lint job asks the GitHub API
for the PR's changed files and reports whether any of them can affect
the image build (Dockerfile, uv.lock, pyproject.toml, .dockerignore).
build-docker-image now also needs lint (execution order is unchanged,
test already needs it) and skips on PRs that touch none of those
files; pushes to master always build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
Author
|
Если ни у кого нет возражений, я смёрджу |
e-stepanov
approved these changes
Aug 26, 2026
nvo87
approved these changes
Aug 26, 2026
nvo87
left a comment
Contributor
There was a problem hiding this comment.
да, круто. Мы до этого у себя билд образа делали опциональным. И при авто-мердже, в пулл-реквестах он не отрабатывал. А тут еще круче.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Modern agent-driven development ("vibe-coding") produces many PRs, and CI minutes scale with them: in zoya, a production project running this template's CI shape, GitHub Actions alone began costing ~$100/month. The two biggest line items were superseded runs of the same PR completing pointlessly, and every PR building all three Docker images even when nothing image-affecting changed. This PR ports both cost guards from zoya's CI.
Concurrency guard (both workflows)
Both the template repo's own
.github/workflows/ci.ymland the workflow generated projects inherit get a top-level concurrency group keyed on workflow and ref:Pushing a new revision to a PR cancels the now-obsolete run of the previous one.
cancel-in-progressis conditional on the event, so a push to master is never cancelled — every master run completes.Conditional image build (generated project's workflow)
The
lintjob gains a step, run only on pull requests, that lists the PR's changed files via the GitHub API and checks them against the set that can affect the image build:Dockerfile,uv.lock,pyproject.toml,.dockerignore. The verdict is exposed as a job output, andbuild-docker-imagenow skips when a PR touches none of those files:Adding
linttoneedsis required to read the output; execution order is unchanged sincetestalready needslint. Pushes to master always build all three images — the condition only ever skips PR runs.The generated workflow lives under
_copy_without_renderincookiecutter.json, so the added${{ }}expressions pass through cookiecutter untouched.🤖 Generated with Claude Code