From 8e6504b9e750b15fc147dffd602a35f6a58b1a7d Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 30 Apr 2025 08:47:59 -0700 Subject: [PATCH] chore: create a script for the release process --- scripts/release_codex.py | 152 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100755 scripts/release_codex.py diff --git a/scripts/release_codex.py b/scripts/release_codex.py new file mode 100755 index 0000000000..7916ffa818 --- /dev/null +++ b/scripts/release_codex.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +""" +Automate the release procedure documented in `../README.md → Releasing codex`. + +Run this script from the repository *root*: + +```bash +python release_codex.py +``` + +It performs the same steps that the README lists manually: + +1. Create and switch to a `bump-version-` branch. +2. Bump the timestamp-based version in `codex-cli/package.json` **and** + `codex-cli/src/utils/session.ts`. +3. Commit with a DCO sign-off. +4. Copy the top-level `README.md` into `codex-cli/` (npm consumers see it). +5. Run `pnpm release` (copies README again, builds, publishes to npm). +6. Push the branch so you can open a PR that merges the version bump. + +The current directory can live anywhere; all paths are resolved relative to +this file so moving it elsewhere (e.g. into `scripts/`) still works. +""" + +from __future__ import annotations + +import datetime as _dt +import json as _json +import os +import re +import shutil +import subprocess as _sp +import sys +from pathlib import Path + +# --------------------------------------------------------------------------- +# Paths +# --------------------------------------------------------------------------- + +# repo-root/ +# ├── codex-cli/ +# ├── scripts/ <-- you are here +# └── README.md + +REPO_ROOT = Path(__file__).resolve().parent.parent +CODEX_CLI = REPO_ROOT / "codex-cli" +PKG_JSON = CODEX_CLI / "package.json" +SESSION_TS = CODEX_CLI / "src" / "utils" / "session.ts" +README_SRC = REPO_ROOT / "README.md" +README_DST = CODEX_CLI / "README.md" + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def sh(cmd: list[str] | str, *, cwd: Path | None = None) -> None: + """Run *cmd* printing it first and exit on non-zero status.""" + + if isinstance(cmd, list): + printable = " ".join(cmd) + else: + printable = cmd + + print("+", printable) + + _sp.run(cmd, cwd=cwd, shell=isinstance(cmd, str), check=True) + + +def _new_version() -> str: + """Return a new timestamp version string such as `0.1.2504301234`.""" + + return "0.1." + _dt.datetime.utcnow().strftime("%y%m%d%H%M") + + +def bump_version() -> str: + """Update package.json and session.ts, returning the new version.""" + + new_ver = _new_version() + + # ---- package.json + data = _json.loads(PKG_JSON.read_text()) + old_ver = data.get("version", "") + data["version"] = new_ver + PKG_JSON.write_text(_json.dumps(data, indent=2) + "\n") + + # ---- session.ts + pattern = r'CLI_VERSION = "0\\.1\\.\\d{10}"' + repl = f'CLI_VERSION = "{new_ver}"' + _text = SESSION_TS.read_text() + if re.search(pattern, _text): + SESSION_TS.write_text(re.sub(pattern, repl, _text)) + else: + print( + "WARNING: CLI_VERSION constant not found – file format may have changed", + file=sys.stderr, + ) + + print(f"Version bump: {old_ver} → {new_ver}") + return new_ver + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + + +def main() -> None: # noqa: C901 – readable top-level flow is desired + # Ensure we can locate required files. + for p in (CODEX_CLI, PKG_JSON, SESSION_TS, README_SRC): + if not p.exists(): + sys.exit(f"Required path missing: {p.relative_to(REPO_ROOT)}") + + os.chdir(REPO_ROOT) + + # ------------------------------- create release branch + branch = "bump-version-" + _dt.datetime.utcnow().strftime("%Y%m%d-%H%M") + sh(["git", "checkout", "-b", branch]) + + # ------------------------------- bump version + commit + new_ver = bump_version() + sh( + [ + "git", + "add", + str(PKG_JSON.relative_to(REPO_ROOT)), + str(SESSION_TS.relative_to(REPO_ROOT)), + ] + ) + sh(["git", "commit", "-s", "-m", f"chore(release): codex-cli v{new_ver}"]) + + # ------------------------------- copy README (shown on npmjs.com) + shutil.copyfile(README_SRC, README_DST) + + # ------------------------------- build + publish via pnpm script + sh(["pnpm", "install"], cwd=CODEX_CLI) + sh(["pnpm", "release"], cwd=CODEX_CLI) + + # ------------------------------- push branch + sh(["git", "push", "-u", "origin", branch]) + + print("\n✅ Release script finished!") + print(f" • npm publish run by pnpm script (branch: {branch})") + print(" • Open a PR to merge the version bump once CI passes.") + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + sys.exit("\nCancelled by user")