diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index 4b632b7..1d51e4e 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -17,14 +17,15 @@ Cut a **$ARGUMENTS** release (major, minor, or patch) of the library in `package ``` If any check fails, stop and report the errors. -3. Publish from `packages/map-views`. npm may need browser or OTP authentication that Claude cannot handle; if `npm publish` asks for it, tell the user to run this in their terminal: +3. The tag push starts the Release workflow (`.github/workflows/release.yml`). It reruns the CI checks, publishes `packages/map-views` to npm with provenance, attests the tarball and creates a GitHub release. Watch it: ``` - npm login && npm publish + for i in $(seq 12); do id=$(gh run list --workflow release.yml --branch "v$v" --limit 1 --json databaseId --jq '.[0].databaseId'); [ -n "$id" ] && break; sleep 5; done + gh run watch "$id" --exit-status ``` + If it fails, show the user `gh run view "$id" --log-failed`. For a transient failure, offer `gh run rerun "$id" --failed`. If the code needs a fix, fix it on `main` and cut a new patch release; never move or reuse a tag. -4. Once the package is published, wait for the registry to serve the new version, polling for up to 5 minutes: +4. Wait for the registry to serve the new version, polling for up to 5 minutes: ``` - v=$(jq -r .version packages/map-views/package.json) for i in $(seq 20); do [ "$(npm view structured-context-map-views@$v version 2>/dev/null)" = "$v" ] && break; sleep 15; done npm view structured-context-map-views dist-tags ``` diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..83f761b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,65 @@ +name: Release + +# Pushing a version tag (the /release skill does this) publishes the library in +# packages/map-views to npm. The repo root is a private workspace and is never published. +on: + push: + tags: ["v[0-9]+.[0-9]+.[0-9]+"] + +permissions: + contents: read + +concurrency: + group: release + cancel-in-progress: false + +jobs: + test: + uses: ./.github/workflows/test.yml + + publish: + needs: test + runs-on: ubuntu-latest + # npm's trusted publisher config for this package names this workflow and environment. + environment: npm + permissions: + contents: write # GitHub release + id-token: write # npm trusted publishing and provenance + attestations: write # artifact attestation of the tarball + defaults: + run: + working-directory: packages/map-views + steps: + - uses: actions/checkout@v6 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + # Trusted publishing needs npm 11.5.1 or later, which Node 24 ships. + - uses: actions/setup-node@v6 + with: + node-version: 24 + - name: Check the tag matches package.json + run: | + v=$(jq -r .version package.json) + if [ "$GITHUB_REF_NAME" != "v$v" ]; then + echo "::error::Tag $GITHUB_REF_NAME does not match packages/map-views version $v" + exit 1 + fi + - run: bun install --frozen-lockfile + working-directory: . + - run: bun run build + # Pack once, so the tarball that is attested is the one published and attached. + - name: Pack + id: pack + run: echo "tarball=$(npm pack --ignore-scripts --silent)" >>"$GITHUB_OUTPUT" + - uses: actions/attest-build-provenance@v3 + with: + subject-path: packages/map-views/${{ steps.pack.outputs.tarball }} + - run: npm publish "$TARBALL" --provenance --access public + env: + TARBALL: ${{ steps.pack.outputs.tarball }} + - name: Create the GitHub release + run: gh release create "$GITHUB_REF_NAME" "$TARBALL" --verify-tag --generate-notes + env: + GH_TOKEN: ${{ github.token }} + TARBALL: ${{ steps.pack.outputs.tarball }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d93e697..5c528ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,7 @@ on: push: branches: [main] pull_request: + workflow_call: jobs: test: diff --git a/AGENTS.md b/AGENTS.md index 713ef9a..938e128 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,7 @@ bun run build # the library, then the navigator ## Releases -Releases go through the `/release ` skill, which runs `bun pm version --no-git-tag-version` in `packages/map-views` (its `preversion` and `version` scripts run the checks and freeze the definition format's schemas in `schemas/generated//` when the format changed), then commits, tags and pushes. Don't run `generate:schemas --release` by hand. +Releases go through the `/release ` skill, which runs `bun pm version --no-git-tag-version` in `packages/map-views` (its `preversion` and `version` scripts run the checks and freeze the definition format's schemas in `schemas/generated//` when the format changed), then commits, tags and pushes. The tag push runs `.github/workflows/release.yml`, which publishes the library to npm with provenance. Don't run `generate:schemas --release` by hand. ## Ways of working