feat: add --promote-alpha option to create_github_release script (#6370)
Historically, running `create_github_release --publish-release` would
always publish a new release from latest `main`, which isn't always the
best idea. We should really publish an alpha, let it bake, and then
promote it.
This PR introduces a new flag, `--promote-alpha`, which does exactly
that. It also works with `--dry-run`, so you can sanity check the commit
it will use as the base commit for the new release before running it for
real.
```shell
$ ./codex-rs/scripts/create_github_release --dry-run --promote-alpha 0.56.0-alpha.2
Publishing version 0.56.0
Running gh api GET /repos/openai/codex/git/refs/tags/rust-v0.56.0-alpha.2
Running gh api GET /repos/openai/codex/git/tags/7d4ef77bc35b011aa0c76c5cbe6cd7d3e53f1dfe
Running gh api GET /repos/openai/codex/compare/main...8b49211e67d3c863df5ecc13fc5f88516a20fa69
Would publish version 0.56.0 using base commit 62474a30e8 derived from rust-v0.56.0-alpha.2.
```
This commit is contained in:
@@ -21,6 +21,11 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
||||
action="store_true",
|
||||
help="Print the version that would be used and exit before making changes.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--promote-alpha",
|
||||
metavar="VERSION",
|
||||
help="Promote an existing alpha tag (e.g., 0.56.0-alpha.5) by using its merge-base with main as the base commit.",
|
||||
)
|
||||
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
@@ -43,26 +48,43 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
||||
args.publish_alpha
|
||||
or args.publish_release
|
||||
or args.emergency_version_override
|
||||
or args.promote_alpha
|
||||
):
|
||||
parser.error(
|
||||
"Must specify --publish-alpha, --publish-release, or --emergency-version-override."
|
||||
"Must specify --publish-alpha, --publish-release, --promote-alpha, or --emergency-version-override."
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
args = parse_args(argv)
|
||||
|
||||
# Strip the leading "v" if present.
|
||||
promote_alpha = args.promote_alpha
|
||||
if promote_alpha and promote_alpha.startswith("v"):
|
||||
promote_alpha = promote_alpha[1:]
|
||||
|
||||
try:
|
||||
if args.emergency_version_override:
|
||||
if promote_alpha:
|
||||
version = derive_release_version_from_alpha(promote_alpha)
|
||||
elif args.emergency_version_override:
|
||||
version = args.emergency_version_override
|
||||
else:
|
||||
version = determine_version(args)
|
||||
print(f"Publishing version {version}")
|
||||
if args.dry_run:
|
||||
if promote_alpha:
|
||||
base_commit = get_promote_alpha_base_commit(promote_alpha)
|
||||
if args.dry_run:
|
||||
print(
|
||||
f"Would publish version {version} using base commit {base_commit} derived from rust-v{promote_alpha}."
|
||||
)
|
||||
return 0
|
||||
elif args.dry_run:
|
||||
return 0
|
||||
|
||||
print("Fetching branch head...")
|
||||
base_commit = get_branch_head()
|
||||
if not promote_alpha:
|
||||
print("Fetching branch head...")
|
||||
base_commit = get_branch_head()
|
||||
print(f"Base commit: {base_commit}")
|
||||
print("Fetching commit tree...")
|
||||
base_tree = get_commit_tree(base_commit)
|
||||
@@ -130,6 +152,39 @@ def get_branch_head() -> str:
|
||||
raise ReleaseError("Unable to determine branch head.") from error
|
||||
|
||||
|
||||
def get_promote_alpha_base_commit(alpha_version: str) -> str:
|
||||
tag_name = f"rust-v{alpha_version}"
|
||||
tag_commit_sha = get_tag_commit_sha(tag_name)
|
||||
return get_merge_base_with_main(tag_commit_sha)
|
||||
|
||||
|
||||
def get_tag_commit_sha(tag_name: str) -> str:
|
||||
response = run_gh_api(f"/repos/{REPO}/git/refs/tags/{tag_name}")
|
||||
try:
|
||||
sha = response["object"]["sha"]
|
||||
obj_type = response["object"]["type"]
|
||||
except KeyError as error:
|
||||
raise ReleaseError(f"Unable to resolve tag {tag_name}.") from error
|
||||
while obj_type == "tag":
|
||||
tag_response = run_gh_api(f"/repos/{REPO}/git/tags/{sha}")
|
||||
try:
|
||||
sha = tag_response["object"]["sha"]
|
||||
obj_type = tag_response["object"]["type"]
|
||||
except KeyError as error:
|
||||
raise ReleaseError(f"Unable to resolve annotated tag {tag_name}.") from error
|
||||
if obj_type != "commit":
|
||||
raise ReleaseError(f"Tag {tag_name} does not reference a commit.")
|
||||
return sha
|
||||
|
||||
|
||||
def get_merge_base_with_main(commit_sha: str) -> str:
|
||||
response = run_gh_api(f"/repos/{REPO}/compare/main...{commit_sha}")
|
||||
try:
|
||||
return response["merge_base_commit"]["sha"]
|
||||
except KeyError as error:
|
||||
raise ReleaseError("Unable to determine merge base with main.") from error
|
||||
|
||||
|
||||
def get_commit_tree(commit_sha: str) -> str:
|
||||
response = run_gh_api(f"/repos/{REPO}/git/commits/{commit_sha}")
|
||||
try:
|
||||
@@ -309,5 +364,12 @@ def format_version(major: int, minor: int, patch: int) -> str:
|
||||
return f"{major}.{minor}.{patch}"
|
||||
|
||||
|
||||
def derive_release_version_from_alpha(alpha_version: str) -> str:
|
||||
match = re.match(r"^(\d+)\.(\d+)\.(\d+)-alpha\.(\d+)$", alpha_version)
|
||||
if match is None:
|
||||
raise ReleaseError(f"Unexpected alpha version format: {alpha_version}")
|
||||
return f"{match.group(1)}.{match.group(2)}.{match.group(3)}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
||||
|
||||
Reference in New Issue
Block a user