chore: change create_github_release to create a fresh clone in a temp directory (#3228)

Ran:

```
./codex-rs/scripts/create_github_release 0.31.0-alpha.1
```

which appeared to work as expected:

- workflow https://github.com/openai/codex/actions/runs/17508403922
- release
https://github.com/openai/codex/releases/tag/rust-v0.31.0-alpha.1

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/3228).
* #3231
* #3230
* __->__ #3228
* #3226
This commit is contained in:
Michael Bolin
2025-09-05 21:57:11 -07:00
committed by GitHub
parent bd65f81e54
commit 066c6cce02

View File

@@ -1,17 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import os
import re import re
import subprocess import subprocess
import sys import sys
import tempfile
from pathlib import Path from pathlib import Path
ROOT_DIR = Path(__file__).resolve().parent.parent
CARGO_TOML = ROOT_DIR / "Cargo.toml"
def parse_args(argv: list[str]) -> argparse.Namespace: def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Create a tagged Codex release.") parser = argparse.ArgumentParser(description="Create a tagged Codex release.")
parser.add_argument( parser.add_argument(
@@ -22,87 +18,62 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
def main(argv: list[str]) -> int: def main(argv: list[str]) -> int:
os.chdir(ROOT_DIR)
args = parse_args(argv) args = parse_args(argv)
try: try:
ensure_clean_worktree() with tempfile.TemporaryDirectory() as temp_dir:
branch = current_branch() repo_dir = Path(temp_dir) / "codex"
ensure_on_main(branch) clone_repository(repo_dir)
ensure_on_origin_main() branch = current_branch(repo_dir)
create_release(args.version, branch) create_release(args.version, branch, repo_dir)
except ReleaseError as error: except ReleaseError as error:
print(f"ERROR: {error}", file=sys.stderr) print(f"ERROR: {error}", file=sys.stderr)
return 1 return 1
return 0 return 0
def ensure_clean_worktree() -> None: def current_branch(repo_dir: Path) -> str:
commands = [ result = run_git(
["diff", "--quiet"], repo_dir,
["diff", "--cached", "--quiet"], ["symbolic-ref", "--short", "-q", "HEAD"],
] capture_output=True,
for command in commands: check=False,
result = run_git(command, check=False) )
if result.returncode != 0:
raise ReleaseError("You have uncommitted changes.")
untracked = run_git(["ls-files", "--others", "--exclude-standard"], capture_output=True)
if untracked.stdout.strip():
raise ReleaseError("You have untracked files.")
def ensure_on_main(branch: str) -> None:
if branch != "main":
raise ReleaseError(
f"Releases must be created from the 'main' branch (current: '{branch}')."
)
def ensure_on_origin_main() -> None:
try:
run_git(["fetch", "--quiet", "origin", "main"])
except ReleaseError as error:
raise ReleaseError(
"Failed to fetch 'origin/main'. Ensure the 'origin' remote is configured and reachable."
) from error
result = run_git(["merge-base", "--is-ancestor", "HEAD", "origin/main"], check=False)
if result.returncode != 0:
raise ReleaseError(
"Your local 'main' HEAD commit is not present on 'origin/main'. "
"Please push first (git push origin main) or check out a commit on 'origin/main'."
)
def current_branch() -> str:
result = run_git(["symbolic-ref", "--short", "-q", "HEAD"], capture_output=True, check=False)
branch = result.stdout.strip() branch = result.stdout.strip()
if result.returncode != 0 or not branch: if result.returncode != 0 or not branch:
raise ReleaseError("Could not determine the current branch (detached HEAD?).") raise ReleaseError("Could not determine the current branch (detached HEAD?).")
return branch return branch
def update_version(version: str) -> None: def update_version(version: str, cargo_toml: Path) -> None:
content = CARGO_TOML.read_text(encoding="utf-8") content = cargo_toml.read_text(encoding="utf-8")
new_content, matches = re.subn( new_content, matches = re.subn(
r'^version = "[^"]+"', f'version = "{version}"', content, count=1, flags=re.MULTILINE r'^version = "[^"]+"', f'version = "{version}"', content, count=1, flags=re.MULTILINE
) )
if matches != 1: if matches != 1:
raise ReleaseError("Unable to update version in Cargo.toml.") raise ReleaseError("Unable to update version in Cargo.toml.")
CARGO_TOML.write_text(new_content, encoding="utf-8") cargo_toml.write_text(new_content, encoding="utf-8")
def create_release(version: str, branch: str) -> None: def create_release(version: str, branch: str, repo_dir: Path) -> None:
tag = f"rust-v{version}" tag = f"rust-v{version}"
run_git(["checkout", "-b", tag]) run_git(repo_dir, ["checkout", "-b", tag])
try: try:
update_version(version) update_version(version, repo_dir / "codex-rs" / "Cargo.toml")
run_git(["add", "Cargo.toml"]) run_git(repo_dir, ["add", "codex-rs/Cargo.toml"])
run_git(["commit", "-m", f"Release {version}"]) run_git(repo_dir, ["commit", "-m", f"Release {version}"])
run_git(["tag", "-a", tag, "-m", f"Release {version}"]) run_git(repo_dir, ["tag", "-a", tag, "-m", f"Release {version}"])
run_git(["push", "origin", f"refs/tags/{tag}"]) run_git(repo_dir, ["push", "origin", f"refs/tags/{tag}"])
finally: finally:
run_git(["checkout", branch]) run_git(repo_dir, ["checkout", branch])
def clone_repository(destination: Path) -> None:
result = subprocess.run(
["gh", "repo", "clone", "openai/codex", str(destination), "--", "--depth", "1"],
text=True,
)
if result.returncode != 0:
raise ReleaseError("Failed to clone openai/codex using gh.")
class ReleaseError(RuntimeError): class ReleaseError(RuntimeError):
@@ -110,11 +81,15 @@ class ReleaseError(RuntimeError):
def run_git( def run_git(
args: list[str], *, capture_output: bool = False, check: bool = True repo_dir: Path,
args: list[str],
*,
capture_output: bool = False,
check: bool = True,
) -> subprocess.CompletedProcess: ) -> subprocess.CompletedProcess:
result = subprocess.run( result = subprocess.run(
["git", *args], ["git", *args],
cwd=ROOT_DIR, cwd=repo_dir,
text=True, text=True,
capture_output=capture_output, capture_output=capture_output,
) )