Skip to content

fix(ci): build the example before the private-registry publish step - #5

Merged
murrayju merged 1 commit into
mainfrom
murrayju/fix-publish-example-registry
Aug 4, 2026
Merged

fix(ci): build the example before the private-registry publish step#5
murrayju merged 1 commit into
mainfrom
murrayju/fix-publish-example-registry

Conversation

@murrayju

@murrayju murrayju commented Aug 4, 2026

Copy link
Copy Markdown
Member

Problem

The install example dependencies step still fails in the publish workflow, now with a different error than the registry mismatch:

error Error: Failed to replace env in config: ${NODE_AUTH_TOKEN}
    at envReplace (/usr/local/lib/node_modules/yarn/lib/cli.js:95448:16)
    at NpmRegistry.normalizeConfig (...)

The registry reset added previously was the right idea but can't work, and the setup-node@v7 bump is what exposed it.

setup-node writes an .npmrc — and exports NPM_CONFIG_USERCONFIG pointing at it — only when given registry-url, and it never unsets that for subsequent steps. The .npmrc it writes always contains a literal, unexpanded placeholder:

//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}

Through v4, the action also exported a dummy NODE_AUTH_TOKEN=XXXXX-XXXXX-XXXXX-XXXXX when the user supplied none, so that placeholder always resolved. actions/setup-node#1558 (in v7) removed the dummy fallback and now only exports the variable when explicitly set.

The asymmetry that makes this bite: npm tolerates the unresolved placeholder, but yarn v1 hard-errors on it. Confirmed against yarn's envReplace, which throws outright when the referenced variable is undefined.

So the "reset the registry to public" approach was a dead end — any registry-url step leaves behind an .npmrc that breaks a later bare yarn, regardless of which registry it points at.

Fix

Move the example install and build before both publish steps, so they run on the default public registry with no .npmrc involved at all. No registry juggling needed.

This has a second benefit worth calling out: publishing is irreversible (npm won't let you reuse a version), so validating the example first means a broken example stops the release instead of leaving a published package with no matching Pages deploy. The previous ordering published to two registries and then discovered the example was broken — which is what happened on the last three release attempts.

Also switched both installs to --frozen-lockfile, so a release can't silently resolve dependencies that differ from the committed lockfiles.

Resulting step order

 4  yarn install --frozen-lockfile      (root)
 5  yarn build                          (root)
 6  yarn version
 7  Determine npm dist-tag
 8  install example dependencies        <- moved up, no .npmrc
 9  build example site                  <- moved up
10  Publish to npm (trusted publishing)
11  actions/setup-node  [registry-url]  <- only step that writes .npmrc, now last
12  Publish to private registry
13  Deploy

Verification

  • Reproduced the exact failure locally: with an .npmrc containing the placeholder and NODE_AUTH_TOKEN unset, yarn install fails with the identical error; with the variable set (the old v4 behavior) it succeeds — confirming the v7 change as the trigger.
  • Simulated the full new step sequence from a clean clone: root install (frozen), root build, version bump, example install (frozen, no .npmrc), example build → Compiled successfully., and example/build/index.html exists for the Deploy step.
  • Confirmed the version bump doesn't invalidate the example's --frozen-lockfile check, since the file:../ entry is recorded without a version.
  • Verified via the parsed YAML that step 11 is the only step setting registry-url, and that nothing running yarn follows it.

The example install failed with:

  error Error: Failed to replace env in config: ${NODE_AUTH_TOKEN}

`setup-node` writes an .npmrc, and exports NPM_CONFIG_USERCONFIG pointing at
it, only when given `registry-url` — and it never unsets that for later steps.
That .npmrc always contains a literal `_authToken=${NODE_AUTH_TOKEN}`. Up
through v4 the action also exported a dummy token when none was supplied, so
the placeholder always resolved; v7 removed that fallback
(actions/setup-node#1558). npm tolerates the unresolved placeholder but yarn v1
hard-errors on it, so the reset-to-public-registry step could not work: any
`registry-url` step leaves an .npmrc that breaks a later bare `yarn`.

Order the example install and build before both publish steps instead, so they
run with no .npmrc at all on the default public registry. This also makes the
release fail fast: publishing is irreversible, so a broken example should stop
the release rather than leave a published package with no matching Pages
deploy.

Also use `--frozen-lockfile` for both installs so a release can't silently
resolve dependencies that differ from the committed lockfiles.
@murrayju
murrayju merged commit 9bcdfb3 into main Aug 4, 2026
2 checks passed
@murrayju
murrayju deleted the murrayju/fix-publish-example-registry branch August 4, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant