Merge develop for v2.4.1 release #16
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 | |
| # Publishes @gravitykit/mcp via npm Trusted Publishing (OIDC) — no NPM_TOKEN | |
| # secret to rotate or leak; OIDC also generates provenance attestations. | |
| # | |
| # One-time setup on npmjs.com: package @gravitykit/mcp → Settings → | |
| # Trusted Publisher → GitHub Actions, repository GravityKit/MCP, | |
| # workflow publish.yml. | |
| # | |
| # Triggers on a v* tag (the release) and workflow_dispatch (manual re-run). | |
| # The version guard makes both idempotent — an already-published version is a | |
| # no-op, so re-running or re-tagging never errors. | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write # create the GitHub Release | |
| id-token: write # OIDC token for npm trusted publishing + provenance | |
| concurrency: | |
| group: npm-publish | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| name: Publish @gravitykit/mcp | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false # npm auth comes from OIDC, not git | |
| - name: Setup Node | |
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: 22 | |
| - name: Update npm (trusted publishing requires npm >= 11.5) | |
| # Pinned to the 11.x major so a future npm major can't change publish | |
| # behavior mid-release. | |
| run: npm install -g npm@11 | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Skip when this version is already published | |
| id: guard | |
| # Only a definitive "version not found" may proceed to publish; any other | |
| # npm view failure (network, registry outage) fails the job so a transient | |
| # error can't slip past the idempotency check. Some npm versions report a | |
| # missing version as exit 0 with empty output, so success requires | |
| # non-empty output too. | |
| run: | | |
| VERSION="$(node -p "require('./package.json').version")" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| if OUTPUT="$(npm view "@gravitykit/mcp@$VERSION" version 2>&1)"; then | |
| STATUS=0 | |
| else | |
| STATUS=$? | |
| fi | |
| if [ "$STATUS" -eq 0 ] && [ -n "$OUTPUT" ]; then | |
| echo "published=true" >> "$GITHUB_OUTPUT" | |
| echo "@gravitykit/mcp@$VERSION is already on npm — nothing to publish." | |
| elif [ "$STATUS" -eq 0 ] || printf '%s' "$OUTPUT" | grep -qiE 'E404|not found|no match found'; then | |
| echo "published=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "::error::Could not determine whether @gravitykit/mcp@$VERSION is published (npm view exit $STATUS):" >&2 | |
| printf '%s\n' "$OUTPUT" >&2 | |
| exit 1 | |
| fi | |
| - name: Publish to npm (OIDC trusted publishing + provenance) | |
| if: steps.guard.outputs.published == 'false' | |
| # prepublishOnly runs the full offline gate (tests + publint + doc guard) | |
| # automatically before the package is published. | |
| run: npm publish --access public | |
| - name: Create GitHub Release | |
| id: release | |
| if: steps.guard.outputs.published == 'false' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| VERSION="${{ steps.guard.outputs.version }}" | |
| if gh release view "v$VERSION" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then | |
| echo "Release v$VERSION already exists — skipping." | |
| exit 0 | |
| fi | |
| gh release create "v$VERSION" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "v$VERSION" \ | |
| --verify-tag \ | |
| --notes "See [CHANGELOG.md](https://github.com/$GITHUB_REPOSITORY/blob/main/CHANGELOG.md) for details. | |
| Install: \`npm install @gravitykit/mcp@$VERSION\` · [View on npm](https://www.npmjs.com/package/@gravitykit/mcp/v/$VERSION)" | |
| # Signals the Slack step that a release was actually created this run | |
| # (not an idempotent skip), so announcements never double-fire. | |
| echo "created=true" >> "$GITHUB_OUTPUT" | |
| - name: Announce release to Slack | |
| # Mirrors gktools' "Notify Slack": POST {link,version,changelog,product} | |
| # to SLACK_RELEASE_NOTIFICATION_WEBHOOK so GravityKit MCP shows up in | |
| # #release-announcements like every other plugin. Only after a release is | |
| # actually created; never fails the job. | |
| if: steps.release.outputs.created == 'true' | |
| env: | |
| SLACK_RELEASE_NOTIFICATION_WEBHOOK: ${{ secrets.SLACK_RELEASE_NOTIFICATION_WEBHOOK }} | |
| # Bind expressions through env (quoted shell vars below) instead of | |
| # interpolating ${{ }} into the run script — avoids template-to-shell injection. | |
| VERSION: ${{ steps.guard.outputs.version }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| if [ -z "${SLACK_RELEASE_NOTIFICATION_WEBHOOK:-}" ]; then | |
| echo "SLACK_RELEASE_NOTIFICATION_WEBHOOK not set — skipping Slack announcement." | |
| exit 0 | |
| fi | |
| LINK="https://github.com/$REPO/releases/tag/v$VERSION" | |
| # Extract this version's CHANGELOG section: lines between "## [VERSION]" | |
| # and the next "## [" header. | |
| NOTES="$(awk -v ver="$VERSION" ' | |
| $0 ~ "^## \\[" ver "\\]" { capture=1; next } | |
| capture && /^## \[/ { exit } | |
| capture { print } | |
| ' CHANGELOG.md)" | |
| # jq builds the JSON so newlines/quotes in the changelog are escaped. | |
| PAYLOAD="$(jq -n \ | |
| --arg link "$LINK" \ | |
| --arg version "$VERSION" \ | |
| --arg changelog "$NOTES" \ | |
| --arg product "GravityKit MCP" \ | |
| '{link:$link,version:$version,changelog:$changelog,product:$product}')" | |
| # Non-fatal, like gktools: a bad Slack response only warns. | |
| RESPONSE="$(curl -sS -X POST \ | |
| -H 'Content-Type: application/json' \ | |
| --data "$PAYLOAD" \ | |
| "$SLACK_RELEASE_NOTIFICATION_WEBHOOK" || true)" | |
| echo "Slack response: $RESPONSE" | |
| if ! printf '%s' "$RESPONSE" | grep -q '"ok":true'; then | |
| echo "::warning::Slack release announcement did not return \"ok\":true." | |
| fi |