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
16 changes: 14 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Publishes `canup` to npm via Changesets + npm Trusted Publishing (OIDC).
#
# No npm token is used. Authentication happens through GitHub's OIDC token, which
# npm exchanges for a short-lived publish credential (requires `id-token: write`
# and a trusted publisher configured for this package on npmjs.com — see
# RELEASING.md). Provenance is generated automatically because this is a public
# repository.
name: Release
on:
push:
Expand All @@ -17,7 +24,12 @@ jobs:
with:
node-version: 22
cache: pnpm
registry-url: 'https://registry.npmjs.org'
# No `registry-url`: it writes an .npmrc with `_authToken=${NODE_AUTH_TOKEN}`
# that npm prefers over the OIDC token exchange, breaking trusted publishing.
# Runners bundle an older npm; trusted publishing needs npm >= 11.5.1, and
# pnpm delegates the publish + OIDC exchange to the npm CLI.
- name: Use npm >= 11.5.1
run: npm install -g npm@latest
- run: pnpm install --frozen-lockfile
- run: pnpm run build
- run: pnpm run test
Expand All @@ -27,4 +39,4 @@ jobs:
version: pnpm changeset version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true
62 changes: 62 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Releasing

Releases are automated with [Changesets](https://github.com/changesets/changesets)
and [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers) (OIDC).
**No npm token is involved** — GitHub Actions authenticates to npm via a
short-lived OIDC credential, and packages are published with
[provenance](https://docs.npmjs.com/generating-provenance-statements).

## For contributors

If your change affects published behavior, add a changeset in the same PR:

```sh
pnpm changeset
```

Pick the bump type (patch / minor / major) and write a short, user-facing
summary. CI reminds you if a PR is missing one.

That's it — you don't publish anything. Maintainers merge the automated release
PR (below) when it's time to ship.

## How a release happens

1. PRs merge to `main`, each carrying a changeset.
2. The release workflow opens (and keeps updating) a **"Version Packages"** PR
that bumps the version and updates `CHANGELOG.md`.
3. Merging that PR publishes the new version to npm — with provenance, no token.

## Maintainer setup (one-time)

npm Trusted Publishing requires the package to exist before a trusted publisher
can be attached, so the very first release is published manually; every release
after that is automated.

1. **First publish (once, requires npm 2FA):**

```sh
pnpm install --frozen-lockfile
pnpm run build
npm publish --access public
```

2. **Configure the trusted publisher** at
<https://www.npmjs.com/package/canup/access> → **Trusted Publisher** →
**GitHub Actions**:

| Field | Value |
|-------|-------|
| Organization or user | `sparkncraft` |
| Repository | `canup` |
| Workflow filename | `release.yml` *(filename only, not a path)* |
| Environment | *(leave blank)* |

After this, no token is needed and the `release.yml` workflow publishes on its
own. Any previously configured `NPM_TOKEN` secret can be deleted.

## Requirements (handled by the workflow)

- npm **≥ 11.5.1** and Node **≥ 22.14.0** — the workflow installs `npm@latest`
because runners ship an older npm and pnpm delegates the publish to the npm CLI.
- `id-token: write` permission on the release job.
Loading