From a28f5baf29660bd5fb2533ff70ee85bb644c6b24 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 14:45:37 -0800 Subject: [PATCH 1/3] ci: convert script back to plain node --- .ado/azure-pipelines.publish.yml | 2 +- .github/scripts/publish-package-if-needed.mts | 59 ++++++++++--------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/.ado/azure-pipelines.publish.yml b/.ado/azure-pipelines.publish.yml index 16349839e4..22528c262b 100644 --- a/.ado/azure-pipelines.publish.yml +++ b/.ado/azure-pipelines.publish.yml @@ -84,7 +84,7 @@ extends: # https://github.com/changesets/changesets/issues/432 # We can't use `changeset publish` because it doesn't support workspaces, so we have to publish each package individually yarn workspaces foreach --all --topological --no-private \ - exec zx $(Build.SourcesDirectory)/.github/scripts/publish-package-if-needed.mts + exec node $(Build.SourcesDirectory)/.github/scripts/publish-package-if-needed.mts displayName: 'Publish NPM Packages' condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'), not(${{ parameters.skipNpmPublish }})) diff --git a/.github/scripts/publish-package-if-needed.mts b/.github/scripts/publish-package-if-needed.mts index 3f39f882e7..7086df2ce5 100644 --- a/.github/scripts/publish-package-if-needed.mts +++ b/.github/scripts/publish-package-if-needed.mts @@ -1,63 +1,64 @@ -#!/usr/bin/env zx -import 'zx/globals'; +#!/usr/bin/env node +import { readFileSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; -// Type declaration for process (zx doesn't include Node.js types) -declare const process: { - env: Record; - cwd: () => string; - argv: string[]; - exit: (code: number) => never; -}; +interface PackageJson { + name: string; + version: string; + private?: boolean; +} /** * Publish a single package to npm if needed * * This script: * - Operates on the current workspace directory - * - Checks npm registry before publishing + * - Checks npm registry before publishing (idempotent - safe to retry) + * - Requires yarn npm authentication to be configured (npmAuthToken) * - Skips private packages automatically * * Usage: * # In a workspace directory: - * npx zx publish-package-if-needed.mts # Publish for real - * npx zx publish-package-if-needed.mts --dry-run # Simulate publishing + * node publish-package-if-needed.mts # Publish for real + * node publish-package-if-needed.mts --dry-run # Simulate publishing * * # For all workspaces in topological order: * yarn workspaces foreach --all --topological --no-private \ - * exec npx zx .github/scripts/publish-package-if-needed.mts + * exec node .github/scripts/publish-package-if-needed.mts */ -// Parse command line arguments const isDryRun = process.argv.includes('--dry-run'); -// Read package.json from current directory -const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf-8')); +const packageJson: PackageJson = JSON.parse(readFileSync('package.json', 'utf-8')); const { name, version, private: isPrivate } = packageJson; -// Skip private packages if (isPrivate) { - echo(`⊘ Skipping private package: ${name}`); + console.log(`⊘ Skipping private package: ${name}`); process.exit(0); } // Check if package@version already exists on npm -const result = await $`npm view ${name}@${version} version 2>&1`.nothrow().quiet(); -const shouldPublish = result.exitCode !== 0 || result.stdout.trim() !== version; +const checkResult = spawnSync('npm', ['view', `${name}@${version}`, 'version'], { + encoding: 'utf-8', + stdio: 'pipe', +}); +const alreadyPublished = checkResult.status === 0 && checkResult.stdout.trim() === version; -if (!shouldPublish) { - echo(`✓ Already published: ${name}@${version}`); +if (alreadyPublished) { + console.log(`✓ Already published: ${name}@${version}`); process.exit(0); } -// Publish the package const startMsg = isDryRun ? 'Simulating publish' : 'Publishing'; const endMsg = isDryRun ? 'Dry-run successful for' : 'Successfully published'; -echo(`→ ${startMsg}: ${name}@${version}`); +console.log(`→ ${startMsg}: ${name}@${version}`); -const publishCmd = isDryRun - ? $`yarn npm publish --access public --dry-run` - : $`yarn npm publish --access public`; +const publishArgs = ['npm', 'publish', '--access', 'public']; +if (isDryRun) publishArgs.push('--dry-run'); -await publishCmd; -echo(`✓ ${endMsg}: ${name}@${version}`); +const publishResult = spawnSync('yarn', publishArgs, { stdio: 'inherit' }); +if (publishResult.status !== 0) { + process.exit(publishResult.status ?? 1); +} +console.log(`✓ ${endMsg}: ${name}@${version}`); From 5c9ab16d9aa3932f930c398cce725b33e452b5f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 14:51:55 -0800 Subject: [PATCH 2/3] dry run job --- .github/workflows/pr.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 519aaaeec5..778ebdedee 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -305,6 +305,30 @@ jobs: - name: Validate changesets run: yarn changeset:validate + publish-dry-run: + name: NPM Publish Dry Run + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up toolchain + uses: microsoft/react-native-test-app/.github/actions/setup-toolchain@5.0.14 + with: + node-version: 22 + + - name: Install dependencies + run: yarn + + - name: Build packages + run: yarn build + + - name: Simulate publish + run: | + yarn workspaces foreach --all --topological --no-private \ + exec node $(pwd)/.github/scripts/publish-package-if-needed.mts --dry-run + test-links: name: Test repo links runs-on: ubuntu-latest @@ -336,6 +360,7 @@ jobs: - windows - win32 - check-changesets + - publish-dry-run - test-links steps: - name: All required jobs passed From 6a3c59c3c3f031b0ff932beb6d5671a9e26d8d3b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 17:07:24 -0800 Subject: [PATCH 3/3] fix yaml keys --- .github/workflows/changesets-version.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/changesets-version.yml b/.github/workflows/changesets-version.yml index 671380dbcb..7cd7b37e1f 100644 --- a/.github/workflows/changesets-version.yml +++ b/.github/workflows/changesets-version.yml @@ -32,9 +32,8 @@ jobs: with: app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - permissions: | - contents: write - pull-requests: write + permission-contents: write # for GH releases and Git tags (Changesets) + permission-pull-requests: write # version PRs (Changesets) - name: Create Version Bump PR id: changesets