Skip to content

[release] harden release script: yarn, public access, resilient publish, pin Node#1712

Merged
mellyeliu merged 3 commits into
mainfrom
fix-release-script-yarn
Jun 16, 2026
Merged

[release] harden release script: yarn, public access, resilient publish, pin Node#1712
mellyeliu merged 3 commits into
mainfrom
fix-release-script-yarn

Conversation

@mellyeliu

@mellyeliu mellyeliu commented Jun 15, 2026

Copy link
Copy Markdown
Member

Hardens the release script (tools/npm/release.js) and pins the Node version. All fixes surfaced while cutting 0.19.0.

Fixes

  1. Install with yarn, not npm. The script ran npm install, which regenerates a package-lock.json (and needs .npmrc legacy-peer-deps) even though the repo uses yarn (yarn install --frozen-lockfile in CI). git add . then committed those npm artifacts — that's how the ~35k-line package-lock.json + .npmrc ended up in the 0.19.0 release commit.

  2. Scope the staging. Stage only the workspace manifests + yarn.lock instead of git add ., so a release can never commit stray/unrelated files again.

  3. Publish with --access public. New scoped packages (@stylexjs/*) default to restricted access and fail on first publish with 402 Payment Required. All stylex packages are public; no-op for already-public ones. (Hit this on @stylexjs/atoms, the new package in 0.19.0.)

  4. Resilient publish loop. Each publish is wrapped in try/catch, so a single failure — e.g. a package the publisher lacks rights for, like the unscoped create-stylex-app (403) — logs and is skipped instead of aborting the release halfway. Failures are collected and the script sets process.exitCode = 1 at the end, so a release that skipped packages isn't reported as success (uses exitCode, not exit, so every package is still attempted first).

  5. No shell-built commands (CodeQL). All variable-interpolating execSync calls are replaced with execFileSync arg arrays (no shell): publish runs via cwd: directory instead of cd <dir> && ..., and npm/git args are passed as arrays. Resolves the "shell command built from environment values" alert. Only the static yarn install remains execSync.

  6. Declare glob. The script requires glob but it was only resolving via hoisting (Cannot find module 'glob' on a clean checkout). Added to root devDependencies.

  7. .nvmrc pinned to Node 22 (matches CI setup-node: 22.x). Node 26 breaks the gen-types/yargs build toolchain (require is not defined in ES module scope), cascading into every dependent package's build.

Verification

  • Ran the patched script on main for 0.19.0: resulting manifests are byte-for-byte identical to the release/0.19.0 branch, with no package-lock.json/.npmrc produced.
  • node --check passes; fixes 3 & 4 validated live during the 0.19.0 publish.

The release script ran `npm install`, which generated a stray
`package-lock.json` (and required `.npmrc` legacy-peer-deps) even though
the repo uses yarn — CI installs with `yarn install --frozen-lockfile`.
`git add .` then committed those npm artifacts.

- Install with `yarn install` instead of `npm install`.
- Stage only the workspace manifests + `yarn.lock` instead of `git add .`,
  so stray/unrelated files can never be committed by a release again.

Verified: running this on main for 0.19.0 produces package manifests
identical to the release/0.19.0 branch, with no package-lock.json/.npmrc.
@mellyeliu mellyeliu requested a review from nmn as a code owner June 15, 2026 23:32
Copilot AI review requested due to automatic review settings June 15, 2026 23:32
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 15, 2026
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stylex Ready Ready Preview, Comment Jun 16, 2026 6:29am

Request Review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the monorepo release script to use Yarn (the repo’s configured package manager) and to stage only expected release artifacts, preventing stray files like package-lock.json from being accidentally committed in release commits.

Changes:

  • Switch dependency installation in the release script from npm install to yarn install.
  • Replace git add . with explicit staging of workspace package.json files plus yarn.lock.

Comment thread tools/npm/release.js
Comment on lines +120 to +125
const manifestPaths = workspaces.map(({ packageJsonPath }) =>
path.relative(repoRoot, packageJsonPath),
);
execSync(`git add ${manifestPaths.map((p) => `"${p}"`).join(' ')} yarn.lock`, {
stdio: 'inherit',
});
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

workflow: benchmarks/perf

Comparison of performance test results, measured in operations per second. Larger is better.
yarn workspace v1.22.22
yarn run v1.22.22
$ node ./compare.js /tmp/tmp.OR1mFGk9lK /tmp/tmp.TSmMXlZDli

Results Base Patch Ratio
babel-plugin: stylex.create
· basic create 589 589 1.00
· complex create 67 66 0.99 -
babel-plugin: stylex.createTheme
· basic themes 466 464 1.00 -
· complex themes 33 33 1.00
Done in 0.09s.
Done in 0.33s.

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

workflow: benchmarks/size

Comparison of minified (terser) and compressed (brotli) size results, measured in bytes. Smaller is better.
yarn workspace v1.22.22
yarn run v1.22.22
$ node ./compare.js /tmp/tmp.4tnzSzc7yF /tmp/tmp.Llfermf1wh

Results Base Patch Ratio
@stylexjs/stylex/lib/cjs/stylex.js
· compressed 1,535 1,535 1.00
· minified 5,166 5,166 1.00
@stylexjs/stylex/lib/cjs/inject.js
· compressed 1,793 1,793 1.00
· minified 4,915 4,915 1.00
benchmarks/size/.build/bundle.js
· compressed 496,650 496,650 1.00
· minified 4,847,840 4,847,840 1.00
benchmarks/size/.build/stylex.css
· compressed 99,757 99,757 1.00
· minified 748,850 748,850 1.00
Done in 0.08s.
Done in 0.32s.

Follow-on fixes to the release script surfaced while cutting 0.19.0:

- Publish with `npm publish --access public`. New scoped packages
  (@stylexjs/*) default to restricted access and fail with E402 on first
  publish; all stylex packages are public. No-op for already-public ones.
- Wrap each `npm publish` in try/catch so one failure (e.g. a package the
  user lacks publish rights for, like the unscoped `create-stylex-app`)
  logs and is skipped instead of aborting the whole release halfway.
- Add `.nvmrc` pinned to Node 22 (matches CI `setup-node` 22.x). Node 26
  breaks the `gen-types`/yargs build toolchain.
@mellyeliu mellyeliu changed the title [release] use yarn in release script and scope git add [release] harden release script: yarn, public access, resilient publish, pin Node Jun 16, 2026
Comment thread tools/npm/release.js Fixed
Address review + CodeQL feedback on the release script:

- Track publish failures and set `process.exitCode = 1` at the end, so a
  release that skipped packages isn't reported as successful. Uses exitCode
  (not exit) so every package is still attempted first.
- Replace all shell-interpolated `execSync` calls with `execFileSync` arg
  arrays (no shell). Fixes CodeQL "shell command built from environment
  values" — publish now runs via `cwd: directory` instead of `cd <dir> &&`,
  and npm/git args are passed as arrays. Only the static `yarn install`
  remains an execSync.
- Declare `glob` in root devDependencies; the script requires it but it was
  only resolving via hoisting (caused "Cannot find module 'glob'").
@mellyeliu mellyeliu merged commit ad13903 into main Jun 16, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants