Files
codex/.github/scripts/releases.py
T
andrewgu-oai 5cbcf810e5 Prevent stable release pointers from moving backward (#51186)
## Why

Publishing an older stable version should not replace a newer release as the default download or installation target.

## What changed

- Compare stable versions before marking a GitHub release as latest, allowing same-version reruns to finish publication.
- Guard npm `latest` and platform dist-tags, publishing older versions under separate `release-<version>-<tag>` tags.
- Check R2's `latest` channel before updating it or the installer aliases, while allowing same-version reruns to repair interrupted installer updates.
- Reject invalid existing stable release metadata and consolidate GitHub latest and canary checks in `releases.py`.

## Testing

Add regression tests for stable version ordering, same-version reruns, npm package and platform tags, and invalid channel metadata. All 21 tests in `.github/scripts/test_releases.py` pass.

GitOrigin-RevId: e6bad3ee163b279ac1661b9070712a41eedd50ff
2026-10-05 22:19:18 +00:00

86 lines
3.1 KiB
Python

"""Validate Codex releases and check whether their GitHub channel pointers can advance."""
import argparse
import json
import re
import sys
_VERSION_RE = re.compile(
r"^[0-9]+\.[0-9]+\.[0-9]+(?:-(?:alpha(?:\.[0-9]+){0,2}"
r"|beta(?:\.[0-9]+)?))?$"
)
def is_valid_release_version(version: str) -> bool:
return _VERSION_RE.fullmatch(version) is not None
def is_valid_stable_release_version(version: str) -> bool:
return is_valid_release_version(version) and "-" not in version
def _version_key(version: str) -> tuple[tuple[int, ...], int, tuple[int, ...]]:
base, _, prerelease = version.partition("-")
channel, _, suffix = prerelease.partition(".")
return (
tuple(int(part) for part in base.split(".")),
{"alpha": 0, "beta": 1, "": 2}[channel],
tuple(int(part) for part in suffix.split(".")) if suffix else (),
)
def should_update_version(version: str, current_version: str) -> bool:
"""Compare version strings; replace an unreadable current version."""
if not is_valid_release_version(version):
raise ValueError(f"invalid release version: {version}")
if not is_valid_release_version(current_version):
# Replace an unreadable pointer so publishing can repair it.
return True
return _version_key(version) > _version_key(current_version)
def should_make_latest(version: str, latest: dict) -> bool:
if not is_valid_stable_release_version(version):
raise ValueError(f"expected a stable release version: {version}")
tag = latest.get("tag_name", "")
current = tag.removeprefix("rust-v") if isinstance(tag, str) else ""
if (
not isinstance(tag, str)
or not tag.startswith("rust-v")
or not is_valid_stable_release_version(current)
or latest.get("draft") is not False
or latest.get("prerelease") is not False
):
raise ValueError("Cannot determine the current GitHub latest stable release")
# An equal version must be able to finish a partially completed publication.
return version == current or should_update_version(version, current)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("version")
parser.add_argument(
"--check-github",
choices=("latest", "canary"),
help="Compare with the latest release JSON or canary Cargo.toml on stdin.",
)
args = parser.parse_args()
if args.check_github is None:
raise SystemExit(0 if is_valid_release_version(args.version) else 1)
if args.check_github == "latest":
update = should_make_latest(args.version, json.load(sys.stdin))
else:
import tomllib
try:
current_version = tomllib.loads(sys.stdin.read())["workspace"]["package"][
"version"
]
except (tomllib.TOMLDecodeError, KeyError, TypeError):
current_version = ""
if not isinstance(current_version, str):
current_version = ""
update = should_update_version(args.version, current_version)
print(str(update).lower())