diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2141b0b..b835b15 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,5 +34,6 @@ jobs: commit-message: 'chore: version packages' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # Empty on purpose: npm authenticates through trusted publishing (OIDC), no token is stored. + NODE_AUTH_TOKEN: '' NPM_CONFIG_PROVENANCE: 'true' diff --git a/RELEASING.md b/RELEASING.md index d25c565..901eee0 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,18 +1,29 @@ # Releasing -Releases are cut by the `Release` workflow (`.github/workflows/release.yml`) with changesets. +Releases are cut by the `Release` workflow (`.github/workflows/release.yml`) with changesets. It publishes to npm through **trusted publishing** (GitHub OIDC): no npm token is stored anywhere, and every version carries provenance. -## One-time setup +## Setup (already done, for reference) -1. Give the repo an npm credential that can publish to the `@cospired` scope, either: - - a repo secret `NPM_TOKEN` (npm automation token), or - - npm trusted publishing: on npmjs.com add this repo and the `release.yml` workflow as a trusted publisher for both packages (then no token is needed). -2. Allow GitHub Actions to create pull requests (Settings, Actions, General, Workflow permissions). +- Each of the four packages has a trusted publisher on npmjs.com (package Settings, Trusted Publisher): GitHub Actions, organization `cospired`, repository `javascript`, workflow `release.yml`, no environment, permission to publish. +- **Staged publishing is on:** a version published by CI is not live until a maintainer approves it on npmjs.com (login and 2FA). +- GitHub Actions may create pull requests (Settings, Actions, General, Workflow permissions). + +A trusted publisher can only be added to a package that already exists. A **new package** therefore needs one manual first publish from a maintainer's machine, then the trusted publisher: + +```sh +cd packages/ +npm pkg delete publishConfig.provenance # a local publish cannot generate provenance +npm publish --access public +git checkout package.json +``` ## Each release -1. Describe the change with `npx changeset` (CI's "publish dry run" job applies pending changesets and dry-runs the publish on every push). -2. Merge to `main`. The workflow opens a "chore: version packages" PR that bumps versions and changelogs. -3. Merge that PR. The workflow publishes to npm with provenance and tags the release. +1. Describe the change with `npx changeset`. The migration notes of a major release belong in the changeset text, because they end up in each package's changelog. +2. Merge to `main`. The workflow opens a "chore: version packages" PR with the new versions and changelogs. +3. Merge that PR. The workflow publishes (stages) every package whose version is not on npm yet, then pushes the git tags and creates the GitHub releases. +4. **Approve the staged versions on npmjs.com**, one per package. Until you do, a further push to `main` may try to stage the same version again, so approve promptly. + +## Checks -`npm run smoke` packs both packages and lints a clean project with every entry; CI runs it too. +CI (`.github/workflows/ci.yml`) runs the tests and the self-lint on Node 22.13, 24, 26 and the latest release, the tests again with every peer dependency at its minimum version, a smoke test that installs the packed tarballs into a clean project, and a publish dry run with the pending changesets applied. `npm run smoke` runs the smoke test locally. diff --git a/package-lock.json b/package-lock.json index 58bb1c0..77e25dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -718,6 +718,12 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/nonrecursive-glob-match": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@isaacs/nonrecursive-glob-match/-/nonrecursive-glob-match-1.1.0.tgz", + "integrity": "sha512-GPm/Dbvk5RLmhRnxXIa7nTpK0xtl4E0wj0MslsuNiJ1FIROU+2+9lgUC/dgF7Ey4QCWhfEsgxilMRMCdHPfDfw==", + "license": "BlueOak-1.0.0" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "license": "MIT", @@ -2440,13 +2446,16 @@ } }, "node_modules/minimatch": { - "version": "10.2.6", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-11.0.7.tgz", + "integrity": "sha512-Tnk+M9mPjqKDZlUd77eMSjPjhnlBIa1mABOwetMryIshUwi1YmOBdGFfQnHgn4Z8A66eLT8ENzJrxwYmKfqrZg==", "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.8" + "@isaacs/nonrecursive-glob-match": "^1.1.0", + "brace-expansion": "^5.0.12" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" diff --git a/package.json b/package.json index c72b6b2..16f4b19 100644 --- a/package.json +++ b/package.json @@ -60,5 +60,8 @@ "prettier": "^3.9.10", "typescript": "~6.0.3", "typescript-eslint": "^8.72.2" + }, + "overrides": { + "minimatch": "^11.0.1" } }