Repository navigation
v1.0.2 #10
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 | |
| on: | |
| push: | |
| tags: ['v*'] | |
| permissions: | |
| id-token: write # npm Trusted Publishing OIDC | |
| contents: write # GitHub Release creation | |
| concurrency: | |
| group: publish | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 | |
| with: | |
| node-version: '22.14.0' | |
| registry-url: https://registry.npmjs.org | |
| - name: Use npm with Trusted Publishing support | |
| # Pinned exact (>=11.5.1 required for Trusted Publishing); bump deliberately. | |
| run: npm install -g npm@11.16.0 | |
| - name: Verify tag matches package.json version | |
| run: | | |
| set -eo pipefail | |
| TAG_VERSION="${GITHUB_REF_NAME#v}" | |
| PKG_VERSION="$(node -p 'require("./package.json").version')" | |
| if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then | |
| echo "::error::Tag v${TAG_VERSION} does not match package.json version ${PKG_VERSION}" | |
| exit 1 | |
| fi | |
| - name: Verify publishable file set | |
| run: | | |
| set -eo pipefail | |
| PACK_JSON="$(npm pack --dry-run --json)" | |
| PACK_JSON="${PACK_JSON}" node <<'NODE' | |
| const data = JSON.parse(process.env.PACK_JSON) | |
| const files = data[0].files.map((file) => file.path).sort() | |
| const expected = [ | |
| 'CHANGELOG.md', | |
| 'LICENSE', | |
| 'README.md', | |
| 'bin/appfigures', | |
| 'dist/af.js', | |
| 'package.json', | |
| 'server.json', | |
| ] | |
| if (JSON.stringify(files) !== JSON.stringify(expected)) { | |
| console.error(`Expected npm pack files ${JSON.stringify(expected)}, got ${JSON.stringify(files)}`) | |
| process.exit(1) | |
| } | |
| NODE | |
| - name: Extract release notes | |
| run: | | |
| set -eo pipefail | |
| node - "${GITHUB_REF_NAME#v}" > release-notes.md <<'NODE' | |
| const fs = require('fs') | |
| const version = process.argv[2] | |
| const content = fs.readFileSync('CHANGELOG.md', 'utf8') | |
| const escaped = version.replace(/[.+*?^$(){}|[\]\\]/g, '\\$&') | |
| const headerRe = new RegExp(`^## \\[${escaped}\\]`) | |
| const nextHeaderRe = /^## \[/ | |
| const captured = [] | |
| let inSection = false | |
| for (const line of content.split('\n')) { | |
| if (inSection && nextHeaderRe.test(line)) break | |
| if (headerRe.test(line)) { | |
| inSection = true | |
| continue | |
| } | |
| if (inSection) captured.push(line) | |
| } | |
| if (!inSection) { | |
| console.error(`No CHANGELOG section found for version ${version}`) | |
| process.exit(1) | |
| } | |
| process.stdout.write(captured.join('\n').trim() + '\n') | |
| NODE | |
| - name: Publish to npm | |
| run: | | |
| set -eo pipefail | |
| NAME="$(node -p 'require("./package.json").name')" | |
| VERSION="$(node -p 'require("./package.json").version')" | |
| TAG="$(node -e 'const version = process.argv[1]; const match = version.match(/^\d+\.\d+\.\d+-([0-9A-Za-z]+)/); if (match) process.stdout.write(match[1]);' "${VERSION}")" | |
| if npm view "${NAME}@${VERSION}" version >/dev/null 2>&1; then | |
| echo "${NAME}@${VERSION} is already published; skipping npm publish" | |
| exit 0 | |
| fi | |
| if [ -n "$TAG" ]; then | |
| npm publish --tag "$TAG" | |
| else | |
| npm publish | |
| fi | |
| # Publish the registry listing after npm publish (the entry references | |
| # @appfigures/cli@<version>, which must exist on npm first). | |
| # Bump MCP_PUBLISHER_VERSION/_SHA256 together from the release checksums.txt. | |
| - name: Install mcp-publisher | |
| env: | |
| MCP_PUBLISHER_VERSION: '1.7.9' | |
| MCP_PUBLISHER_SHA256: 'ab128162b0616090b47cf245afe0a23f3ef08936fdce19074f5ba0a4469281ac' | |
| run: | | |
| set -eo pipefail | |
| curl -fsSL -o mcp-publisher.tar.gz \ | |
| "https://github.com/modelcontextprotocol/registry/releases/download/v${MCP_PUBLISHER_VERSION}/mcp-publisher_linux_amd64.tar.gz" | |
| echo "${MCP_PUBLISHER_SHA256} mcp-publisher.tar.gz" | sha256sum -c - | |
| tar xz -f mcp-publisher.tar.gz mcp-publisher | |
| rm -f mcp-publisher.tar.gz | |
| - name: Stamp release version into server.json | |
| run: | | |
| set -eo pipefail | |
| VERSION="${GITHUB_REF_NAME#v}" node <<'NODE' | |
| const fs = require('fs') | |
| const version = process.env.VERSION | |
| const server = JSON.parse(fs.readFileSync('server.json', 'utf8')) | |
| server.version = version | |
| server.packages[0].version = version | |
| fs.writeFileSync('server.json', JSON.stringify(server, null, '\t') + '\n') | |
| NODE | |
| - name: Publish to MCP Registry | |
| run: | | |
| set -eo pipefail | |
| # Derive the hex key from the PEM secret; remove the file after. | |
| printf '%s' "${{ secrets.MCP_REGISTRY_PRIVATE_KEY }}" > key.pem | |
| ./mcp-publisher login dns --domain appfigures.com \ | |
| --private-key "$(openssl pkey -in key.pem -noout -text | grep -A3 'priv:' | tail -n +2 | tr -d ' :\n')" | |
| rm -f key.pem | |
| ./mcp-publisher publish | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -eo pipefail | |
| if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then | |
| echo "Release ${GITHUB_REF_NAME} already exists; skipping" | |
| exit 0 | |
| fi | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| gh release create "${GITHUB_REF_NAME}" \ | |
| --title "@appfigures/cli v${VERSION}" \ | |
| --notes-file release-notes.md |