0.2.1 #8
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: Release | |
| # Fires on a SemVer tag push (`vX.Y.Z`). Builds once, then publishes to | |
| # npm + GitHub Packages and creates a GitHub Release. Use `pnpm version` | |
| # locally to bump and tag in one go, then `git push --follow-tags`. | |
| # Manual `workflow_dispatch` is kept for re-publishing an existing tag. | |
| on: | |
| push: | |
| tags: | |
| - "v*.*.*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to release (e.g. v0.1.0). Tag must already exist on origin." | |
| required: true | |
| permissions: | |
| contents: write # create GitHub Release | |
| packages: write # publish to GitHub Packages | |
| id-token: write # npm provenance (sigstore) | |
| jobs: | |
| # ───────────────────────────────────────────────────────────────────── | |
| # 1. Build & verify the package once. Both publish jobs reuse this artifact. | |
| # ───────────────────────────────────────────────────────────────────── | |
| build: | |
| name: Build & verify | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 12 | |
| outputs: | |
| version: ${{ steps.read.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| - uses: pnpm/action-setup@v5 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| - run: pnpm install --frozen-lockfile | |
| - run: pnpm run typecheck | |
| - run: pnpm run build | |
| - name: Read package version | |
| id: read | |
| run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT" | |
| - name: Verify tag matches package version | |
| run: | | |
| INPUT="${{ github.event.inputs.tag }}" | |
| TAG="${INPUT:-${GITHUB_REF_NAME#refs/tags/}}" | |
| PKG="v${{ steps.read.outputs.version }}" | |
| echo "tag=$TAG pkg=$PKG" | |
| if [ "$TAG" != "$PKG" ]; then | |
| echo "::error::Tag $TAG does not match package.json version $PKG" | |
| exit 1 | |
| fi | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: dist | |
| path: | | |
| dist/ | |
| package.json | |
| README.md | |
| retention-days: 14 | |
| # ───────────────────────────────────────────────────────────────────── | |
| # 2. Publish to npm (public registry). | |
| # Requires NPM_TOKEN secret in repo → Settings → Secrets & variables. | |
| # ───────────────────────────────────────────────────────────────────── | |
| publish-npm: | |
| name: Publish · npm | |
| needs: build | |
| runs-on: ubuntu-latest | |
| environment: npm | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: { name: dist } | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| registry-url: "https://registry.npmjs.org" | |
| scope: "@ossrandom" | |
| - name: Skip if version already on npm | |
| id: npm-check | |
| # `npm view` against the configured registry returns 0 if the | |
| # version exists, non-zero otherwise. Lets re-running the same | |
| # tag (e.g. after a downstream failure) be a no-op instead of | |
| # erroring out the whole job. | |
| run: | | |
| PKG_NAME=$(node -p "require('./package.json').name") | |
| PKG_VER=$(node -p "require('./package.json').version") | |
| if npm view "$PKG_NAME@$PKG_VER" version > /dev/null 2>&1; then | |
| echo "already=true" >> "$GITHUB_OUTPUT" | |
| echo "::notice::$PKG_NAME@$PKG_VER is already published on npm — skipping." | |
| else | |
| echo "already=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Publish (with provenance) | |
| # --ignore-scripts: build was already done in the `build` job; | |
| # the prepublishOnly hook would otherwise try to invoke pnpm, | |
| # which isn't installed in this job. | |
| if: steps.npm-check.outputs.already != 'true' | |
| run: npm publish --provenance --access public --ignore-scripts | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| # ───────────────────────────────────────────────────────────────────── | |
| # 3. Publish to GitHub Packages (mirror). | |
| # Uses GITHUB_TOKEN — no secret needed. Same @ossrandom scope as npm, | |
| # only the registry URL changes. | |
| # ───────────────────────────────────────────────────────────────────── | |
| publish-gpr: | |
| name: Publish · GitHub Packages | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: { name: dist } | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| registry-url: "https://npm.pkg.github.com" | |
| scope: "@randomcodespace" | |
| - name: Rewrite name + publishConfig for GitHub Packages | |
| # GHP requires the npm scope to match the repo owner. We rewrite | |
| # `@ossrandom/design-system` → `@randomcodespace/design-system` | |
| # in the artifact's package.json before publishing. The committed | |
| # package.json keeps the canonical npm name. | |
| run: | | |
| node -e " | |
| const fs = require('fs'); | |
| const p = JSON.parse(fs.readFileSync('package.json','utf8')); | |
| p.name = '@randomcodespace/design-system'; | |
| p.publishConfig = { access: 'public', registry: 'https://npm.pkg.github.com' }; | |
| fs.writeFileSync('package.json', JSON.stringify(p, null, 2)); | |
| " | |
| - name: Skip if version already on GHP | |
| id: gpr-check | |
| # Run AFTER the rewrite step so the lookup uses the GHP scope. | |
| run: | | |
| PKG_NAME=$(node -p "require('./package.json').name") | |
| PKG_VER=$(node -p "require('./package.json').version") | |
| if npm view "$PKG_NAME@$PKG_VER" version > /dev/null 2>&1; then | |
| echo "already=true" >> "$GITHUB_OUTPUT" | |
| echo "::notice::$PKG_NAME@$PKG_VER is already published on GHP — skipping." | |
| else | |
| echo "already=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Publish to GitHub Packages | |
| if: steps.gpr-check.outputs.already != 'true' | |
| run: npm publish --ignore-scripts | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # ───────────────────────────────────────────────────────────────────── | |
| # 4. Create the GitHub Release with auto-generated notes. | |
| # ───────────────────────────────────────────────────────────────────── | |
| github-release: | |
| name: GitHub Release | |
| needs: [build, publish-npm, publish-gpr] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/download-artifact@v8 | |
| with: { name: dist, path: artifact } | |
| - name: Pack tarball | |
| # `--ignore-scripts` skips prepublishOnly (which calls pnpm and | |
| # would fail in this minimal job). The dest dir must exist — | |
| # npm pack does not create it. | |
| run: | | |
| mkdir -p release-assets | |
| cd artifact && npm pack --ignore-scripts --pack-destination ../release-assets | |
| ls -la ../release-assets | |
| - uses: softprops/action-gh-release@v3 | |
| with: | |
| # Honor the workflow_dispatch input; fall back to the tag the | |
| # tag-push trigger fired on (github.ref_name). | |
| tag_name: ${{ github.event.inputs.tag || github.ref_name }} | |
| name: ${{ github.event.inputs.tag || github.ref_name }} | |
| generate_release_notes: true | |
| files: | | |
| release-assets/*.tgz |