forked from bazel-contrib/rules_python
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcreate_rc.py
More file actions
114 lines (96 loc) · 3.97 KB
/
Copy pathcreate_rc.py
File metadata and controls
114 lines (96 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""Subcommand to tag and push the next release candidate."""
from tools.private.release import gh, git
from tools.private.release.release_issue import (
RELEASE_TITLE_RE,
parse_backports,
parse_checklist_state,
update_task_in_body,
)
from tools.private.release.utils import (
REPO_URL,
get_latest_rc_tag,
)
def cmd_create_rc(args):
"""Executes the create-rc subcommand."""
body = gh.get_issue_body(args.issue)
state = parse_checklist_state(body)
if (
state["prepare_release"]["status"] != "done"
or state["create_branch"]["status"] != "done"
):
print(
"Error: Preconditions not met (release must be prepared and branch created)."
)
return 1
# Gating: RC tagging is blocked if any backport is unchecked OR does not have status=done
backports = parse_backports(body)
conflicting_or_pending = [
b for b in backports if not b["checked"] or b["status"] != "done"
]
if conflicting_or_pending:
print(
f"Gating RC tagging: {len(conflicting_or_pending)} backports are still"
" unfinished, failed, or in conflict."
)
return 1
# Resolve version and branch
issue_title = gh.get_issue_title(args.issue)
version_match = RELEASE_TITLE_RE.search(issue_title)
if not version_match:
print(f"Error: Could not parse version from issue title: {issue_title}")
return 1
version = version_match.group(1)
branch_version = ".".join(version.split(".")[:2])
branch_name = f"release/{branch_version}"
# Determine next RC tag
git.fetch(args.remote)
git.fetch(args.remote, tags=True, force=True)
latest_rc = get_latest_rc_tag(version)
if not latest_rc:
next_rc_num = 0
next_rc = f"{version}-rc0"
else:
rc_num = int(latest_rc.split("-rc")[-1])
next_rc_num = rc_num + 1
next_rc = f"{version}-rc{next_rc_num}"
# Precheck: next RC number must exist and be unchecked in the checklist
rc_tags = state.get("rc_tags", {})
if next_rc_num not in rc_tags:
print(
f"Error: Checklist is missing required task 'Tag RC{next_rc_num}'"
f" to cut {version}-rc{next_rc_num}."
)
return 1
target_rc_task = rc_tags[next_rc_num]
if target_rc_task["checked"] or target_rc_task["status"] == "done":
print(
f"Error: Task 'Tag RC{next_rc_num}' is already marked done in the checklist."
)
return 1
# Verify HEAD is not already tagged
git.checkout(f"{args.remote}/{branch_name}")
head_tags = git.get_tags_at_head()
if any(tag.startswith(f"{version}-rc") for tag in head_tags):
print(f"HEAD of {branch_name} is already tagged with an RC. Skipping.")
return 0
print(f"Tagging and pushing next RC: {next_rc}...")
git.tag(next_rc, "HEAD")
git.push(args.remote, next_rc)
commit_sha = git.get_commit_sha("HEAD")
# Check off the appropriate "Tag RC{N}" task in the checklist
print(f"Checking off Tag RC{next_rc_num} task...")
metadata = {"status": "done", "tag": next_rc, "commit": commit_sha[:8]}
task_name = f"Tag RC{next_rc_num}"
updated_body = update_task_in_body(body, task_name, checked=True, metadata=metadata)
gh.update_issue_body(args.issue, updated_body)
tag_url = f"{REPO_URL}/releases/tag/{next_rc}"
bcr_search_url = f"https://github.com/bazelbuild/bazel-central-registry/pulls?q=is%3Apr+rules_python+{version}"
release_workflow_url = f"{REPO_URL}/actions/workflows/release.yml"
comment_body = f"""**New Release Candidate Tagged!** 🐍🌿
Release Candidate **{next_rc}** has been successfully generated and tagged on branch `{branch_name}`.
- View Tag: [{next_rc}]({tag_url})
- Track BCR Progress: [Search BCR Pull Requests]({bcr_search_url})
- Trigger Release Workflow: [Release Workflow]({release_workflow_url})"""
gh.post_issue_comment(args.issue, comment_body)
print("RC creation completed successfully!")
return 0