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",
|
action="store_true",
|
||||||
help="Print the version that would be used and exit before making changes.",
|
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 = parser.add_mutually_exclusive_group()
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
@@ -43,26 +48,43 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|||||||
args.publish_alpha
|
args.publish_alpha
|
||||||
or args.publish_release
|
or args.publish_release
|
||||||
or args.emergency_version_override
|
or args.emergency_version_override
|
||||||
|
or args.promote_alpha
|
||||||
):
|
):
|
||||||
parser.error(
|
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
|
return args
|
||||||
|
|
||||||
|
|
||||||
def main(argv: list[str]) -> int:
|
def main(argv: list[str]) -> int:
|
||||||
args = parse_args(argv)
|
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:
|
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
|
version = args.emergency_version_override
|
||||||
else:
|
else:
|
||||||
version = determine_version(args)
|
version = determine_version(args)
|
||||||
print(f"Publishing version {version}")
|
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
|
return 0
|
||||||
|
|
||||||
print("Fetching branch head...")
|
if not promote_alpha:
|
||||||
base_commit = get_branch_head()
|
print("Fetching branch head...")
|
||||||
|
base_commit = get_branch_head()
|
||||||
print(f"Base commit: {base_commit}")
|
print(f"Base commit: {base_commit}")
|
||||||
print("Fetching commit tree...")
|
print("Fetching commit tree...")
|
||||||
base_tree = get_commit_tree(base_commit)
|
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
|
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:
|
def get_commit_tree(commit_sha: str) -> str:
|
||||||
response = run_gh_api(f"/repos/{REPO}/git/commits/{commit_sha}")
|
response = run_gh_api(f"/repos/{REPO}/git/commits/{commit_sha}")
|
||||||
try:
|
try:
|
||||||
@@ -309,5 +364,12 @@ def format_version(major: int, minor: int, patch: int) -> str:
|
|||||||
return f"{major}.{minor}.{patch}"
|
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__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main(sys.argv))
|
sys.exit(main(sys.argv))
|
||||||
|
|||||||
Reference in New Issue
Block a user