Skip to content

Commit a25a43c

Browse files
committed
fix: change create_github_release to take either --create-alpha or --create-release
1 parent e93155a commit a25a43c

File tree

2 files changed

+108
-13
lines changed

2 files changed

+108
-13
lines changed

codex-rs/scripts/create_github_release

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,36 @@ CARGO_TOML_PATH = "codex-rs/Cargo.toml"
1414

1515

1616
def parse_args(argv: list[str]) -> argparse.Namespace:
17-
parser = argparse.ArgumentParser(description="Create a tagged Codex release.")
17+
parser = argparse.ArgumentParser(description="Publish a tagged Codex release.")
1818
parser.add_argument(
19-
"version",
20-
help="Version string used for Cargo.toml and the Git tag (e.g. 0.1.0-alpha.4).",
19+
"-n",
20+
"--dry-run",
21+
action="store_true",
22+
help="Print the version that would be used and exit before making changes.",
23+
)
24+
25+
group = parser.add_mutually_exclusive_group(required=True)
26+
group.add_argument(
27+
"--publish-alpha",
28+
action="store_true",
29+
help="Publish the next alpha release for the upcoming minor version.",
30+
)
31+
group.add_argument(
32+
"--publish-release",
33+
action="store_true",
34+
help="Publish the next stable release by bumping the minor version.",
2135
)
2236
return parser.parse_args(argv[1:])
2337

2438

2539
def main(argv: list[str]) -> int:
2640
args = parse_args(argv)
2741
try:
42+
version = determine_version(args)
43+
print(f"Publishing version {version}")
44+
if args.dry_run:
45+
return 0
46+
2847
print("Fetching branch head...")
2948
base_commit = get_branch_head()
3049
print(f"Base commit: {base_commit}")
@@ -34,21 +53,21 @@ def main(argv: list[str]) -> int:
3453
print("Fetching Cargo.toml...")
3554
current_contents = fetch_file_contents(base_commit)
3655
print("Updating version...")
37-
updated_contents = replace_version(current_contents, args.version)
56+
updated_contents = replace_version(current_contents, version)
3857
print("Creating blob...")
3958
blob_sha = create_blob(updated_contents)
4059
print(f"Blob SHA: {blob_sha}")
4160
print("Creating tree...")
4261
tree_sha = create_tree(base_tree, blob_sha)
4362
print(f"Tree SHA: {tree_sha}")
4463
print("Creating commit...")
45-
commit_sha = create_commit(args.version, tree_sha, base_commit)
64+
commit_sha = create_commit(version, tree_sha, base_commit)
4665
print(f"Commit SHA: {commit_sha}")
4766
print("Creating tag...")
48-
tag_sha = create_tag(args.version, commit_sha)
67+
tag_sha = create_tag(version, commit_sha)
4968
print(f"Tag SHA: {tag_sha}")
5069
print("Creating tag ref...")
51-
create_tag_ref(args.version, tag_sha)
70+
create_tag_ref(version, tag_sha)
5271
print("Done.")
5372
except ReleaseError as error:
5473
print(f"ERROR: {error}", file=sys.stderr)
@@ -59,6 +78,7 @@ def main(argv: list[str]) -> int:
5978
class ReleaseError(RuntimeError):
6079
pass
6180

81+
6282
def run_gh_api(endpoint: str, *, method: str = "GET", payload: dict | None = None) -> dict:
6383
print(f"Running gh api {method} {endpoint}")
6484
command = [
@@ -204,5 +224,73 @@ def create_tag_ref(version: str, tag_sha: str) -> None:
204224
)
205225

206226

