From 9aab21dc629a867ee80694c2e75ad774e2c676a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 3 Oct 2026 01:50:03 +0000 Subject: [PATCH 1/2] Release v1.10.0 --- CHANGELOG.md | 25 ++++++++++++++++++- .../20261002_000000_release_workflows.md | 19 -------------- 2 files changed, 24 insertions(+), 20 deletions(-) delete mode 100644 changelog.d/20261002_000000_release_workflows.md diff --git a/CHANGELOG.md b/CHANGELOG.md index fad9fd7..c47f75e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,28 @@ Entries for 1.0.0 through 1.5.2 were backfilled from git history after the fact, +## [1.10.0] - 2026-10-03 + +### Added + +- Automated releases. Run **Prepare release** from the Actions tab: it bumps `version` in `pyproject.toml` with `uv version --bump`, collects `changelog.d/` into `CHANGELOG.md`, and opens a "Release vX.Y.Z" pull request. Approve its CI and merge it, and **Release on merge** tags the merge commit, creates the GitHub release from the changelog section, and, for a library published to PyPI, starts `publish.yml`. The `auto` bump picks minor when a fragment adds, changes, deprecates or removes something, and patch when fragments only fix; it never picks major. +- The steps live in two reusable workflows in this repo, `prepare-release.yml` and `release-on-merge.yml`, and generated projects get thin callers pinned to `@v1`, as with `python-ci.yml`. Release fixes reach every project when `v1` moves, without a `copier update`. +- The safeguards: Prepare release refuses a run from another branch, with no fragments, with a fragment that has entries but no category heading or that quotes a scriv marker (scriv would silently drop the lines above it), with an existing tag, or with a release pull request already open, and is safe to re-run after a failure. Release on merge checks that `pyproject.toml` at the merge commit agrees with the release branch, refuses a tag already on another commit, and skips a tag or release that already exists, so it can be re-run. Its concurrency group is keyed on the branch, so an unrelated pull request closing can't cancel a pending release run. +- `publish.yml` takes a `workflow_dispatch` trigger, so Release on merge can start it. A tag created with the default Actions token triggers no workflows, and PyPI trusted publishing can't run from a reusable workflow, so the dispatched run is still `publish.yml`, the workflow the trusted publisher names. It refuses any ref but a `v*` tag, fails if the tag doesn't match the built wheel's version, and moves to checkout 7.0.1 and setup-uv 10.0.1. +- This template releases itself with the same reusable workflows, in a mode that takes the version from the latest `vX.Y.Z` tag, so every template release exercises them before `v1` moves. Its own changelog is now scriv fragments too, and `bump-v1.yml` can be started on a tag as well as by a published release. Started that way, it refuses anything but the newest final `v1.X.Y` tag, so `v1` only moves forward. + +### Changed + +- Libraries build with uv's own backend, `uv_build`, instead of hatchling, and keep a static `version` in `pyproject.toml`, so `uv version --bump` manages it. `__version__` reads it back from the installed package metadata (`"unknown"` in a source tree that was never installed). hatchling was there to read the version from `__init__.py`, which uv can't bump; with the version in `pyproject.toml` it isn't needed. `[tool.scriv]` reads the version from `pyproject.toml` for every project kind. MIT projects set `license-files = ["LICENSE"]`, since uv_build ships only the license files it is told about. + +### Upgrading + +- A manual `copier update` across 1.10.0 needs `--trust`, because the template now runs a migration. Without it copier stops with `Template uses potentially unsafe feature: migrations.` and changes nothing, for apps as well as libraries. The weekly template-update workflow already passes it. +- Turn on _Settings → Actions → General_ → **Allow GitHub Actions to create and approve pull requests**, or Prepare release fails when it opens the pull request. The weekly template-update workflow needs the same setting. CI on each release pull request then starts once you click **Approve workflows to run** on it. +- For a library, `copier update` changes `pyproject.toml` to uv_build and a static `version`, and a migration then sets that `version` to the `__version__` the project's `__init__.py` had before the update. Without it the template's `0.1.0` would merge in silently. Check `uv version --short` before merging the update. `__init__.py` itself conflicts: keep the template's metadata lookup, plus any other code the file had. +- For a library, check that the wheel's contents don't change: uv_build expects the package under `src//`, and any hatch build options (includes, excludes, force-include) need their `[tool.uv.build-backend]` equivalents. +- No PyPI change is needed. The trusted publisher still names `publish.yml`. A project that publishes from a differently named workflow should rename it to `publish.yml` and update the publisher. + ## [1.9.1] - 2026-10-02 Repairs 1.9.0, which was tagged before `CHANGELOG.md` had a `[1.9.0]` section. `bump-v1.yml` refuses a release it can't find described, so it left `v1` on 1.8.1 and the 1.9.0 tag lightweight. Consumers land on 1.9.1 rather than 1.9.0; the contents are the same bar this changelog. @@ -203,4 +225,5 @@ The largest release so far: an optional TypeScript side, automated template upda [1.8.1]: https://github.com/MattFisher/python-project-template/compare/v1.8.0...v1.8.1 [1.9.0]: https://github.com/Generality-Labs/python-project-template/compare/v1.8.1...v1.9.0 [1.9.1]: https://github.com/Generality-Labs/python-project-template/compare/v1.9.0...v1.9.1 -[unreleased]: https://github.com/Generality-Labs/python-project-template/compare/v1.9.1...HEAD +[1.10.0]: https://github.com/Generality-Labs/python-project-template/compare/v1.9.1...v1.10.0 +[unreleased]: https://github.com/Generality-Labs/python-project-template/compare/v1.10.0...HEAD diff --git a/changelog.d/20261002_000000_release_workflows.md b/changelog.d/20261002_000000_release_workflows.md deleted file mode 100644 index a830d8b..0000000 --- a/changelog.d/20261002_000000_release_workflows.md +++ /dev/null @@ -1,19 +0,0 @@ -### Added - -- Automated releases. Run **Prepare release** from the Actions tab: it bumps `version` in `pyproject.toml` with `uv version --bump`, collects `changelog.d/` into `CHANGELOG.md`, and opens a "Release vX.Y.Z" pull request. Approve its CI and merge it, and **Release on merge** tags the merge commit, creates the GitHub release from the changelog section, and, for a library published to PyPI, starts `publish.yml`. The `auto` bump picks minor when a fragment adds, changes, deprecates or removes something, and patch when fragments only fix; it never picks major. -- The steps live in two reusable workflows in this repo, `prepare-release.yml` and `release-on-merge.yml`, and generated projects get thin callers pinned to `@v1`, as with `python-ci.yml`. Release fixes reach every project when `v1` moves, without a `copier update`. -- The safeguards: Prepare release refuses a run from another branch, with no fragments, with a fragment that has entries but no category heading or that quotes a scriv marker (scriv would silently drop the lines above it), with an existing tag, or with a release pull request already open, and is safe to re-run after a failure. Release on merge checks that `pyproject.toml` at the merge commit agrees with the release branch, refuses a tag already on another commit, and skips a tag or release that already exists, so it can be re-run. Its concurrency group is keyed on the branch, so an unrelated pull request closing can't cancel a pending release run. -- `publish.yml` takes a `workflow_dispatch` trigger, so Release on merge can start it. A tag created with the default Actions token triggers no workflows, and PyPI trusted publishing can't run from a reusable workflow, so the dispatched run is still `publish.yml`, the workflow the trusted publisher names. It refuses any ref but a `v*` tag, fails if the tag doesn't match the built wheel's version, and moves to checkout 7.0.1 and setup-uv 10.0.1. -- This template releases itself with the same reusable workflows, in a mode that takes the version from the latest `vX.Y.Z` tag, so every template release exercises them before `v1` moves. Its own changelog is now scriv fragments too, and `bump-v1.yml` can be started on a tag as well as by a published release. Started that way, it refuses anything but the newest final `v1.X.Y` tag, so `v1` only moves forward. - -### Changed - -- Libraries build with uv's own backend, `uv_build`, instead of hatchling, and keep a static `version` in `pyproject.toml`, so `uv version --bump` manages it. `__version__` reads it back from the installed package metadata (`"unknown"` in a source tree that was never installed). hatchling was there to read the version from `__init__.py`, which uv can't bump; with the version in `pyproject.toml` it isn't needed. `[tool.scriv]` reads the version from `pyproject.toml` for every project kind. MIT projects set `license-files = ["LICENSE"]`, since uv_build ships only the license files it is told about. - -### Upgrading - -- A manual `copier update` across 1.10.0 needs `--trust`, because the template now runs a migration. Without it copier stops with `Template uses potentially unsafe feature: migrations.` and changes nothing, for apps as well as libraries. The weekly template-update workflow already passes it. -- Turn on _Settings → Actions → General_ → **Allow GitHub Actions to create and approve pull requests**, or Prepare release fails when it opens the pull request. The weekly template-update workflow needs the same setting. CI on each release pull request then starts once you click **Approve workflows to run** on it. -- For a library, `copier update` changes `pyproject.toml` to uv_build and a static `version`, and a migration then sets that `version` to the `__version__` the project's `__init__.py` had before the update. Without it the template's `0.1.0` would merge in silently. Check `uv version --short` before merging the update. `__init__.py` itself conflicts: keep the template's metadata lookup, plus any other code the file had. -- For a library, check that the wheel's contents don't change: uv_build expects the package under `src//`, and any hatch build options (includes, excludes, force-include) need their `[tool.uv.build-backend]` equivalents. -- No PyPI change is needed. The trusted publisher still names `publish.yml`. A project that publishes from a differently named workflow should rename it to `publish.yml` and update the publisher. From e44242983cc79d9ebc2fa4432d31c709202e27e7 Mon Sep 17 00:00:00 2001 From: Matt Fisher Date: Sat, 3 Oct 2026 11:52:51 +1000 Subject: [PATCH 2/2] Add summary paragraph --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c47f75e..73d9dee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ Entries for 1.0.0 through 1.5.2 were backfilled from git history after the fact, ## [1.10.0] - 2026-10-03 +Releases are automated, through two reusable workflows that generated projects call from thin `@v1` callers. Run "Prepare release" from the Actions tab, approve the CI on the pull request it opens, and merge. The merge tags the release and creates the GitHub release, and a library on PyPI is then published. Libraries now build with `uv_build`, with the version set once in `pyproject.toml`. Every project needs one repository setting and `copier update --trust`, and libraries should check their version and wheel after updating; see Upgrading. + ### Added - Automated releases. Run **Prepare release** from the Actions tab: it bumps `version` in `pyproject.toml` with `uv version --bump`, collects `changelog.d/` into `CHANGELOG.md`, and opens a "Release vX.Y.Z" pull request. Approve its CI and merge it, and **Release on merge** tags the merge commit, creates the GitHub release from the changelog section, and, for a library published to PyPI, starts `publish.yml`. The `auto` bump picks minor when a fragment adds, changes, deprecates or removes something, and patch when fragments only fix; it never picks major.