blob: 2b3d5859c1687138f38ec922961e5dbd7ebd317d [file] [view]
# Releasing
Start from a clean checkout at `main`.
Before running through the release it's good to run the build and the tests
locally, and make sure CI is passing. You can also test-drive the commit in an
existing Bazel workspace to sanity check functionality.
## Releasing from HEAD
Releases are managed using a semi-automated process centered around a GitHub
Release Tracking Issue and automated workflows triggered by comments or issue edits.
> [!NOTE]
> Comment-based commands must be posted by project maintainers (Owner,
> Member, or Collaborator) and must be on their own line (leading and trailing
> whitespace is ignored).
### Steps
1. **Prepare the Release**: Run the [Release: Prepare](https://github.com/bazel-contrib/rules_python/actions/workflows/release_prepare.yaml)
workflow manually. You can trigger it from the GitHub Actions UI or using
the GitHub CLI:
```shell
gh workflow run release_prepare.yaml --repo bazel-contrib/rules_python
```
This will automatically determine the next version, create a release tracking
issue, and send a preparation PR.
2. **Approve and Merge**: Approve and merge the PR. Once merged, a release
branch will be created automatically.
3. **Add Backports (if needed)**: If there are backports, add them following
the [How to add backports](#how-to-add-backports) steps.
4. **Create an RC**: Comment `/create-rc` on the tracking issue. This will
automatically process pending backports before creating the RC. If any
backport fails, the RC creation will abort.
5. **Iterate**: Repeat steps 3 and 4 until backports and RCs are no longer
needed.
6. **Finalize the Release**: Comment `/promote` on the tracking issue to
finalize the release.
### Manually triggering the release workflow
The release workflow can be manually triggered using the GitHub CLI (`gh`).
This is useful for re-running a release or for creating a release from a
specific commit.
To trigger the workflow, use the `gh workflow run` command:
```shell
gh workflow run release_publish.yaml --ref <TAG>
```
By default, the workflow will publish the wheel to PyPI. To skip this step,
you can set the `publish_to_pypi` input to `false`:
```shell
gh workflow run release_publish.yaml --ref <TAG> -f publish_to_pypi=false
```
### Manually publishing to PyPI
If PyPI publishing failed or was skipped during the main release, the PyPI
publishing workflow can be triggered manually using the GitHub CLI (`gh`) or
via the [GitHub Actions UI](https://github.com/bazel-contrib/rules_python/actions/workflows/publish_pypi.yaml):
```shell
gh workflow run publish_pypi.yaml --ref <TAG> -f tag_name=<TAG>
```
### Determining Semantic Version
**rules_python** uses [semantic version](https://semver.org), so releases with
API changes and new features bump the minor, and those with only bug fixes and
other minor changes bump the patch digit.
The release tool will automatically determine the next version number based on
the `VERSION_NEXT_*` placeholders in the codebase. To see what changes are
being accumulated for the next release, review the pending news entries in the
`news/` directory.
## How to add backports
To add backports to an active release, you can use one of the following
methods:
### Method A: Comment on the PR
Comment `/backport` on the PR you wish to backport. This will automatically
add the PR to the active release's backports checklist. Once the PR is merged,
the backports will be automatically processed.
> [!NOTE]
> Commenting `/backport` on an open PR will block further release publishing
> (like creating RCs or promoting) until the PR is merged or manually set to
> status=ignore in the checklist.
### Method B: Comment on the Tracking Issue
Comment `/add-backports <PR_REF> [<PR_REF> ...]` (space or comma separated) on
the tracking issue. The `<PR_REF>` can be a PR number (optionally prefixed with
`#`) or a PR URL (strictly for the configured repository). This will
automatically add the PRs to the checklist and trigger processing.
### Method C: Manual Checklist Update
1. Manually add checklist items under the `## Backports` section of the
Release Tracking Issue. The format must be: `- [ ] #<PR_NUMBER>` (e.g.,
`- [ ] #1234`).
2. When ready, comment `/process-backports` on the tracking issue to trigger
processing.
### Method D: Release Tool CLI
You can use the release tool to add backports from your local checkout:
```shell
bazel run //tools/private/release -- add-backports <PR_REF> [<PR_REF> ...]
```
The `<PR_REF>` can be:
* A PR number (e.g., `124` or `#124`)
* A PR URL (e.g., `https://github.com/bazel-contrib/rules_python/pull/124`
or `https://github.com/bazel-contrib/rules_python/pull/124/files`)
* Only URLs for the configured repository are accepted.
### Failure Behavior
If a backport fails to process (e.g., due to cherry-pick conflicts):
* The failed backport checklist item will remain unchecked with
`status=error-<reason>`.
* You must resolve the conflict manually: checkout the release branch,
cherry-pick the PR, resolve conflicts, push to remote, and manually check
the box on the tracking issue checklist with `status=done` metadata.
## Automated patch releases to multiple versions
If you need to backport a PR to multiple older active release branches (e.g.,
backporting a fix to `1.7`, `1.8`, and `1.9` when the latest release is
`2.2.0`), you can automate the creation of release tracking issues and
verification of cherry-picks using a Backport Tracking Issue.
### Steps
1. **Create a Backport Tracking Issue**: Create a new issue on GitHub with
the label `type: backport-pr`.
* The title should describe the backport, e.g., `Backport: #1234`
(referencing the PR to backport).
* The body must contain the target range in the following format:
```markdown
* PR: #1234
* From version: 1.7
* To version: 2.2
```
This tells the tool to target all active release branches between
`release/1.7` and `release/2.2` inclusive.
2. **Prepare the Backports**: Trigger the preparation by commenting `/prepare`
on the backport tracking issue, or by manually running the [Backport:
Prepare](https://github.com/bazel-contrib/rules_python/actions/workflows/backport_prepare.yaml)
workflow with the issue number.
* The workflow will checkout each release branch in the range, attempt to
cherry-pick the PR, and verify if the changelog can be updated.
* It will then update the backport tracking issue body with a list of
tasks:
* `Verify apply <minor_version>`: Automatically checked if the
cherry-pick succeeded, or left unchecked with
`status=failed-conflict` or `status=failed-changelog` if it failed.
* `Release issue <next_version>`: A task to initiate the release for
each target version.
3. **Resolve Conflicts (if any)**: If any `Verify apply` task failed:
* You must resolve the conflict manually on that specific release branch
(checkout branch, cherry-pick, resolve conflicts, push to remote).
* Once resolved, manually check the corresponding `Verify apply` task box
on the tracking issue and set its metadata to `status=success` (e.g.,
`- [x] Verify apply 1.8 | status=success`).
4. **Initiate Releases**: Once all `Verify apply` tasks are successful
(either automatically or after manual resolution), comment
`/create-releases` on the backport tracking issue, or manually run the
[Backport: Create
Releases](https://github.com/bazel-contrib/rules_python/actions/workflows/backport_create_releases.yaml)
workflow.
* This will automatically create a standard Release Tracking Issue for
each target version (e.g., `Release 1.7.1`, `Release 1.8.1`, etc.).
* For patch releases, the created release tracking issues will have `Tag
RC` tasks automatically removed, as release candidates are not
required for patch releases.
* The backport PR will be automatically added to the checklist of each
created release tracking issue.
5. **Execute Releases**: Follow the standard release process for each created
release tracking issue. Since these are patch releases, you can skip the
`/create-rc` step and comment `/promote` directly to tag and publish the
release from the release branch head.
## Manual patch release with cherry picks
If a patch release from head would contain changes that aren't appropriate for
a patch release, then the patch release needs to be based on the original
release tag and the patch changes cherry-picked into it.
In this example, release `0.37.0` is being patched to create release `0.37.1`.
The fix being included is commit `deadbeef`.
1. `git checkout release/0.37`
1. `git cherry-pick -x deadbeef`
1. Fix merge conflicts, if any.
1. `git cherry-pick --continue` (if applicable)
1. `git push upstream`
If multiple commits need to be applied, repeat the `git cherry-pick` step for
each.
Once the release branch is in the desired state, comment `/create-rc` on the
tracking issue to tag it, as done with a release from head.
### Announcing releases
We announce releases in the #python channel in the Bazel slack
(bazelbuild.slack.com). Here's a template:
```
Greetings Pythonistas,
rules_python X.Y.Z-rcN is now available
Changelog: https://rules-python.readthedocs.io/en/X.Y.Z-rcN/changelog.html#vX-Y-Z
It will be promoted to stable next week, pending feedback.
```
It's traditional to include notable changes from the changelog, but not
required.
### Re-releasing a version
Re-releasing a version (i.e. changing the commit a tag points to) is
*sometimes* possible, but it depends on how far into the release process it got.
The two points of no return are:
* If the PyPI package has been published: PyPI disallows using the same
filename/version twice. Once published, it cannot be replaced.
* If the BCR package has been published: Once it's been committed to the BCR
registry, it cannot be replaced.
If release steps fail _prior_ to those steps, then its OK to change the tag. You
may need to manually delete the GitHub release.
## Manual Editing of Tracking Issue
You can manually edit the Release Tracking Issue to control the release flow.
The checklist items use metadata suffix: `| key=value key2=value2`.
* **Retry Prepare Release**: Reset the task to `- [ ] Prepare Release | status=awaiting-preparation`.
* **Force Task Done**: Check the box `- [x]` and add appropriate metadata (e.g. `status=done`).
## Secrets
### PyPI user rules-python
Part of the release process uploads packages to PyPI as the user `rules-python`.
This account is managed by `rickeylev`. Note that Google also has recovery access
and can be contacted at rules-python-pypi@google.com if something needs to be
done with the PyPI account.