diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 7c2fab795..0c8206161 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -29,22 +29,79 @@ jobs: with: registry-url: 'https://registry.npmjs.org' + - name: Generate unique version from git + id: version + run: | + # Get base version from package.json + BASE_VERSION=$(node -p "require('./package.json').version") + + # Generate git describe version + GIT_DESCRIBE=$(git describe --tags --always --dirty 2>/dev/null || echo "unknown") + + if [[ $GITHUB_REF == refs/tags/* ]]; then + # For tags, use the base version as-is (stable release) + NPM_VERSION="${BASE_VERSION}" + NPM_TAG="latest" + echo "Publishing stable release: ${NPM_VERSION}" + else + # For main branch, create a pre-release version using git describe + # Format: 0.3.0-next.5.g1a2b3c4 (base-next.commits.hash) + GIT_COMMIT=$(git rev-parse --short HEAD) + COMMITS_SINCE_TAG=$(git rev-list --count HEAD ^$(git describe --tags --abbrev=0 2>/dev/null || echo HEAD) 2>/dev/null || echo "0") + NPM_VERSION="${BASE_VERSION}-next.${COMMITS_SINCE_TAG}.g${GIT_COMMIT}" + NPM_TAG="next" + echo "Publishing pre-release: ${NPM_VERSION}" + fi + + echo "version=${NPM_VERSION}" >> $GITHUB_OUTPUT + echo "tag=${NPM_TAG}" >> $GITHUB_OUTPUT + + # Update package.json with the new version + node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('package.json')); pkg.version = '${NPM_VERSION}'; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');" + + echo "Updated package.json to version ${NPM_VERSION}" + - name: Generate version file run: ./scripts/generate-version.sh - name: Build application run: make build - - name: Determine NPM tag - id: npm-tag + - name: Check if version exists + id: check-exists run: | - if [[ $GITHUB_REF == refs/tags/* ]]; then - echo "tag=latest" >> $GITHUB_OUTPUT - echo "Publishing as 'latest' tag (stable release)" + PACKAGE_NAME=$(node -p "require('./package.json').name") + VERSION="${{ steps.version.outputs.version }}" + + if npm view "${PACKAGE_NAME}@${VERSION}" version &>/dev/null; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Version ${VERSION} already exists on npm" else - echo "tag=next" >> $GITHUB_OUTPUT - echo "Publishing as 'next' tag (pre-release from main)" + echo "exists=false" >> $GITHUB_OUTPUT + echo "Version ${VERSION} does not exist, will publish" fi + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Publish to NPM - run: npm publish --tag ${{ steps.npm-tag.outputs.tag }} + if: steps.check-exists.outputs.exists == 'false' + run: npm publish --tag ${{ steps.version.outputs.tag }} + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Update dist-tag (version already exists) + if: steps.check-exists.outputs.exists == 'true' && github.ref_type == 'tag' + run: | + PACKAGE_NAME=$(node -p "require('./package.json').name") + VERSION="${{ steps.version.outputs.version }}" + TAG="${{ steps.version.outputs.tag }}" + + echo "Version ${VERSION} already published, updating dist-tag to ${TAG}" + npm dist-tag add "${PACKAGE_NAME}@${VERSION}" "${TAG}" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Skip (pre-release already exists) + if: steps.check-exists.outputs.exists == 'true' && github.ref_type != 'tag' + run: | + echo "⏭️ Pre-release version already exists, skipping"