Skip to content

👷 ci(release): move releases onto shared workflows - #867

Merged
gaborbernat merged 1 commit into
mainfrom
fix/release-contract
Oct 27, 2026
Merged

gaborbernat merged 1 commit into
mainfrom
fix/release-contract

Conversation

@gaborbernat

@gaborbernat gaborbernat commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

filelock carried its own release scripts: shell that picked the next version and committed the changelog, and an awk and Python pipeline that turned docs/changelog.rst into GitHub Release notes. 🚀 This PR replaces them with the shared release path from tox-dev/github-workflows 6.0.1 and release-creator 4.1.0, so fixes to that path reach filelock through a pin bump.

Maintainers keep the same entry point: dispatch Prepare release with auto, major, minor or patch, and the shared workflow builds the changelog from fragments, adds a New Contributors subsection through release-creator contributors, then commits and tags with the release App key. Contributors stop writing credits by hand. Fragments name no PR and carry no author, and prepare links each one to its squash-merged PR and credits the commit authors and co-authors. CONTRIBUTING now documents the fragment types and this credit rule.

Release architecture

A tag starts two jobs side by side. The shared validate-python-release build installs its build backends from hash-pinned constraints exported from the lock, while a read-only job renders the GitHub Release notes from the changelog with release-creator. Only the publish job holds the PyPI OIDC token. It uploads without skip-existing, so a version already on PyPI fails the job instead of passing silently, because PyPI never accepts a file name twice, and a verify job then compares every built file with what PyPI serves before publish-github-release creates the Release. Each job receives artifacts by ID.

flowchart LR
    Tag[Tag push] --> Build[Build distributions]
    Tag --> Notes[Render release notes]
    Build --> PyPI[Publish to PyPI]
    Notes --> PyPI
    PyPI --> Verify[Verify PyPI files]
    Verify --> GHR[GitHub Release]
    Notes --> GHR
    classDef src fill:#cfe4ff,stroke:#1f6feb,color:#0b1f3a;
    classDef secret fill:#ffe3a3,stroke:#d29200,color:#3a2c00;
    class Tag,Build,Notes,Verify src;
    class PyPI,GHR secret;
Loading

We trust people with write access, and the PR merge is where we validate their changes. The release path therefore drops checks that re-validate a writer's own actions: the tag-time guard that refused a version missing from the changelog is gone, and the tag filter accepts any tag. Supply-chain guards stay: pinned actions, the hashed build constraints and the PyPI comparison.

Changes outside the release jobs

The news check moves into its own workflow, so adding or removing a label reruns only that check and no longer the whole test matrix. Its shared validate-news action validates fragments only when the fragment directory or Towncrier config changed, and the lock only when lock inputs changed. A human PR still needs a fragment or the skip news label.

docs/changelog.rst is regenerated with the release-creator template: the new category names (Added, Changes, Fixed and so on), a stable anchor for each version and category, and author credits on entries. tox -e release now previews pending fragments without picking a version.

Nab writes pylock.toml from a [tool.nab] table for CPython 3.15 on Linux x86-64 with a seven-day upload cutoff, and locks release-creator 4.1.0, towncrier 26.9.0 and prek 0.5.6. A new build group pins the build backends, and only the release, prepare and news jobs install from the lock. Test, type and docs runs still resolve current dependencies. A weekly Upgrade release tools run opens the relock PR.

Pre-commit hooks are frozen to commit SHAs, and Dependabot's pre-commit ecosystem (weekly, seven-day cooldown) plus a quarterly pre-commit.ci autoupdate keep them current. mdformat now comes from its upstream hook repo, and docstrfmt formats the changelog.

The PyPI page changes too. 📦 The project URLs point at tox-dev/filelock instead of the old py-filelock name, a Changelog link is added, the keywords become file, lock and synchronization (they listed application, cache, directory, log and user), the MIT license and Topic :: Internet classifiers go, and hatch-fancy-pypi-readme renders the README. Every workflow, job and step name now starts with one emoji from the shared vocabulary.

🛡️ CodeQL

CodeQL moves from default setup to a committed workflow on ubuntu-26.04 with the same languages (actions, python), which removes the ubuntu-latest migration notice default setup produces. It switches to the security-extended query suite and skips tests/, where alerts on fixtures and helpers would not get fixed.

@gaborbernat gaborbernat added enhancement documentation skip news Internal change; exempt from the news fragment check labels Oct 20, 2026
@gaborbernat gaborbernat changed the title 👷 ci(release): unify preparation and history 👷 ci: unify release preparation Oct 20, 2026
@gaborbernat
gaborbernat force-pushed the fix/release-contract branch 10 times, most recently from 05eb6a8 to 4036fd9 Compare October 26, 2026 20:59
@gaborbernat gaborbernat changed the title 👷 ci: unify release preparation 👷 ci(release): move releases onto shared workflows Oct 26, 2026
@gaborbernat
gaborbernat force-pushed the fix/release-contract branch 5 times, most recently from c48fc84 to 41b701f Compare October 27, 2026 01:57
Move releases onto the shared github-workflows 6.0.1 path with
release-creator 4.1.0: a dispatched prepare run picks the version,
assembles the RST changelog from fragments and pushes an App-authored
commit and tag. The changelog covers the published history with stable
category anchors.

The tag workflow builds in parallel with a read-only notes job, uploads
to PyPI through OIDC without skipping existing files, verifies the
published digests and attestations, then creates the GitHub Release
with one call. Tag runs are serialised per ref and never cancelled;
pull request and push runs cancel superseded ones. GitHub's generated
notes and the draft stage job are gone.

Writers are validated at pull request merge, so checks that re-validate
their actions go: the tag re-check before the GitHub Release, the
release-validate group used only by prepare's removed self-check, and
the redundant pull_request condition on the news job. The news check
runs each validation only when its files change.

Nab writes pylock.toml for every group from a [tool.nab] table with a
seven-day cutoff, plus a temporary exception for release-creator 4.1.0
that expires after 2026-11-02. A build group locks the hatchling
backends with Cython and setuptools, since PyYAML ships no CPython 3.15
wheel. The unused release-check group is dropped.

Every workflow, job and step gets a name starting with one emoji. The gate is
now "🚦 Required checks pass" and the PR build "🏗️ Build distributions".

The hook cooldown check, its scheduled rerun and the release-creator
managed hook pins are removed. Dependabot's pre-commit ecosystem and a
quarterly pre-commit.ci autoupdate handle hook revisions instead.

CONTRIBUTING drops hand-written credits: they come from commit authors
and co-authors, and prepare runs release-creator contributors.

CodeQL moves from default setup to a committed advanced workflow on
ubuntu-26.04 with the same languages, now running security-extended and
skipping tests.
@gaborbernat
gaborbernat marked this pull request as ready for review October 27, 2026 05:39
@gaborbernat
gaborbernat merged commit 87ccd0f into main Oct 27, 2026
52 checks passed
@gaborbernat
gaborbernat deleted the fix/release-contract branch October 27, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation enhancement skip news Internal change; exempt from the news fragment check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant