Ask
[skip ci] is all-or-nothing: it skips validation, publishing and Pages together. Add two narrower markers that compose on top of it:
[skip publish] — run everything, but do not release to PyPI.
[skip github-pages] — run everything, but do not push to gh-pages.
[skip ci] keeps its current meaning: skip everything.
Why
The two side-effecting jobs are exactly the ones you sometimes want to suppress without losing the signal from the ones you don't:
- A docs-only or comment-only change on the default branch: you want tests to run, you don't want to burn a PyPI version number. Today the only lever is
[skip ci], which throws away the test run too — so the choice is "release something trivial" or "test nothing".
- A change that touches the docs build itself, or a repo whose Pages deploy is noisy: same shape.
- Landing several commits in quick succession where only the last should publish.
PyPI version numbers are permanently burned once used, so "release fewer accidental versions" has real value, and today the only way to get it also costs you CI.
Shape of the change
The machinery already exists — [tool.wads.ci.publish].skip_ci_marker / publish_marker are read into setup outputs and consumed by the publish job's if:. So this is the same pattern, one more marker each:
# publish job
if: "!contains(github.event.head_commit.message, needs.setup.outputs.skip-ci-marker)
&& !contains(github.event.head_commit.message, '[skip publish]')
&& github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
&& (needs.setup.outputs.publish-enabled == 'true' || contains(github.event.head_commit.message, needs.setup.outputs.publish-marker))"
# github-pages job
if: "!contains(github.event.head_commit.message, '[skip ci]')
&& !contains(github.event.head_commit.message, '[skip github-pages]')
&& github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
&& needs.setup.outputs.docs-enabled != 'false'"
Ideally configurable the way the existing ones are, e.g. [tool.wads.ci.publish].skip_publish_marker and [tool.wads.ci.docs].skip_marker, defaulting to [skip publish] / [skip github-pages] — so the literals aren't hard-coded and a repo can rename them.
Both templates need it (uv-ci.yml reusable + github_ci_uv.yml inline), plus a line each in the CI-config reference so the markers are discoverable.
Note on the publish job's existing condition
Worth deciding as part of this: publish currently gates on skip-ci-marker (configurable) while github-pages hard-codes '[skip ci]'. If skip_ci_marker is ever set to something non-default, the two jobs disagree about what "skip" means. Making them consistent would fold naturally into this change.
Ask
[skip ci]is all-or-nothing: it skips validation, publishing and Pages together. Add two narrower markers that compose on top of it:[skip publish]— run everything, but do not release to PyPI.[skip github-pages]— run everything, but do not push togh-pages.[skip ci]keeps its current meaning: skip everything.Why
The two side-effecting jobs are exactly the ones you sometimes want to suppress without losing the signal from the ones you don't:
[skip ci], which throws away the test run too — so the choice is "release something trivial" or "test nothing".PyPI version numbers are permanently burned once used, so "release fewer accidental versions" has real value, and today the only way to get it also costs you CI.
Shape of the change
The machinery already exists —
[tool.wads.ci.publish].skip_ci_marker/publish_markerare read intosetupoutputs and consumed by thepublishjob'sif:. So this is the same pattern, one more marker each:Ideally configurable the way the existing ones are, e.g.
[tool.wads.ci.publish].skip_publish_markerand[tool.wads.ci.docs].skip_marker, defaulting to[skip publish]/[skip github-pages]— so the literals aren't hard-coded and a repo can rename them.Both templates need it (
uv-ci.ymlreusable +github_ci_uv.ymlinline), plus a line each in the CI-config reference so the markers are discoverable.Note on the publish job's existing condition
Worth deciding as part of this:
publishcurrently gates onskip-ci-marker(configurable) whilegithub-pageshard-codes'[skip ci]'. Ifskip_ci_markeris ever set to something non-default, the two jobs disagree about what "skip" means. Making them consistent would fold naturally into this change.