Skip to content

Publish to npm

Publish to npm #22

Workflow file for this run

name: Publish to npm
# Runs after the full CI workflow succeeds on main (not on the raw push), so a
# red lint/cost-map-sync/python job blocks an npm release too. The old js/**
# path filter is gone; the version gate below already makes no-op runs cheap.
on:
workflow_run:
workflows: [CI]
types: [completed]
branches: [main]
workflow_dispatch:
concurrency:
group: publish-npm-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: write # push the release tag; npm auth stays the token secret
jobs:
publish:
# workflow_run's `branches` filter matches the HEAD branch NAME of the
# triggering run — a fork PR from a branch named "main" would match it. The
# event/head_repository checks restrict publishing to push-triggered CI on
# this repo's own main.
if: >-
(github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') ||
(github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_repository.full_name == github.repository)
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: js
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
# workflow_run checks out the default branch by default; pin to the
# exact commit CI validated.
ref: ${{ github.event.workflow_run.head_sha || github.ref }}
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
# Node 22: current LTS, comfortably covers the JS toolchain (Vite/Vitest).
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Test
run: npm test --if-present
- name: Check if version is already published
id: check
run: |
set -euo pipefail
PKG_NAME=$(node -p "require('./package.json').name")
PKG_VERSION=$(node -p "require('./package.json').version")
echo "name=$PKG_NAME" >> "$GITHUB_OUTPUT"
echo "version=$PKG_VERSION" >> "$GITHUB_OUTPUT"
if npm view "$PKG_NAME@$PKG_VERSION" version > /dev/null 2>npm_view.err; then
echo "$PKG_NAME@$PKG_VERSION already published on npm, skipping."
echo "should_publish=false" >> "$GITHUB_OUTPUT"
elif grep -q 'E404' npm_view.err; then
echo "$PKG_NAME@$PKG_VERSION not found on npm, will publish."
echo "should_publish=true" >> "$GITHUB_OUTPUT"
else
echo "npm view failed unexpectedly; aborting publish check." >&2
cat npm_view.err >&2
exit 1
fi
- name: Publish
if: steps.check.outputs.should_publish == 'true'
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Tag the release
# Maps the published artifact back to its exact commit ("js-" prefix:
# the PyPI package versions independently and tags "py-v<version>").
if: steps.check.outputs.should_publish == 'true'
env:
GH_TOKEN: ${{ github.token }}
PKG_VERSION: ${{ steps.check.outputs.version }}
run: |
gh api "repos/${{ github.repository }}/git/refs" \
-f ref="refs/tags/js-v$PKG_VERSION" \
-f sha="$(git rev-parse HEAD)" \
|| echo "::warning::tag js-v$PKG_VERSION already exists or could not be created"