Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 6 additions & 18 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ concurrency:
# The whole permission surface: push the release branch, publish, tag.
permissions:
contents: write
# npm trusted publishing: the job asks GitHub for an OIDC token, and pnpm
# exchanges it for a short npm token that can publish `@human-kit/ui` only.
# There is no npm secret.
id-token: write

jobs:
release:
Expand Down Expand Up @@ -96,31 +100,15 @@ jobs:
echo "Merging it publishes to npm."
} >> "$GITHUB_STEP_SUMMARY"

# `changeset publish` authenticates through an `.npmrc`, and nothing else
# here writes one: the repo ships none, and `actions/setup-node` only
# generates one when given `registry-url`. `changesets/action` used to do
# this itself, which is why it was invisible until that action was dropped —
# an unauthenticated publish comes back as `E404 undefined`, because npm
# masks "you may not publish here" as "no such package".
#
# Written to $HOME rather than the workspace so it cannot be committed by a
# later step, and only on the branch that actually publishes.
- name: Authenticate with npm
if: steps.version.outputs.versioned == 'false'
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > "$HOME/.npmrc"

# Only when there was nothing left to version — that is, the release branch
# has been merged. `changeset publish` skips versions already on npm, so a
# rerun is a no-op, and it recovers a release whose version commit landed
# but whose publish did not.
# but whose publish did not. No `.npmrc` carries a token, so a failed OIDC
# exchange stops the publish instead of falling back to a stale credential.
- name: Publish
if: steps.version.outputs.versioned == 'false'
run: pnpm run release
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# `changeset publish` creates the `@human-kit/ui@<version>` tags locally and
Expand Down
5 changes: 5 additions & 0 deletions scripts/publish.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ execSync('pnpm exec changeset publish', { stdio: 'inherit' });
//
// `changeset publish` REJECTS an explicit `--tag` in pre mode, so the tag is moved
// afterwards. It is idempotent, and a no-op once the version already carries it.
//
// The Release workflow has no npm token: it publishes through trusted publishing,
// which authorizes the publish and nothing else by default. Before the next
// prerelease, give this step a credential (for example, allow `npm dist-tag` on the
// trusted publisher at npmjs.com), or it fails.
if (pre) {
const pkg = JSON.parse(readFileSync(packageUrl, 'utf8'));
console.log(`Pointing the "${pre.tag}" dist-tag at ${pkg.version}.`);
Expand Down
Loading