diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..717e337 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,83 @@ +name: Publish + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + registry-url: https://registry.npmjs.org + + - name: Install deps + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm run lint + + - name: Typecheck + run: pnpm run typecheck + + - name: Test + run: pnpm run test + + - name: Build + run: pnpm run build + + - name: Verify tag/version lock + run: | + NPM_VERSION=$(node -p "require('./package.json').version") + if [[ "${GITHUB_REF:-}" == refs/tags/v* ]]; then + TAG_VERSION="${GITHUB_REF#refs/tags/v}" + if [ "$TAG_VERSION" != "$NPM_VERSION" ]; then + echo "::error::Tag/version mismatch: tag=$TAG_VERSION package=$NPM_VERSION." + exit 1 + fi + fi + echo "Version locked: $NPM_VERSION" + + publish-npm: + needs: verify + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + registry-url: https://registry.npmjs.org + + - run: pnpm install --frozen-lockfile + - run: pnpm run build + + # Idempotent: re-running a tag whose npm version is already published + # must not fail the workflow. + - name: Publish to npm (skip if already published) + run: | + NAME=$(node -p "require('./package.json').name") + VERSION=$(node -p "require('./package.json').version") + if npm view "$NAME@$VERSION" version >/dev/null 2>&1; then + echo "$NAME@$VERSION already on registry; skipping publish" + else + pnpm publish --no-git-checks --access public + fi + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}