227+
def determine_version(args: argparse.Namespace) -> str:
228+
latest_version = get_latest_release_version()
229+
major, minor, patch = parse_semver(latest_version)
230+
next_minor_version = format_version(major, minor + 1, patch)
231+
232+
if args.publish_release:
233+
return next_minor_version
234+
235+
alpha_prefix = f"{next_minor_version}-alpha."
236+
releases = list_releases()
237+
highest_alpha = 0
238+
found_alpha = False
239+
for release in releases:
240+
tag = release.get("tag_name", "")
241+
candidate = strip_tag_prefix(tag)
242+
if candidate and candidate.startswith(alpha_prefix):
243+
suffix = candidate[len(alpha_prefix) :]
244+
try:
245+
alpha_number = int(suffix)
246+
except ValueError:
247+
continue
248+
highest_alpha = max(highest_alpha, alpha_number)
249+
found_alpha = True
250+
251+
if found_alpha:
252+
return f"{alpha_prefix}{highest_alpha + 1}"
253+
return f"{alpha_prefix}1"
254+
255+
256+
def get_latest_release_version() -> str:
257+
response = run_gh_api(f"/repos/{REPO}/releases/latest")
258+
tag = response.get("tag_name")
259+
version = strip_tag_prefix(tag)
260+
if not version:
261+
raise ReleaseError("Latest release tag has unexpected format.")
262+
return version
263+
264+
265+
def list_releases() -> list[dict]:
266+
response = run_gh_api(f"/repos/{REPO}/releases?per_page=100")
267+
if not isinstance(response, list):
268+
raise ReleaseError("Unexpected response when listing releases.")
269+
return response
270+
271+
272+
def strip_tag_prefix(tag: str | None) -> str | None:
273+
if not tag:
274+
return None
275+
prefix = "rust-v"
276+
if not tag.startswith(prefix):
277+
return None
278+
return tag[len(prefix) :]
279+
280+
281+
def parse_semver(version: str) -> tuple[int, int, int]:
282+
parts = version.split(".")
283+
if len(parts) != 3:
284+
raise ReleaseError(f"Unexpected version format: {version}")
285+
try:
286+
return int(parts[0]), int(parts[1]), int(parts[2])
287+
except ValueError as error:
288+
raise ReleaseError(f"Version components must be integers: {version}") from error
289+
290+
291+
def format_version(major: int, minor: int, patch: int) -> str:
292+
return f"{major}.{minor}.{patch}"
293+
294+
207295
if __name__ == "__main__":
208296
sys.exit(main(sys.argv))

docs/release_management.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,23 @@ Currently, we made Codex binaries available in three places:
88

99
# Cutting a Release
1010

11-
Currently, choosing the version number for the next release is a manual process. In general, just go to https://github.com/openai/codex/releases/latest and see what the latest release is and increase the minor version by `1`, so if the current release is `0.20.0`, then the next release should be `0.21.0`.
11+
Run the `codex-rs/scripts/create_github_release` script in the repository to publish a new release. The script will choose the appropriate version number depending on the type of release you are creating.
1212

13-
Assuming you are trying to publish `0.21.0`, first you would run:
13+
To cut a new alpha release from `main` (feel free to cut alphas liberally):
1414

15-
```shell
16-
VERSION=0.21.0
17-
./codex-rs/scripts/create_github_release.sh "$VERSION"
1815
```
16+
./codex-rs/scripts/create_github_release --publish-alpha
17+
```
18+
19+
To cut a new _public_ release from `main` (which requires more caution), run:
20+
21+
```
22+
./codex-rs/scripts/create_github_release --publish-release
23+
```
24+
25+
TIP: Add the `--dry-run` flag to report the next version number for the respective release and exit.
1926

20-
This will kick off a GitHub Action to build the release, so go to https://github.com/openai/codex/actions/workflows/rust-release.yml to find the corresponding workflow. (Note: we should automate finding the workflow URL with `gh`.)
27+
Running the publishing script will kick off a GitHub Action to build the release, so go to https://github.com/openai/codex/actions/workflows/rust-release.yml to find the corresponding workflow. (Note: we should automate finding the workflow URL with `gh`.)
2128

2229
When the workflow finishes, the GitHub Release is "done," but you still have to consider npm and Homebrew.
2330

0 commit comments

Comments
 (0)