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
This commit is contained in:
Charlie Marsh
2026-09-06 20:57:56 +00:00
committed by copyberry
parent d30f9cc72a
commit 8283bc56b1
2 changed files with 101 additions and 41 deletions
+59 -27
View File
@@ -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: |
+42 -14
View File
@@ -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(