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
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Protect GitHub configuration that can affect CI and publishing.
/.github/CODEOWNERS @b2m9
/.github/workflows/** @b2m9
85 changes: 85 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Publish

on:
release:
types: [published]

permissions:
contents: read

concurrency:
group: publish-${{ github.event.release.tag_name }}
cancel-in-progress: false

jobs:
validate:
name: Validate release tag
runs-on: ubuntu-latest
permissions:
contents: read

env:
RELEASE_TAG: ${{ github.event.release.tag_name }}

steps:
- name: Checkout release tag
uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
with:
ref: ${{ github.event.release.tag_name }}

- name: Verify release tag matches package version
run: |
PACKAGE_VERSION="$(node -p "require('./package.json').version")"
EXPECTED_TAG="v${PACKAGE_VERSION}"

if [[ "${PACKAGE_VERSION}" == *-* ]]; then
echo "::error::Prerelease version ${PACKAGE_VERSION} requires an explicit npm dist-tag"
exit 1
fi

if [ "${RELEASE_TAG}" != "${EXPECTED_TAG}" ]; then
echo "::error::Release tag ${RELEASE_TAG} must match package.json version ${PACKAGE_VERSION} as ${EXPECTED_TAG}"
exit 1
fi

stage:
name: Stage package on npm
runs-on: ubuntu-latest
needs: validate
permissions:
contents: read
id-token: write
environment: npm-publish

steps:
- name: Checkout release tag
uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
with:
ref: ${{ github.event.release.tag_name }}

- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
registry-url: https://registry.npmjs.org
package-manager-cache: false

- name: Install dependencies
run: npm ci

- name: Check package
run: npm run check

- name: Install npm with staged publishing support
run: npm install --global npm@11.15.0

- name: Assert npm staged publishing support
run: |
npm --version
npm stage --help

- name: Dry-run npm package contents
run: npm pack --dry-run

- name: Stage package on npm
run: npm stage publish --ignore-scripts
38 changes: 38 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Releasing

This package uses npm trusted publishing with GitHub Actions. The workflow stages
Comment thread
b2m9 marked this conversation as resolved.
new versions on npm, but does not make them live. A maintainer must review and
approve the staged package on npm with 2FA.

## Release checklist

1. Make sure `main` is green and contains the release commit.
2. Bump `package.json` and `package-lock.json` to the next version.
3. Run:

```sh
npm ci
npm run check
npm pack --dry-run
```

4. Commit the version bump.
5. Create and push a matching tag, for example `v0.2.0`.
6. Publish a GitHub Release for that tag.
7. Wait for the `Publish` workflow to stage the package on npm.
8. Review the staged package on npm.
9. Approve the staged package with npm 2FA.

## Reviewing a staged package

Use npmjs.com, or inspect it from the CLI:

```sh
npm stage list @b2m9/keyfold
npm stage view <stage-id>
npm stage download <stage-id>
npm stage approve <stage-id>
```

The workflow requires the GitHub Release tag to match the package version exactly:
`package.json` version `0.2.0` must be released from tag `v0.2.0`.