Skip to content

Publish to npm

Publish to npm #3

Workflow file for this run

name: Publish to npm
concurrency:
group: publish-${{ github.ref }}
cancel-in-progress: true
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
version:
description: 'Version to publish (leave empty to use package.json version)'
required: false
type: string
tag:
description: 'npm tag (latest, beta, next)'
required: false
default: 'latest'
type: choice
options:
- latest
- beta
- next
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Enable Corepack (Yarn 3)
run: |
corepack enable
corepack prepare yarn@3.6.1 --activate
- name: Install dependencies
run: yarn install --immutable
- name: Run tests
run: yarn test
- name: Lint
run: yarn lint
- name: Typecheck
run: yarn typecheck
- name: Build package
run: yarn build
- name: Verify tag matches package.json version
if: ${{ github.event_name == 'push' }}
run: |
PKG_VERSION=$(node -p "require('./package.json').version")
if [ "v${PKG_VERSION}" != "${GITHUB_REF_NAME}" ]; then
echo "Tag ${GITHUB_REF_NAME} does not match package.json version v${PKG_VERSION}"
exit 1
fi
- name: Set version
if: ${{ github.event_name == 'workflow_dispatch' && inputs.version != '' }}
env:
INPUT_VERSION: ${{ inputs.version }}
run: npm version "$INPUT_VERSION" --no-git-tag-version
- name: Check if version already exists on npm
id: check_version
run: |
PKG_VERSION=$(node -p "require('./package.json').version")
if npm view "$(node -p "require('./package.json').name")@${PKG_VERSION}" version >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "Version ${PKG_VERSION} already exists on npm, skipping publish"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "Version ${PKG_VERSION} does not exist on npm, will publish"
fi
- name: Publish to npm
if: steps.check_version.outputs.exists == 'false'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_DIST_TAG: ${{ inputs.tag }}
run: |
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
TAG="${NPM_DIST_TAG:-latest}"
npm publish --provenance --tag "$TAG"
else
npm publish --provenance
fi
- name: Determine release metadata
if: ${{ github.event_name != 'release' }}
id: meta
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
TAG=""
PRERELEASE="false"
if [ "${GITHUB_EVENT_NAME}" = "push" ]; then
TAG="${GITHUB_REF_NAME}"
elif [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
if [ -n "${INPUT_VERSION:-}" ]; then
TAG="v${INPUT_VERSION}"
else
PKG_VERSION="$(node -p "require('./package.json').version")"
TAG="v${PKG_VERSION}"
fi
fi
if echo "$TAG" | grep -q -- "-"; then
PRERELEASE="true"
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT"
- name: Create GitHub Release
uses: actions/github-script@v7
if: ${{ github.event_name != 'release' }}
env:
TAG: ${{ steps.meta.outputs.tag }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PRERELEASE: ${{ steps.meta.outputs.prerelease }}
with:
script: |
const { TAG, PRERELEASE } = process.env;
if (!TAG) {
core.setFailed('TAG is empty, cannot create release.');
} else {
await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: TAG,
name: `Release ${TAG}`,
draft: false,
prerelease: PRERELEASE === 'true',
generate_release_notes: true,
});
core.info(`GitHub release created for ${TAG}`);
}