Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions .github/ISSUE_TEMPLATE/patch_release_request.md

This file was deleted.

12 changes: 8 additions & 4 deletions .github/ISSUE_TEMPLATE/release_tracking_template.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
---
name: Release Tracking Issue
about: Checklist for tracking a new release of rules_python.
name: Release or Backport Tracking Issue
about: Checklist for tracking a new release, patch release, or backport of rules_python.
title: 'Release <version>'
labels: ['type: release']
---
# Release tasks
<!-- For patch releases and backports, only "Tag Final" is needed; delete the
other release tasks below. -->
- [ ] Prepare Release | status=awaiting-preparation
- [ ] Create Release branch
- [ ] Tag RC0
- [ ] Tag Final

## Backports

To request a backport, comment `/backport` on the PR, comment `/backport <PR>`
on this issue, or add it to the checklist below. See
To request or track a backport, comment `/backport` on the PR, comment
`/backport <PR>` on this issue, or add it to the checklist below. See
[RELEASING.md: How to add backports](https://github.com/bazel-contrib/rules_python/blob/main/RELEASING.md#how-to-add-backports)
for details.

- [ ] #PR_NUMBER

---

To manually control the release flow, see the
Expand Down
37 changes: 25 additions & 12 deletions docs/devguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,25 @@ we prepare for releases.
(creating-backport-prs)=
## Creating Backport PRs

:::{note}
Prefer filing a backport issue using the [release or backport tracking
template][backport-issue], because it triggers automation to perform all
necessary backporting steps.
:::

The steps to create a backport PR are:

1. Create an issue for the patch release; use the [patch release
template][patch-release-issue].
2. Create a fork of `rules_python`.
3. Checkout the `release/X.Y` branch.
4. Use `git cherry-pick -x` to cherry pick the desired fixes.
5. Update the release's `CHANGELOG.md` file:
* Add a Major.Minor.Patch section if one doesn't exist
* Copy the changelog text from `main` to the release's changelog.
6. Send a PR with the backport's changes.
1. Create a fork of `rules_python`.
2. Checkout the `release/X.Y` branch.
3. Use `git cherry-pick -x` to cherry pick the desired fixes.
4. Update the release's `CHANGELOG.md` file using the release tool's
`process-news` command:
```shell
bazel run //tools/private/release -- process-news <VERSION> <PR_NUMBER>
```
This merges the PR's news entries into `CHANGELOG.md`, deletes the news
files, and updates any `VERSION_NEXT_*` markers.
5. Send a PR with the backport's changes.
* The title should be `backport: PR#N to Major.Minor`
* The body must preserve the original PR's number, commit hash, description,
and authorship.
Expand All @@ -145,7 +153,12 @@ The steps to create a backport PR are:
```
* If the PR contains multiple backport commits, separate each's description
with `-----`.
7. Send a PR to update the `main` branch's `CHANGELOG.md` to reflect the
changes done in the patched release.
6. Send a PR to update the `main` branch's `CHANGELOG.md` to reflect the
changes done in the patched release:
* Checkout the `main` branch.
* Run the `process-news` command as before:
```shell
bazel run //tools/private/release -- process-news <VERSION> <PR_NUMBER>
```

[patch-release-issue]: https://github.com/bazelbuild/rules_python/issues/new?template=patch_release.md
[backport-issue]: https://github.com/bazel-contrib/rules_python/issues/new?template=release_tracking_template.md
10 changes: 6 additions & 4 deletions docs/support.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ Backports can be done to older releases, but only if newer releases also have
the fix backported. For example, if the current release is 1.5, in order to
patch 1.4, version 1.5 must be patched first.

Backports can be requested by [creating an issue with the patch release
template][patch-release-issue] or by sending a pull request performing the backport.
See the dev guide for [how to create a backport PR](creating-backport-prs).
Backports can be requested by [creating an issue with the release or backport
tracking template][backport-issue] or by sending a pull request performing the
backport. Creating an issue is preferred because it triggers automation to
perform all necessary backporting steps. See the dev guide for
[how to create a backport PR](creating-backport-prs).

[patch-release-issue]: https://github.com/bazelbuild/rules_python/issues/new?template=patch_release_request.md
[backport-issue]: https://github.com/bazel-contrib/rules_python/issues/new?template=release_tracking_template.md

## Supported Bazel Versions

Expand Down
36 changes: 36 additions & 0 deletions tests/tools/private/release/release_issue_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
add_sync_changelog_task_to_body,
format_metadata_line,
load_release_tracking_template,
parse_backports,
parse_checklist_state,
parse_metadata_line,
)
Expand Down Expand Up @@ -97,6 +98,41 @@ def test_add_backports_to_body():
assert updated_body.strip() == expected_body.strip()


def test_parse_backports_ignores_placeholders():
body = """
## Backports
- [ ] #PR_NUMBER
- [ ] #
- [ ] #123 | status=done
"""
items = parse_backports(body)
assert len(items) == 1
assert items[0].pr_ref == "#123"


def test_add_backports_to_body_removes_placeholders():
body = """
## Checklist
- [ ] Tag Final

## Backports
- [ ] #PR_NUMBER
- [ ] #
- [ ] #123 | status=done
"""
items = [{"ref": "124"}]
updated_body = add_backports_to_body(body, items)
expected_body = """
## Checklist
- [ ] Tag Final

## Backports
- [ ] #123 | status=done
- [ ] #124
"""
assert updated_body.strip() == expected_body.strip()


def test_add_sync_changelog_task_to_body():
body = """
## Checklist
Expand Down
20 changes: 18 additions & 2 deletions tools/private/release/release_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,13 @@ def parse_backports(body):
for line in lines:
parsed = parse_metadata_line(line)
if parsed:
name = parsed["name"].strip()
# Ignore empty or placeholder checklist items (e.g. '#PR_NUMBER')
if not re.match(r"^#?\d+$", name):
continue
items.append(
BackportTask(
pr_ref=parsed["name"],
pr_ref=name,
checked=parsed["checked"],
status=parsed["metadata"].get("status", "pending"),
rc=parsed["metadata"].get("rc"),
Expand Down Expand Up @@ -326,6 +330,15 @@ def add_backports_to_body(body: str, items: list[dict[str, Any]]) -> str:

section_content = match.group(2)

# Filter out empty or placeholder checklist items (e.g. "- [ ] #PR_NUMBER")
cleaned_lines = []
for line in section_content.splitlines():
parsed = parse_metadata_line(line)
if parsed and not re.match(r"^#?\d+$", parsed["name"].strip()):
continue
cleaned_lines.append(line)
section_content = "\n".join(cleaned_lines)

# Parse existing backports to avoid duplicates
existing_items = parse_backports(body)
existing_refs = {item.pr_ref for item in existing_items}
Expand All @@ -348,7 +361,10 @@ def add_backports_to_body(body: str, items: list[dict[str, Any]]) -> str:
)

if not new_lines:
return body
section_content_clean = section_content.rstrip("\n")
updated_section = section_content_clean + "\n\n"
start, end = match.span(2)
return body[:start] + updated_section + body[end:]

# Append new lines to the section content.
section_content_clean = section_content.rstrip("\n")
Expand Down