diff --git a/.github/workflows/release_add_backports.yaml b/.github/workflows/release_add_backports.yaml index b20fd95480..db28a03642 100644 --- a/.github/workflows/release_add_backports.yaml +++ b/.github/workflows/release_add_backports.yaml @@ -24,6 +24,7 @@ on: permissions: issues: write + pull-requests: write jobs: add_backports: diff --git a/dev/release/add_backports.py b/dev/release/add_backports.py index 8d357e8459..1a10e46cce 100644 --- a/dev/release/add_backports.py +++ b/dev/release/add_backports.py @@ -26,6 +26,7 @@ def run(self) -> int: args = self.args issue_num = args.issue + created_issue = False if not issue_num: print( "No issue specified. Trying to auto-discover active release" @@ -64,6 +65,7 @@ def run(self) -> int: issue_num = self.gh.create_release_tracking_issue( patch_version, template_content ) + created_issue = True print( f"::notice::Created patch release tracking issue #{issue_num} for" f" v{patch_version}" @@ -74,59 +76,75 @@ def run(self) -> int: ) return 1 - resolved_prs = [] + try: + body = self.gh.get_issue_body(issue_num) + issue_title = self.gh.get_issue_title(issue_num) + except Exception as e: + print(f"::error::Failed to update tracking issue: {e}") + return 1 + + version_match = RELEASE_TITLE_RE.search(issue_title) + is_patch = False + if version_match: + version = version_match.group(1) + is_patch = not version.endswith(".0") + + action = "Created" if created_issue else "Updated" + comment_body = ( + f"{action} release tracking issue #{issue_num} ({issue_title}) with" + " this PR added to the backports checklist." + ) + for pr_ref in args.prs: try: - pr_num = self.gh.resolve_pr_number(pr_ref) - resolved_prs.append(pr_num) + pr = self.gh.resolve_pr_number(pr_ref) except Exception as e: print(f"::error::Error resolving PR ref '{pr_ref}': {e}") return 1 - print( - f"Adding backports {resolved_prs} (resolved from {args.prs}) to tracking issue #{issue_num}..." - ) - try: - body = self.gh.get_issue_body(issue_num) - items_to_add = [{"ref": f"#{pr}"} for pr in resolved_prs] - body = add_backports_to_body(body, items_to_add) - for pr in resolved_prs: - body = add_sync_changelog_task_to_body(body, pr) - state = parse_checklist_state(body) - rc_tags = state.get("rc_tags", {}) - has_pending_rc = any( - not task.checked and task.status != "done" for task in rc_tags.values() + print( + f"Adding backport #{pr} (resolved from {pr_ref}) to tracking" + f" issue #{issue_num}..." ) - next_rc_num = max(rc_tags.keys()) + 1 if rc_tags else 0 + try: + body = add_backports_to_body(body, [{"ref": f"#{pr}"}]) + body = add_sync_changelog_task_to_body(body, pr) + state = parse_checklist_state(body) + rc_tags = state.get("rc_tags", {}) + has_pending_rc = any( + not task.checked and task.status != "done" + for task in rc_tags.values() + ) + next_rc_num = max(rc_tags.keys()) + 1 if rc_tags else 0 - issue_title = self.gh.get_issue_title(issue_num) - version_match = RELEASE_TITLE_RE.search(issue_title) - is_patch = False - if version_match: - version = version_match.group(1) - is_patch = not version.endswith(".0") + if not has_pending_rc and (rc_tags or not is_patch): + print( + f"No pending RC task found. Adding 'Tag" + f" RC{next_rc_num}' to checklist..." + ) + body = add_rc_task_to_body(body, next_rc_num) + except ValueError as e: + print(f"::error::{e}") + return 1 + except Exception as e: + print(f"::error::Failed to update tracking issue: {e}") + return 1 - if not has_pending_rc and (rc_tags or not is_patch): + try: + self.gh.update_issue_body(issue_num, body) print( - f"No pending RC task found. Adding 'Tag" - f" RC{next_rc_num}' to checklist..." + f"::notice::Successfully updated tracking issue #{issue_num}" + " checklist." ) - body = add_rc_task_to_body(body, next_rc_num) - except ValueError as e: - print(f"::error::{e}") - return 1 - except Exception as e: - print(f"::error::Failed to update tracking issue: {e}") - return 1 + except Exception as e: + print(f"::error::Failed to update tracking issue body: {e}") + return 1 - try: - self.gh.update_issue_body(issue_num, body) - print( - f"::notice::Successfully updated tracking issue #{issue_num} checklist." - ) - except Exception as e: - print(f"::error::Failed to update tracking issue body: {e}") - return 1 + try: + self.gh.post_issue_comment(pr, comment_body) + except Exception as e: + print(f"::error::Failed to post comment to PR #{pr}: {e}") + return 1 return 0 diff --git a/tests/tools/private/release/add_backports_test.py b/tests/tools/private/release/add_backports_test.py index 24636c6e3c..3b5ece7ccf 100644 --- a/tests/tools/private/release/add_backports_test.py +++ b/tests/tools/private/release/add_backports_test.py @@ -30,6 +30,12 @@ def test_add_backports_explicit_issue(mock_gh): assert "- [ ] Tag RC0" in updated_body assert "- [ ] Sync Changelog #124" in updated_body assert "- [ ] Sync Changelog #125" in updated_body + expected_comment = ( + "Updated release tracking issue #123 (Release 2.1.0) with this PR added" + " to the backports checklist." + ) + assert mock_gh.issue_comments[124] == [expected_comment] + assert mock_gh.issue_comments[125] == [expected_comment] def test_add_backports_auto_discover_success(mock_gh): @@ -51,6 +57,10 @@ def test_add_backports_auto_discover_success(mock_gh): assert result == 0 updated_body = mock_gh.get_issue_body(issue_num) assert "- [ ] #124" in updated_body + assert mock_gh.issue_comments[124] == [ + f"Updated release tracking issue #{issue_num} (Release 2.1.0) with this" + " PR added to the backports checklist." + ] def test_add_backports_auto_discover_no_issues_creates_patch_release( @@ -75,6 +85,10 @@ def test_add_backports_auto_discover_no_issues_creates_patch_release( assert "Prepare Release" not in body assert "Create Release branch" not in body assert "- [ ] Tag Final" in body + assert mock_gh.issue_comments[124] == [ + f"Created release tracking issue #{issue['number']} (Release 1.2.1)" + " with this PR added to the backports checklist." + ] def test_add_backports_auto_discover_skips_complete_release_creates_patch_release(