diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index 9acaeac..99ffd5e 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -11,26 +11,70 @@ on: jobs: publish: runs-on: ubuntu-latest + permissions: + contents: read + id-token: write defaults: run: working-directory: ./mcp-server steps: - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - uses: actions/setup-node@v4 with: node-version: "24.x" registry-url: "https://registry.npmjs.org" - - run: npm ci - - name: Publish to NPM + # The runner's bundled npm predates OIDC support for dist-tag, which + # npm/cli#10038 added in 11.21.0 and 12.2.0. Pinned rather than `latest`: + # this runs in the job holding `id-token: write`, so whatever it installs + # can mint an npm credential for this package. Bumping it requires node + # >= 24.15.0, which `node-version` above must keep satisfying. + - name: Install npm with OIDC dist-tag support + run: npm install -g npm@12.2.0 --ignore-scripts + + - name: Promote to latest run: | - git config user.name "Currents NPM Bot" - git config user.email "npm@currents.dev" - npm dist-tag add @currents/mcp@${{ github.event.inputs.packageVersion }} latest + if ! npm dist-tag add @currents/mcp@${{ github.event.inputs.packageVersion }} latest; then + echo "::error::The registry refused the dist-tag. Trusted publishing grants it separately from publish, and it is off by default: enable 'Allow npm dist-tag' on the trusted publisher configuration for @currents/mcp at https://www.npmjs.com/package/@currents/mcp/access" + exit 1 + fi npm dist-tag rm @currents/mcp beta - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # Separate job so the third-party actions below do not run beside + # `id-token: write`: neither needs OIDC, and both resolve a mutable tag. + announce: + needs: publish + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Mark Linear release as complete + id: release + uses: linear/linear-release-action@v0 + with: + access_key: ${{ secrets.LINEAR_ACCESS_KEY }} + command: complete + version: ${{ github.event.inputs.packageVersion }} + + - name: Post to Slack + if: success() && steps.release.outputs.release-url + uses: slackapi/slack-github-action@v2 + with: + webhook: ${{ secrets.SLACK_RELEASE_WEBHOOK_URL }} + webhook-type: incoming-webhook + payload: | + { + "text": "πŸš€ Release: @currents/mcp@${{ github.event.inputs.packageVersion }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*πŸš€Release: @currents/mcp@${{ github.event.inputs.packageVersion }}* has been marked as complete in Linear.\n\n<${{ steps.release.outputs.release-url }}|View Release Notes>" + } + } + ] + } diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 4300057..8ffa92b 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -34,9 +34,10 @@ jobs: - name: Validate release branch for latest channel if: github.event.inputs.channel == 'latest' run: | - if [[ ! "${{ github.ref }}" =~ ^refs/(heads|tags)/release/ ]]; then - echo "Error: Publishing to 'latest' channel requires a release/* branch or tag" + if [[ ! "${{ github.ref }}" =~ ^refs/heads/release/ ]]; then + echo "Error: Publishing to 'latest' channel requires a release/* branch" echo "Current ref: ${{ github.ref }}" + echo "Release tags are named v, so the tag of a release does not match." exit 1 fi diff --git a/RELEASE.md b/RELEASE.md index e44c251..91ee3a1 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -105,9 +105,15 @@ The workflow will: 1. Add the `latest` dist-tag to the specified version 2. Remove the `beta` dist-tag from that version +3. Mark the release complete in Linear and post it to Slack This is useful when you've tested a beta release and want to make it the default install without rebuilding. +The workflow authenticates with npm through Trusted Publishing, so it needs no +`NPM_TOKEN`. Trusted publishing grants dist-tag separately from publish, and the +grant is off by default: **Allow npm dist-tag** has to be enabled on the trusted +publisher configuration for `@currents/mcp`, or the registry refuses the tag. + ## Linear Release The repository follows a branch-cut release model with Linear Releases integration: @@ -116,7 +122,7 @@ The repository follows a branch-cut release model with Linear Releases integrati 2. **Release branch creation** β€” when a `release/*` branch is pushed, it automatically: - Syncs with Linear Release 3. **Stabilization** β€” only bug fixes and critical changes are allowed on the release branch -4. **Publishing** β€” when publishing to npm via the "Publish NPM Package" workflow with `latest` channel, the release is automatically marked as completed in Linear and posted to Slack +4. **Publishing** β€” the release is marked complete in Linear and posted to Slack when a version reaches the `latest` channel, whether by "NPM - Promote beta to latest" or by "Publish NPM Package" with the `latest` channel The workflow is defined in `.github/workflows/linear-release.yaml` and syncs the release state between Git branches and Linear Releases.