From 8283bc56b1825737e1526e009d7b36a428423588 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 6 Sep 2026 20:45:38 +0000 Subject: [PATCH] Move npm package staging into a separate release workflow job (#43281) ## What changed - Stage npm tarballs in a job with `contents: read` permissions and upload them as the `npm-packages` artifact. - Require staging to succeed before the `release` job runs, and download the staged tarballs there. Remove its dependency installation, packaging steps, and `actions: read` permission. - Reuse native artifacts from `--artifacts-dir` when every target directory is nonempty, skipping workflow lookup and download. Retain workflow-based downloads as a fallback. GitOrigin-RevId: 89c6a5039afbac12968fb6f35a39c8db723c4c62 --- .github/workflows/rust-release.yml | 86 ++++++++++++++++++++---------- scripts/stage_npm_packages.py | 56 ++++++++++++++----- 2 files changed, 101 insertions(+), 41 deletions(-) diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-release.yml index e07c23b3ba..6e38336e73 100644 --- a/.github/workflows/rust-release.yml +++ b/.github/workflows/rust-release.yml @@ -1183,6 +1183,58 @@ jobs: with: publish: true + stage-npm-packages: + name: stage npm packages + needs: + - build + - finalize-macos + - build-windows + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Download target artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: dist + pattern: "{aarch64,x86_64}-{apple-darwin{,-app-server},unknown-linux-musl{,-app-server},pc-windows-msvc}" + + - name: Setup pnpm + uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5 + with: + run_install: false + + - name: Setup Node.js for npm packaging + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 22 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Stage npm packages + run: | + release_version="${GITHUB_REF_NAME#rust-v}" + ./scripts/stage_npm_packages.py \ + --release-version "$release_version" \ + --artifacts-dir "${GITHUB_WORKSPACE}/dist" \ + --package codex \ + --package codex-responses-api-proxy \ + --package codex-sdk + + - name: Upload staged npm packages + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: npm-packages + path: dist/npm/*.tgz + if-no-files-found: error + release: needs: - tag-check @@ -1190,6 +1242,7 @@ jobs: - finalize-macos - build-windows - argument-comment-lint-release-assets + - stage-npm-packages if: >- ${{ always() && @@ -1197,13 +1250,13 @@ jobs: needs.build.result == 'success' && needs.finalize-macos.result == 'success' && needs.build-windows.result == 'success' && - needs.argument-comment-lint-release-assets.result == 'success' + needs.argument-comment-lint-release-assets.result == 'success' && + needs.stage-npm-packages.result == 'success' }} name: release runs-on: ubuntu-latest permissions: contents: write - actions: read outputs: version: ${{ steps.release_name.outputs.name }} tag: ${{ github.ref_name }} @@ -1314,32 +1367,11 @@ jobs: echo "npm_tag=" >> "$GITHUB_OUTPUT" fi - - name: Setup pnpm - uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5 + - name: Download staged npm packages + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - run_install: false - - - name: Setup Node.js for npm packaging - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: 22 - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Stage npm packages - env: - GH_TOKEN: ${{ github.token }} - RELEASE_VERSION: ${{ steps.release_name.outputs.name }} - run: | - workflow_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" - ./scripts/stage_npm_packages.py \ - --release-version "$RELEASE_VERSION" \ - --workflow-url "$workflow_url" \ - --artifacts-dir "${GITHUB_WORKSPACE}/dist" \ - --package codex \ - --package codex-responses-api-proxy \ - --package codex-sdk + name: npm-packages + path: dist/npm - name: Stage installer scripts run: | diff --git a/scripts/stage_npm_packages.py b/scripts/stage_npm_packages.py index 1ce9b22d01..b258b4c946 100755 --- a/scripts/stage_npm_packages.py +++ b/scripts/stage_npm_packages.py @@ -181,7 +181,7 @@ def resolve_workflow_url(version: str, override: str | None) -> tuple[str, str | def install_native_components( - workflow_url: str, + workflow_url: str | None, components: set[str], vendor_root: Path, artifacts_dir: Path, @@ -192,16 +192,24 @@ def install_native_components( vendor_dir = vendor_root / "vendor" vendor_dir.mkdir(parents=True, exist_ok=True) - workflow_id = workflow_url.rstrip("/").split("/")[-1] - print(f"Downloading native artifacts from workflow {workflow_id}...", flush=True) - with _gha_group(f"Download native artifacts from workflow {workflow_id}"): - artifacts_dir.mkdir(parents=True, exist_ok=True) - install_from_workflow_artifacts( - workflow_id, - artifacts_dir, - sorted(components), - vendor_dir, + if workflow_url is None: + with _gha_group("Install downloaded native artifacts"): + install_from_downloaded_artifacts( + artifacts_dir, sorted(components), vendor_dir + ) + else: + workflow_id = workflow_url.rstrip("/").split("/")[-1] + print( + f"Downloading native artifacts from workflow {workflow_id}...", flush=True ) + with _gha_group(f"Download native artifacts from workflow {workflow_id}"): + artifacts_dir.mkdir(parents=True, exist_ok=True) + install_from_workflow_artifacts( + workflow_id, + artifacts_dir, + sorted(components), + vendor_dir, + ) print(f"Installed native dependencies into {vendor_dir}", flush=True) @@ -213,6 +221,14 @@ def install_from_workflow_artifacts( ) -> None: artifacts = select_target_artifacts(workflow_id, components) download_artifacts(workflow_id, artifacts_dir, artifacts) + install_from_downloaded_artifacts(artifacts_dir, components, vendor_dir) + + +def install_from_downloaded_artifacts( + artifacts_dir: Path, + components: Sequence[str], + vendor_dir: Path, +) -> None: if CODEX_PACKAGE_COMPONENT in components: install_codex_package_archives(artifacts_dir, vendor_dir, BINARY_TARGETS) install_binary_components( @@ -507,10 +523,6 @@ def main() -> int: try: if native_component_sets: - workflow_url, resolved_head_sha = resolve_workflow_url( - args.release_version, args.workflow_url - ) - print(f"Using native artifacts from {workflow_url}", flush=True) if args.artifacts_dir is not None: artifacts_temp_root = args.artifacts_dir.resolve() artifacts_temp_root.mkdir(parents=True, exist_ok=True) @@ -519,6 +531,22 @@ def main() -> int: tempfile.mkdtemp(prefix="npm-native-artifacts-", dir=runner_temp) ) remove_artifacts_temp_root = True + + target_artifact_dirs = [ + artifact_dir_for_target(artifacts_temp_root, target) + for target in BINARY_TARGETS + ] + if args.artifacts_dir is not None and all( + artifact_dir.is_dir() and any(artifact_dir.iterdir()) + for artifact_dir in target_artifact_dirs + ): + workflow_url = None + else: + workflow_url, resolved_head_sha = resolve_workflow_url( + args.release_version, args.workflow_url + ) + print(f"Using native artifacts from {workflow_url}", flush=True) + print(f"Using artifact cache at {artifacts_temp_root}", flush=True) for components in native_component_sets: vendor_temp_root = Path(