mirror of
https://github.com/openai/codex.git
synced 2026-09-08 15:50:34 +00:00
fix: split standalone installer staging from npm release flow
This commit is contained in:
12
.github/workflows/rust-release.yml
vendored
12
.github/workflows/rust-release.yml
vendored
@@ -540,8 +540,16 @@ jobs:
|
||||
--release-version "$RELEASE_VERSION" \
|
||||
--package codex \
|
||||
--package codex-responses-api-proxy \
|
||||
--package codex-sdk \
|
||||
--standalone-output-dir dist/installer
|
||||
--package codex-sdk
|
||||
|
||||
- name: Stage standalone installer archives
|
||||
env:
|
||||
RELEASE_VERSION: ${{ steps.release_name.outputs.name }}
|
||||
run: |
|
||||
./scripts/stage_standalone_installer_archives.py \
|
||||
--release-version "$RELEASE_VERSION" \
|
||||
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
||||
--output-dir dist/installer
|
||||
|
||||
- name: Stage installer scripts
|
||||
run: |
|
||||
|
||||
@@ -16,9 +16,6 @@ from pathlib import Path
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
BUILD_SCRIPT = REPO_ROOT / "codex-cli" / "scripts" / "build_npm_package.py"
|
||||
INSTALL_NATIVE_DEPS = REPO_ROOT / "codex-cli" / "scripts" / "install_native_deps.py"
|
||||
STAGE_STANDALONE_INSTALLER_ARCHIVES = (
|
||||
REPO_ROOT / "scripts" / "stage_standalone_installer_archives.py"
|
||||
)
|
||||
WORKFLOW_NAME = ".github/workflows/rust-release.yml"
|
||||
GITHUB_REPO = "openai/codex"
|
||||
|
||||
@@ -56,12 +53,6 @@ def parse_args() -> argparse.Namespace:
|
||||
default=None,
|
||||
help="Directory where npm tarballs should be written (default: dist/npm).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--standalone-output-dir",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="Directory where standalone installer archives should be written.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--keep-staging-dirs",
|
||||
action="store_true",
|
||||
@@ -139,26 +130,6 @@ def run_command(cmd: list[str]) -> None:
|
||||
subprocess.run(cmd, cwd=REPO_ROOT, check=True)
|
||||
|
||||
|
||||
def stage_standalone_installer_archives(
|
||||
release_version: str,
|
||||
vendor_src: Path,
|
||||
output_dir: Path,
|
||||
packages: list[str],
|
||||
) -> None:
|
||||
cmd = [
|
||||
str(STAGE_STANDALONE_INSTALLER_ARCHIVES),
|
||||
"--release-version",
|
||||
release_version,
|
||||
"--vendor-src",
|
||||
str(vendor_src),
|
||||
"--output-dir",
|
||||
str(output_dir),
|
||||
]
|
||||
for package in packages:
|
||||
cmd.extend(["--package", package])
|
||||
run_command(cmd)
|
||||
|
||||
|
||||
def tarball_name_for_package(package: str, version: str) -> str:
|
||||
if package in CODEX_PLATFORM_PACKAGES:
|
||||
platform = package.removeprefix("codex-")
|
||||
@@ -222,32 +193,6 @@ def main() -> int:
|
||||
|
||||
final_messages.append(f"Staged {package} at {pack_output}")
|
||||
|
||||
if args.standalone_output_dir is not None:
|
||||
if vendor_src is None:
|
||||
raise RuntimeError(
|
||||
"--standalone-output-dir requires staged native binaries, but no selected "
|
||||
"package installed native components."
|
||||
)
|
||||
standalone_packages = [
|
||||
package for package in packages if package in CODEX_PLATFORM_PACKAGES
|
||||
]
|
||||
if not standalone_packages:
|
||||
raise RuntimeError(
|
||||
"--standalone-output-dir requires at least one selected Codex platform "
|
||||
"package."
|
||||
)
|
||||
|
||||
standalone_output_dir = args.standalone_output_dir
|
||||
standalone_output_dir.mkdir(parents=True, exist_ok=True)
|
||||
stage_standalone_installer_archives(
|
||||
args.release_version,
|
||||
vendor_src,
|
||||
standalone_output_dir,
|
||||
standalone_packages,
|
||||
)
|
||||
final_messages.append(
|
||||
f"Staged standalone installer archives in {standalone_output_dir}"
|
||||
)
|
||||
finally:
|
||||
if vendor_temp_root is not None and not args.keep_staging_dirs:
|
||||
shutil.rmtree(vendor_temp_root, ignore_errors=True)
|
||||
|
||||
@@ -5,7 +5,10 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tarfile
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
@@ -13,6 +16,8 @@ from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
BUILD_SCRIPT = REPO_ROOT / "codex-cli" / "scripts" / "build_npm_package.py"
|
||||
INSTALL_NATIVE_DEPS = REPO_ROOT / "codex-cli" / "scripts" / "install_native_deps.py"
|
||||
WORKFLOW_NAME = ".github/workflows/rust-release.yml"
|
||||
|
||||
_SPEC = importlib.util.spec_from_file_location("codex_build_npm_package", BUILD_SCRIPT)
|
||||
if _SPEC is None or _SPEC.loader is None:
|
||||
@@ -20,6 +25,12 @@ if _SPEC is None or _SPEC.loader is None:
|
||||
_BUILD_MODULE = importlib.util.module_from_spec(_SPEC)
|
||||
_SPEC.loader.exec_module(_BUILD_MODULE)
|
||||
CODEX_PLATFORM_PACKAGES = getattr(_BUILD_MODULE, "CODEX_PLATFORM_PACKAGES", {})
|
||||
STANDALONE_NATIVE_COMPONENTS = (
|
||||
"codex",
|
||||
"codex-command-runner",
|
||||
"codex-windows-sandbox-setup",
|
||||
"rg",
|
||||
)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
@@ -32,9 +43,15 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument(
|
||||
"--vendor-src",
|
||||
type=Path,
|
||||
required=True,
|
||||
help="Directory containing native binaries under vendor/<target>.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--workflow-url",
|
||||
help=(
|
||||
"Optional workflow URL to download native artifacts from when --vendor-src "
|
||||
"is not provided."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
type=Path,
|
||||
@@ -51,7 +68,10 @@ def parse_args() -> argparse.Namespace:
|
||||
"Defaults to all platform packages."
|
||||
),
|
||||
)
|
||||
return parser.parse_args()
|
||||
args = parser.parse_args()
|
||||
if args.vendor_src is None and not args.workflow_url:
|
||||
parser.error("Provide either --vendor-src or --workflow-url.")
|
||||
return args
|
||||
|
||||
|
||||
def archive_name(platform_tag: str, version: str) -> str:
|
||||
@@ -98,28 +118,83 @@ def write_archive(staging_dir: Path, output_path: Path) -> None:
|
||||
archive.add(path, arcname=path.relative_to(staging_dir), recursive=False)
|
||||
|
||||
|
||||
def resolve_release_workflow(version: str) -> dict:
|
||||
stdout = subprocess.check_output(
|
||||
[
|
||||
"gh",
|
||||
"run",
|
||||
"list",
|
||||
"--branch",
|
||||
f"rust-v{version}",
|
||||
"--json",
|
||||
"workflowName,url,headSha",
|
||||
"--workflow",
|
||||
WORKFLOW_NAME,
|
||||
"--jq",
|
||||
"first(.[])",
|
||||
],
|
||||
cwd=REPO_ROOT,
|
||||
text=True,
|
||||
)
|
||||
workflow = json.loads(stdout or "null")
|
||||
if not workflow:
|
||||
raise RuntimeError(f"Unable to find rust-release workflow for version {version}.")
|
||||
return workflow
|
||||
|
||||
|
||||
def resolve_workflow_url(version: str, override: str | None) -> str:
|
||||
if override:
|
||||
return override
|
||||
workflow = resolve_release_workflow(version)
|
||||
return workflow["url"]
|
||||
|
||||
|
||||
def install_native_components(workflow_url: str, vendor_root: Path) -> Path:
|
||||
cmd = [str(INSTALL_NATIVE_DEPS), "--workflow-url", workflow_url]
|
||||
for component in STANDALONE_NATIVE_COMPONENTS:
|
||||
cmd.extend(["--component", component])
|
||||
cmd.append(str(vendor_root))
|
||||
subprocess.run(cmd, cwd=REPO_ROOT, check=True)
|
||||
return vendor_root / "vendor"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
vendor_src = args.vendor_src.resolve()
|
||||
output_dir = args.output_dir.resolve()
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
packages = args.packages or sorted(CODEX_PLATFORM_PACKAGES)
|
||||
for package in sorted(set(packages)):
|
||||
package_config = CODEX_PLATFORM_PACKAGES[package]
|
||||
platform_tag = package_config["npm_tag"]
|
||||
target = package_config["target_triple"]
|
||||
is_windows = package_config["os"] == "win32"
|
||||
output_path = output_dir / archive_name(platform_tag, args.release_version)
|
||||
runner_temp = Path(os.environ.get("RUNNER_TEMP", tempfile.gettempdir()))
|
||||
|
||||
with tempfile.TemporaryDirectory(
|
||||
prefix=f"codex-standalone-{platform_tag}-"
|
||||
) as staging_dir_str:
|
||||
staging_dir = Path(staging_dir_str)
|
||||
stage_target(vendor_src, staging_dir, target, is_windows)
|
||||
write_archive(staging_dir, output_path)
|
||||
vendor_temp_root: Path | None = None
|
||||
try:
|
||||
if args.vendor_src is not None:
|
||||
vendor_src = args.vendor_src.resolve()
|
||||
else:
|
||||
workflow_url = resolve_workflow_url(args.release_version, args.workflow_url)
|
||||
vendor_temp_root = Path(
|
||||
tempfile.mkdtemp(prefix="standalone-native-", dir=runner_temp)
|
||||
)
|
||||
vendor_src = install_native_components(workflow_url, vendor_temp_root)
|
||||
|
||||
print(f"Staged standalone installer archive at {output_path}")
|
||||
for package in sorted(set(packages)):
|
||||
package_config = CODEX_PLATFORM_PACKAGES[package]
|
||||
platform_tag = package_config["npm_tag"]
|
||||
target = package_config["target_triple"]
|
||||
is_windows = package_config["os"] == "win32"
|
||||
output_path = output_dir / archive_name(platform_tag, args.release_version)
|
||||
|
||||
with tempfile.TemporaryDirectory(
|
||||
prefix=f"codex-standalone-{platform_tag}-"
|
||||
) as staging_dir_str:
|
||||
staging_dir = Path(staging_dir_str)
|
||||
stage_target(vendor_src, staging_dir, target, is_windows)
|
||||
write_archive(staging_dir, output_path)
|
||||
|
||||
print(f"Staged standalone installer archive at {output_path}")
|
||||
finally:
|
||||
if vendor_temp_root is not None:
|
||||
shutil.rmtree(vendor_temp_root, ignore_errors=True)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user