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
4 changes: 4 additions & 0 deletions .github/workflows/release-dry-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ jobs:
node-version: 22
cache: npm
registry-url: https://registry.npmjs.org
- name: Prepare trusted publishing npm
run: |
npm install --global npm@11.5.1
npm --version
- name: Install dependencies
run: npm ci
- name: Install ReleaseBox
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ jobs:
node-version: 22
cache: npm
registry-url: https://registry.npmjs.org
- name: Prepare trusted publishing npm
run: |
npm install --global npm@11.5.1
npm --version
- name: Install dependencies
run: npm ci
- name: Install ReleaseBox
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ format and uses semantic versioning when versioned releases are published.

## [Unreleased]

- Pinned npm 11.5.1 preparation in release and dry-run workflows, with regression checks and release-readiness guidance for trusted publishing.

### Fixed

- Join shell continuations and recognize leading environment assignments when
Expand Down
4 changes: 2 additions & 2 deletions docs/release-readiness.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ Run `npm run package:smoke` when available and review the dry-run file list for

## Automated publication

The release workflow uses npm trusted publishing (GitHub Actions OIDC) and requires the npm package to trust this repository's `release.yml` workflow. A version tag packs the package once, publishes that exact tarball to npm with public access and provenance, and attaches the same file to the GitHub release.
The release workflow uses npm trusted publishing (GitHub Actions OIDC) and requires the npm package to trust this repository's `release.yml` workflow. Both release workflows install and print npm `11.5.1` before installing dependencies; trusted publishing requires npm `11.5.1` or later. A version tag packs the package once, publishes that exact tarball to npm with public access and provenance, and attaches the same file to the GitHub release.

The release dry-run workflow exercises the same artifact handoff on relevant pull requests: it packs once and runs `npm publish <tarball> --dry-run --access public`. `npm run release:workflow-check` guards both workflows against repacking or failing to reuse the artifact.
The release dry-run workflow exercises the same npm preparation and artifact handoff on relevant pull requests: it packs once and runs `npm publish <tarball> --dry-run --access public`. `npm run release:workflow-check` guards both workflows against omitting or downgrading the pinned trusted-publishing npm version, repacking, or failing to reuse the artifact.

## Notes

Expand Down
28 changes: 27 additions & 1 deletion scripts/check-release-workflows.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,28 @@ import { readFile } from "node:fs/promises";

const release = await readFile(".github/workflows/release.yml", "utf8");
const dryRun = await readFile(".github/workflows/release-dry-run.yml", "utf8");
const trustedPublishingNpmVersion = "11.5.1";

function assertTrustedPublishingNpm(workflow, name) {
const prepareIndex = workflow.indexOf("- name: Prepare trusted publishing npm");
const installIndex = workflow.indexOf("- name: Install dependencies");

assert.notEqual(prepareIndex, -1, `${name} must prepare npm for trusted publishing`);
assert.ok(
prepareIndex < installIndex,
`${name} must prepare trusted publishing npm before dependency installation`,
);
assert.match(
workflow,
new RegExp(`npm install --global npm@${trustedPublishingNpmVersion.replaceAll(".", "\\.")}`),
`${name} must pin npm ${trustedPublishingNpmVersion}`,
);
assert.match(
workflow.slice(prepareIndex, installIndex),
/npm --version/,
`${name} must print the effective npm version`,
);
}

function assertSinglePack(workflow, name) {
assert.equal(
Expand All @@ -17,6 +39,8 @@ function assertSinglePack(workflow, name) {

assertSinglePack(release, "release workflow");
assertSinglePack(dryRun, "release dry-run workflow");
assertTrustedPublishingNpm(release, "release workflow");
assertTrustedPublishingNpm(dryRun, "release dry-run workflow");

assert.match(
release,
Expand All @@ -34,4 +58,6 @@ assert.match(
"dry run must publish the packed artifact without repacking",
);

console.log("release workflows pack once and reuse the package artifact");
console.log(
`release workflows prepare npm ${trustedPublishingNpmVersion}, pack once, and reuse the package artifact`,
);