Skip to content

Publish to NPM

Publish to NPM #52

Workflow file for this run

name: Publish to NPM
# Manual, on-demand publishing (mirrors the DxMessaging release route): dispatch this workflow
# to publish the current package.json version. The publish step is re-runnable (it skips a
# version already on the registry) and attaches build provenance.
on:
workflow_dispatch:
inputs:
dry_run:
description: "Pack and report the version/dist-tag without publishing"
type: boolean
default: false
concurrency:
group: publish-npm
cancel-in-progress: false
permissions:
contents: read
jobs:
publish:
name: Publish npm package
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
id-token: write # required for `npm publish --provenance`
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
registry-url: "https://registry.npmjs.org"
- name: Pack and resolve version / dist-tag
id: pack
run: |
set -euo pipefail
pkg="$(jq -r '.name' package.json)"
ver="$(jq -r '.version' package.json)"
if [ -z "${pkg}" ] || [ "${pkg}" = "null" ] || [ -z "${ver}" ] || [ "${ver}" = "null" ]; then
echo "::error::package.json is missing name or version."
exit 1
fi
# rc/alpha/beta/preview pre-releases publish under the "next" dist-tag; stable under "latest".
if printf '%s' "${ver}" | grep -qiE '\-(rc|alpha|beta|preview)'; then
npm_tag="next"
else
npm_tag="latest"
fi
package_file="$(npm pack --json | jq -r '.[0].filename')"
{
echo "pkg=${pkg}"
echo "ver=${ver}"
echo "npm_tag=${npm_tag}"
echo "package_file=${package_file}"
} >> "${GITHUB_OUTPUT}"
echo "Prepared ${pkg}@${ver} -> dist-tag '${npm_tag}' (${package_file})."
- name: Publish to npm with provenance
if: ${{ inputs.dry_run == false }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
PKG: ${{ steps.pack.outputs.pkg }}
VER: ${{ steps.pack.outputs.ver }}
NPM_TAG: ${{ steps.pack.outputs.npm_tag }}
PACKAGE_FILE: ${{ steps.pack.outputs.package_file }}
run: |
set -euo pipefail
# Re-runnable: skip if this exact name@version is already on the registry (a prior run may
# have published it before failing downstream). npm publish is otherwise irreversible.
if npm view "${PKG}@${VER}" version >/dev/null 2>&1; then
echo "::notice::${PKG}@${VER} is already on the registry; skipping publish."
else
npm publish "${PACKAGE_FILE}" --provenance --access public --tag "${NPM_TAG}"
echo "::notice::Published ${PKG}@${VER} to dist-tag '${NPM_TAG}'."
fi
- name: Dry-run summary
if: ${{ inputs.dry_run == true }}
run: |
echo "Dry run: would publish ${{ steps.pack.outputs.pkg }}@${{ steps.pack.outputs.ver }} to dist-tag '${{ steps.pack.outputs.npm_tag }}'."