chore: release 1.1.3 #6
Workflow file for this run
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: | |
| 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: 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: Determine npm tag and release metadata | |
| id: meta | |
| run: | | |
| # Determine npm tag | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| NPM_TAG="${{ inputs.tag }}" | |
| else | |
| # Check if this is a prerelease version (contains -, like 1.0.0-beta.1) | |
| VERSION=$(node -p "require('./package.json').version") | |
| if echo "$VERSION" | grep -q "-"; then | |
| NPM_TAG="next" | |
| PRERELEASE="true" | |
| else | |
| NPM_TAG="latest" | |
| PRERELEASE="false" | |
| fi | |
| fi | |
| echo "npm_tag=$NPM_TAG" >> "$GITHUB_OUTPUT" | |
| echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Publish to npm | |
| if: steps.check_version.outputs.exists == 'false' | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: npm publish --provenance --tag ${{ steps.meta.outputs.npm_tag }} | |
| - name: Extract changelog for current version | |
| id: changelog | |
| run: | | |
| VERSION="${{ steps.meta.outputs.version }}" | |
| if [ -f "CHANGELOG.md" ]; then | |
| # Extract content for this version from CHANGELOG.md | |
| # Match lines between "## <small>VERSION" or "## [VERSION]" and next "## " | |
| CHANGELOG=$(awk "/^## .*${VERSION}/,/^## [^#]/" CHANGELOG.md | sed '1d;$d') | |
| if [ -n "$CHANGELOG" ]; then | |
| echo "found=true" >> "$GITHUB_OUTPUT" | |
| echo "$CHANGELOG" > /tmp/changelog.txt | |
| else | |
| echo "found=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| else | |
| echo "found=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Create GitHub Release | |
| uses: actions/github-script@v7 | |
| env: | |
| TAG: v${{ steps.meta.outputs.version }} | |
| PRERELEASE: ${{ steps.meta.outputs.prerelease }} | |
| CHANGELOG_FOUND: ${{ steps.changelog.outputs.found }} | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const { TAG, PRERELEASE, CHANGELOG_FOUND } = process.env; | |
| let body = ''; | |
| // Try to use changelog from CHANGELOG.md | |
| if (CHANGELOG_FOUND === 'true') { | |
| try { | |
| body = fs.readFileSync('/tmp/changelog.txt', 'utf8').trim(); | |
| core.info('Using changelog from CHANGELOG.md'); | |
| } catch (error) { | |
| core.warning('Could not read changelog file'); | |
| } | |
| } | |
| // Fallback: generate from commits if no changelog | |
| if (!body) { | |
| core.info('Generating changelog from commits'); | |
| const tags = await github.rest.repos.listTags({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| per_page: 100 | |
| }); | |
| const currentIndex = tags.data.findIndex(t => t.name === TAG); | |
| const previousTag = currentIndex >= 0 && currentIndex < tags.data.length - 1 | |
| ? tags.data[currentIndex + 1].name | |
| : null; | |
| if (previousTag) { | |
| const comparison = await github.rest.repos.compareCommits({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| base: previousTag, | |
| head: TAG | |
| }); | |
| body = '### Changes\n\n'; | |
| comparison.data.commits.forEach(commit => { | |
| const message = commit.commit.message.split('\n')[0]; | |
| const sha = commit.sha.substring(0, 7); | |
| body += `- ${message} ([${sha}](${commit.html_url}))\n`; | |
| }); | |
| body += `\n**Full Changelog**: https://github.com/${context.repo.owner}/${context.repo.repo}/compare/${previousTag}...${TAG}`; | |
| } | |
| } | |
| if (!body) { | |
| body = 'Release ' + TAG; | |
| } | |
| await github.rest.repos.createRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| tag_name: TAG, | |
| name: TAG, | |
| body: body, | |
| draft: false, | |
| prerelease: PRERELEASE === 'true', | |
| }); | |
| core.info(`GitHub release created for ${TAG}`); |