Skip to content

Merge pull request #8 from auth0/release/auto_npm_release #2

Merge pull request #8 from auth0/release/auto_npm_release

Merge pull request #8 from auth0/release/auto_npm_release #2

Workflow file for this run

name: Publish to Public NPM
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- master
workflow_dispatch:
inputs:
dry_run:
description: "Dry run (preview without publishing)"
required: false
type: boolean
default: true
permissions:
contents: write
id-token: write
jobs:
publish:
name: Build & Publish to Public NPM
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- name: Determine dry run mode
id: dry_run_mode
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "DRY_RUN=true" >> $GITHUB_ENV
echo "Running in DRY RUN mode (PR)"
elif [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref }}" = "refs/heads/master" ]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
echo "Running in PUBLISH mode (merged to master)"
elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "DRY_RUN=${{ github.event.inputs.dry_run }}" >> $GITHUB_ENV
echo "Running in MANUAL mode (dry_run=${{ github.event.inputs.dry_run }})"
else
echo "DRY_RUN=true" >> $GITHUB_ENV
echo "Running in DRY RUN mode (default)"
fi
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "yarn"
registry-url: "https://registry.npmjs.org"
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Detect version and npm tag from package.json
id: detect
run: |
PACKAGE_NAME=$(node -p "require('./package.json').name")
VERSION=$(node -p "require('./package.json').version")
determine_tag() {
local version=$1
if [[ "$version" == *"alpha"* ]]; then
echo "alpha"
elif [[ "$version" == *"beta"* ]]; then
echo "beta"
elif [[ "$version" == *"rc"* ]]; then
echo "next"
else
echo "latest"
fi
}
NPM_TAG=$(determine_tag "$VERSION")
echo "Detected from package.json:"
echo "Package: $PACKAGE_NAME"
echo "Version: $VERSION"
echo "NPM Tag: ${NPM_TAG}"
echo "PACKAGE_NAME=${PACKAGE_NAME}" >> $GITHUB_ENV
echo "VERSION=${VERSION}" >> $GITHUB_ENV
echo "NPM_TAG=${NPM_TAG}" >> $GITHUB_ENV
- name: Check if version already exists on npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "Checking if ${PACKAGE_NAME}@${VERSION} already exists on npm..."
# Check if the specific version exists
if npm view "${PACKAGE_NAME}@${VERSION}" version 2>/dev/null; then
echo "❌ ERROR: Version ${VERSION} already exists on npm!"
echo "Please bump the version in package.json before publishing."
exit 1
else
echo "✅ Version ${VERSION} does not exist on npm. Safe to publish."
fi
- name: Check if git tag already exists
run: |
TAG_NAME="v${VERSION}"
echo "Checking if git tag ${TAG_NAME} already exists..."
if git rev-parse "${TAG_NAME}" >/dev/null 2>&1; then
echo "❌ ERROR: Git tag ${TAG_NAME} already exists!"
echo "Please use a different version or delete the existing tag."
exit 1
else
echo "✅ Git tag ${TAG_NAME} does not exist. Safe to proceed."
fi
- name: Update package for public npm
run: |
node -e "
const pkg = require('./package.json');
pkg.publishConfig = {
access: 'public',
registry: 'https://registry.npmjs.org/'
};
require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n');
"
- name: Publish package to public npm
id: publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "Publishing ${PACKAGE_NAME}@${VERSION} with tag: ${NPM_TAG}"
echo "Dry run mode: ${DRY_RUN}"
if [ "$DRY_RUN" = "true" ]; then
echo "DRY RUN - Skipping publish"
npm publish --dry-run --tag="${NPM_TAG}"
echo "published=dry-run" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "package_name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT
echo "Published ${PACKAGE_NAME}@${VERSION} (dry run)"
else
npm publish --tag="${NPM_TAG}"
echo "published=true" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "package_name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT
echo "Published ${PACKAGE_NAME}@${VERSION}"
fi
- name: Generate Summary
run: |
echo "## Public NPM Publication Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$DRY_RUN" = "true" ]; then
echo "### DRY RUN MODE" >> $GITHUB_STEP_SUMMARY
echo "No packages were published. This was a test run." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
echo "### Published Package" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.publish.outputs.published }}" != "" ]; then
echo "- \`${{ steps.publish.outputs.package_name }}@${VERSION}\`" >> $GITHUB_STEP_SUMMARY
echo " - Tag: \`${NPM_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo " - Registry: https://registry.npmjs.org" >> $GITHUB_STEP_SUMMARY
echo " - Install: \`npm install ${{ steps.publish.outputs.package_name }}@${NPM_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
echo "### Links" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.publish.outputs.published }}" != "" ]; then
echo "- [View ${{ steps.publish.outputs.package_name }} on npm](https://www.npmjs.com/package/${{ steps.publish.outputs.package_name }})" >> $GITHUB_STEP_SUMMARY
fi
- name: Create Git tag
if: env.DRY_RUN != 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if [ "${{ steps.publish.outputs.published }}" = "true" ]; then
TAG_NAME="v${VERSION}"
git tag -a "$TAG_NAME" -m "Release ${PACKAGE_NAME}@${VERSION}"
git push origin "$TAG_NAME"
echo "Created tag: $TAG_NAME"
fi
- name: Create GitHub Release
if: |
env.DRY_RUN != 'true' &&
steps.publish.outputs.published == 'true'
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ env.VERSION }}
name: "${{ env.PACKAGE_NAME }}@${{ env.VERSION }}"
body: |
Published to NPM
**Package**: `${{ env.PACKAGE_NAME }}`
**Version**: `${{ env.VERSION }}`
**NPM Tag**: `${{ env.NPM_TAG }}`
```bash
npm install ${{ env.PACKAGE_NAME }}@${{ env.VERSION }}
```
[View on NPM](https://www.npmjs.com/package/${{ env.PACKAGE_NAME }}/v/${{ env.VERSION }})
prerelease: ${{ env.NPM_TAG != 'latest' }}
draft: false
- name: Restore package.json file
if: always()
run: |
git checkout package.json || true
- name: Handle workflow failure
if: failure()
run: |
echo "## Workflow Failed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The workflow encountered an error. Please check the logs above for details." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Common Issues" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Authentication**: Verify NPM_TOKEN secret is configured correctly" >> $GITHUB_STEP_SUMMARY
echo "- **Version conflict**: Package version may already exist on npm" >> $GITHUB_STEP_SUMMARY
echo "- **Tests failure**: Check if tests pass successfully" >> $GITHUB_STEP_SUMMARY
echo "- **Network issues**: NPM registry may be unreachable" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Next Steps" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "1. Review the error logs in this workflow run" >> $GITHUB_STEP_SUMMARY
echo "2. Fix the issue and retry the workflow" >> $GITHUB_STEP_SUMMARY
echo "3. If needed, manually publish using: \`npm publish\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Workflow Run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY