Skip to content

💥 feat!: trust writers, name every job and step - #23

Merged
gaborbernat merged 23 commits into
mainfrom
feat/trust-writers
Oct 26, 2026
Merged

gaborbernat merged 23 commits into
mainfrom
feat/trust-writers

Conversation

@gaborbernat

@gaborbernat gaborbernat commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

People with write access are validated when their pull request merges, so the shared workflows stop re-checking what writers already merged, tagged or typed into a workflow file. Pull request checks and supply-chain guards stay.

Removed from the release path. The tag-time lock job in validate-python-release.yaml, the whole check-tagged-source action, tag identity and main ancestry checks, the tag re-check before creating the GitHub Release, and the version-matches-tag, one-wheel-one-sdist and empty-dist/ checks. Prepare loses its lock and validate jobs, so it builds the patch and pushes it. The push job keeps only the path allowlist that limits what the release App may push. if: github.ref == 'refs/heads/main' job guards, validation of inputs callers pass, re-checks of files our own steps just built, and writer-process guards go too.

Removed inputs. Callers must drop them:

  • validate-python-release.yaml and prepare-towncrier-release.yaml: additional-lock*, additional-matrix-* and nab-git-commit;
  • nab-git-commit everywhere else;
  • install-locked-tools: verify-lock and verify-groups;
  • export-build-constraints: verify-groups;
  • validate-release-patch: version and checks;
  • publish-post-release-pr: app-slug and commit-message.

Changed behaviour. On a rerun, publish-github-release updates the existing draft instead of failing on a changed title or body. The asset digest check stays, including for an already published immutable Release. validate-news runs each check only when the pull request touches what it checks: the lock check when pyproject.toml, pylock*.toml or nab.toml changed, fragment checks when fragments changed, and the Towncrier config check when that config changed. check.yaml no longer reruns on pushes to main.

Names. Every job and step now has a name that starts with an emoji, and the same kind of step uses the same emoji across workflows. Job names change, so required status checks in rulesets need the new names. In callers, validate-python-release now reports 🏗️ Build distributions, and prepare reports 🏷️ Assemble release and ⬆️ Push release commit and tag.

gw's own tools and tests now use release-creator 4.0.0.

Before merging, the default ruleset's required checks have to move to the new job names, or GitHub blocks the merge: Required checks pass → 🚦 Required checks pass and changelog → 📝 News fragment (pre-commit.ci - pr is unchanged). swap_required_checks.py tox-dev/github-workflows 23 --apply does exactly that, after checking that this PR reports both new names as passing.

validate-news already checks the lock on the pull request that changes
it, so the tag-time lock job, the prepare lock job and the lock step of
check-tagged-source only re-checked what writers merged. Their secondary
lock inputs go with them.
Writers push the tags, so re-checking that a tag names GITHUB_SHA and
sits on main only catches their own mistakes. This removes the
check-tagged-source Action, the inline tag check of
validate-python-release.yaml and the source job of the self-release.
No caller installs Nab from a Git commit any more, so the temporary
input, its format check and the workspace install go.
The tag a writer pushed started the run, so checking again that it
still names the release commit only catches a writer moving it. This
drops the check from the self-release, publish-github-release and
publish-jetbrains-marketplace.
The release jobs build the wheel, sdist and dist directory themselves,
so checking their count, version and file types again only catches a
writer's mistake. The PyPI digest and attestation checks stay.
The validate job recalculated the version and ran release-creator and
prek on the patch assemble had just built, and validate-release-patch
and commit-and-tag re-checked the branch and working tree. The push job
keeps applying the patch with its path and mode checks.
Only writers can dispatch the workflow, so gating the publish job on
main only stopped their own runs. The release-auth environment keeps
its own branch rule.
Writers choose the groups, locks, targets and secondary lock inputs, so
checking them up front only catches their own typos; uv, Nab and
packaging still fail on input they cannot use. This removes
check_lock_groups.py and the verify-lock and verify-groups inputs.
prepare-towncrier, read-towncrier-config, select-previous-tag and
commit-and-tag validated inputs and configuration that only writers set.
Towncrier, release-creator and Git still fail on what they cannot use.
The publishing Actions checked the shape of inputs that writers pass:
tag, title, mode, asset names, archive names, plugin ID, channel,
artifact IDs and the post-release pull request inputs. The digest,
receipt and bundle checks stay.
The sign, Marketplace and post-release Actions re-checked ZIPs, receipts,
commits and branches that the release jobs had just produced or pushed.
The digest, duplicate-member, bundle and manifest checks stay. The
post-release Action drops app-slug and commit-message, which only fed
the author and message checks.
The Marketplace deployment scan and the post-release metadata, duplicate
and label checks stopped writers who edited a pull request or deployment
by hand. The upload receipts and the closed-pull-request stop stay.
check.yaml re-ran every check on merged main and on dispatch, and
refresh-release-lock compared the target environments of a refreshed
lock that a writer reviews in its pull request anyway. Check mode still
compares the whole lock.
publish-github-release stops comparing the title, notes and prerelease
flag of an existing Release and instead updates a draft that differs.
It picks the first Release for a tag and creates a missing draft in
publish mode. The read-after-write retry and asset digest checks stay.
validate-news now validates fragments only when the fragment directory
changes, checks the Towncrier configuration only when it changes, and
runs the lock check only for pyproject, pylock or nab.toml changes.
Workflow changes no longer trigger the lock check.
release-creator 4.0.0 no longer fails on an empty release or a missing
notes section, so these tests only pinned the 3.x error messages.
Apply the approved job and step names to the workflows and Actions, and
point the tests that look steps up by name at the new names. The job
names change required-check names in callers. The Marketplace Action
also recognizes the renamed caller step 🚀 Publish signed ZIP.
Raise gw's own release-creator floors to 4, move the temporary cutoff
override to the 4.0.0 upload and relock. release-creator 4 no longer
rejects bare fragment names and checks only a changed Towncrier
configuration itself, so the tests use errors it still raises.
Every composite Action, inline workflow step and tools script now prints
each choice it makes and why: selected lock groups, build constraints
reuse, version and previous tag, skipped checks and steps, release draft
state, asset uploads and Marketplace receipts. git, gh and curl commands
no longer discard their output, except where the command is a yes/no
test, whose outcome is printed instead. Python tools explain on stderr,
so captured stdout, step outputs and written files stay unchanged, and
nothing relies on release-creator's own stderr.
Each bare test, cmp, [[ ]] || exit 1 and exit 1 failure in the Actions
now prints an ::error:: line naming the check and the values it compared,
including every Marketplace receipt field and post-release path manifest
check, which the tests now assert. Counts are pluralized through a shared
tools/plural.sh, curl calls use --no-progress-meter, and
build_constraints.py no longer truth-tests an optional group list.
release-creator 4.1.0 explains each command's choices on stderr, so the
shared steps now show what release-creator decided as well.
The inline shell check lints each run block from a temporary copy, so a
block that sources tools/plural.sh fails shellcheck there.
@gaborbernat
gaborbernat merged commit 3bf530f into main Oct 26, 2026
10 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