Publish to npm #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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}`); | |
| } |