Skip to content

reflex-release@0.1.0

Choose a tag to compare

@github-actions github-actions released this 28 Aug 06:09
45b8ed5

Features

  • New package: reflex-release extracts Reflex's changelog-driven release pipeline β€” the towncrier news-fragment workflow, the changelog-as-source-of-truth publish detection, and the human-gated PyPI upload β€” into a reusable tool other repositories can adopt with uvx reflex-release init. It scaffolds the GitHub Actions workflows into the consuming repository (required for PyPI trusted publishing, which validates the workflow's own repository) and keeps them in step with reflex-release sync --check. Repository shape lives in a [tool.reflex-release] table: single package or monorepo, branch policy, lockstep groups that release together at one version, and internal packages that release without a changelog. Every upload waits on an approval from the pypi environment's required reviewers, and the artifacts it covers are named by SHA-256 in the run summary and in a manifest attached to the GitHub release. See packages/reflex-release/README.md for setup, configuration and the security model. (#6868)
  • reflex-release can now delegate a package's build to a workflow the consuming repository owns, for packages whose artifacts cannot come from a single uv build β€” a matrix of platform-specific wheels, say. A [[tool.reflex-release.custom-build]] entry names the packages and the workflow file, and the generated publish.yml calls it in place of its own build job, passing the package, version, tag, build directory and the artifact-name prefix to upload under. Everything either side of the build is unchanged: the whole matrix runs before the approval gate, in the same unprivileged trust boundary (contents: read, no secrets, no OIDC β€” a called workflow cannot hold more than its caller grants), and every file it produces is verified against the release, hashed into the manifest the approver sees, and published only after that approval. A failed leg fails the release rather than uploading a partial set, and expect-artifacts can additionally require the built set to match a list of filename patterns so a leg that silently produced nothing is caught too. reflex-release sync fails when a configured build workflow is missing or declares no workflow_call trigger, so a renamed file is a red pull request instead of a failed release. (#6891)
  • Add post-release-workflow to [tool.reflex-release]: the named workflow is dispatched once per published tag, on the tag itself, after the upload, the tag and the GitHub release exist β€” with tag, package and version as workflow_dispatch inputs. The dispatch step and the actions: write grant it needs are only scaffolded into publish.yml (and the workflows that call it) when the setting is present, so a repository that runs nothing after a release keeps the narrower permissions.
  • Materializing a changelog now names leftover orphan news fragments (+something.feature.md) after the pull request whose commit added them, so their entries get the usual #-link instead of shipping unlinked.
  • Materialization now lifts dependency pins a release cannot ship. A *.dev floor β€” and, for a final version, a prerelease floor on a sibling package β€” is rewritten to the earliest published version that satisfies the requirement, uv.lock is re-resolved, and both land in the release commit alongside the changelog bump. "Published" means tagged, which is this pipeline's record of what reached PyPI, so a prerelease satisfies a floor only when the version being materialized is itself a prerelease. A floor no published version satisfies has nowhere to go, so the package is held back at plan time β€” dropped from an auto-selection (a lockstep group whole), an error for an explicit one β€” rather than materialized into a version that could never be published. (#6889)
  • Add uv-version and python-version to [tool.reflex-release]: every generated workflow now installs uv and Python at those exact versions instead of whatever setup-uv resolves at run time. Both default to versions this tool pins, so upgrading reflex-release moves the release toolchain with it and sync --check reports that as drift until the workflows are regenerated β€” the same signal a template change gives. Set either key to keep your own cadence, or to "" to leave that version to the setup action. (#6941)
  • Add never-publish-packages to [tool.reflex-release], for the packages a repository builds but never releases β€” an application, a docs bundle, a fixture. A listed package gets no Dispatch release checkbox, is never auto-selected, is skipped by changelog detection even if it has a CHANGELOG.md, needs no news fragment, and is refused by prepare-publish, so a manual publish dispatch fails in the first unprivileged job instead of at verify-dist. It cannot also be a lockstep member, a custom-build package, latest-release-package or internal; each combination is rejected when the configuration loads. changelog-exempt-packages was the closest thing before, and it only waives the news-fragment requirement. (#6941)

Bug Fixes

  • A release using a [[tool.reflex-release.custom-build]] entry no longer publishes nothing while reporting success. Exactly one of the built-in build job and a custom-build job runs for any given package, so the other is always skipped β€” and GitHub evaluates the implicit success() a job gets when its if names no status function over the whole transitive dependency closure, not just the direct needs. The skipped build therefore reached publish straight through the collect written to absorb it, and tag-and-release behind it: every build succeeded, the artifacts were verified and checksummed, and then the upload silently never happened. Both jobs now carry an explicit needs.<job>.result == 'success' guard. release_from_changelog.yml's report job, the canonical failure signal for a partial release, was blind to the same shape because it accepted any skipped leg; it now accepts a skipped leg only when detection found nothing for that leg to publish, so a release that publishes nothing β€” or holds a lockstep package back β€” is red.
  • The generated changelog.yml now re-runs when a pull request's labels change, and reads the labels back from the API instead of the event payload. skip-changelog and changelog-version-edit waive parts of the check, so a verdict is only valid for the label set it was computed under: applying a label after the last push previously started no run at all, removing one left the green run that label produced standing, and re-running a failed run replayed the original payload β€” where the new label does not exist β€” so the check kept failing until someone pushed again. The job itself stays ungated so every run computes the real verdict, because a job skipped by if reports a check that branch protection counts as passing. (#6941)
  • A release using a [[tool.reflex-release.custom-build]] entry no longer publishes nothing while reporting success. Exactly one of the built-in build job and a custom-build job runs for any given package, so the other is always skipped β€” and GitHub evaluates the implicit success() a job gets when its if names no status function over the whole transitive dependency closure, not just the direct needs. The skipped build therefore reached publish straight through the collect written to absorb it, and tag-and-release behind it: every build succeeded, the artifacts were verified and checksummed, and then the upload silently never happened. Both jobs now carry an explicit needs.<job>.result == 'success' guard. release_from_changelog.yml's report job, the canonical failure signal for a partial release, was blind to the same shape because it accepted any skipped leg; it now accepts a skipped leg only when detection found nothing for that leg to publish, so a release that publishes nothing β€” or holds a lockstep package back β€” is red. (#6950)

Miscellaneous

  • Every run: step in the generated release workflows now declares shell: bash, so a defaults.run.shell added to one of those files β€” or a runner whose default shell is not bash β€” cannot change how a release-critical script is interpreted, or silently drop the -e/-o pipefail a failing step relies on. (#6926)
  • Property docstrings are now noun phrases rather than "Get the ..." / "Return the ..." (ruff 0.16's new D421).
  • Append new Config fields after the existing ones. Config is exported, so its generated __init__ has a positional contract that inserting a field in the middle would break for any caller that does not pass every argument by keyword; a test now pins the historical field order as a prefix. (#6941)
  • Pin hatchling and uv-dynamic-versioning exactly in this package's [build-system] requires. Build requirements are resolved fresh rather than locked, so a repository that vendors the tool β€” running it from its own lockfile rather than PyPI β€” no longer has the backend that builds its release tooling move underneath it. (#6941)
  • Raise the package-checkbox limit on the Dispatch release form from ten to twenty, matching GitHub's actual workflow_dispatch input limit. Repositories with between nine and nineteen releasable packages (or lockstep groups) keep the checkboxes under dispatch-package-inputs = "auto" instead of falling back to the comma-separated field. (#6941)