Repository navigation
feat(tools): raw_api_request — прямой GET к API Яндекс.Трекера #46
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 | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| packages: write | |
| id-token: write | |
| jobs: | |
| # Job 1: Run semantic-release to determine version and create release | |
| release: | |
| name: Semantic Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| new_release_published: ${{ steps.semantic.outputs.new_release_published }} | |
| new_release_version: ${{ steps.semantic.outputs.new_release_version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22.x' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run full validation | |
| run: npm run validate | |
| env: | |
| CI: true | |
| - name: Run smoke tests | |
| run: npm run test:smoke | |
| - name: Semantic Release | |
| id: semantic | |
| uses: cycjimmy/semantic-release-action@v4 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Job 2: Publish to NPM using OIDC Trusted Publishing (no NPM_TOKEN needed!) | |
| publish-npm: | |
| name: Publish to NPM Registry (Trusted Publishing) | |
| needs: release | |
| runs-on: ubuntu-latest | |
| if: needs.release.outputs.new_release_published == 'true' | |
| # id-token: write MUST be declared at job level — workflow-level permissions | |
| # are not inherited for id-token when a job uses `environment:`. Without this | |
| # explicit block, ACTIONS_ID_TOKEN_REQUEST_URL is not set, npm can't mint an | |
| # OIDC token, and trusted publishing silently returns HTTP 404 from registry. | |
| permissions: | |
| contents: read | |
| id-token: write | |
| # Environment must be configured in GitHub repo settings | |
| # and match the trusted publisher config on npmjs.com | |
| environment: npm-publish | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: v${{ needs.release.outputs.new_release_version }} | |
| - name: Setup Node.js 24 with NPM registry | |
| # Node 24 ships with npm 11.x. Node 22 ships with npm 10.x which does | |
| # NOT support OIDC trusted publishing — it fails with ENEEDAUTH even | |
| # when ACTIONS_ID_TOKEN_REQUEST_* env vars are set (OIDC support was | |
| # added in npm 11.5.1). Upgrading npm inside the runner via | |
| # `npm install -g npm@latest` hits a self-update bootstrap bug | |
| # (MODULE_NOT_FOUND promise-retry), so the clean solution is to use | |
| # a Node version that already ships with npm 11.x. | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24.x' | |
| cache: 'npm' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Verify npm version supports OIDC | |
| run: | | |
| NPM_VERSION=$(npm --version) | |
| echo "npm version: $NPM_VERSION" | |
| # OIDC trusted publishing requires npm >= 11.5.1. sort -V puts | |
| # versions in ascending order; if the minimum of [NPM_VERSION, 11.5.1] | |
| # is 11.5.1, then NPM_VERSION >= 11.5.1. | |
| LOWEST=$(printf '%s\n%s\n' "$NPM_VERSION" "11.5.1" | sort -V | head -1) | |
| if [ "$LOWEST" != "11.5.1" ]; then | |
| echo "❌ npm $NPM_VERSION is too old for OIDC (need ≥ 11.5.1)" | |
| exit 1 | |
| fi | |
| echo "✅ npm $NPM_VERSION supports OIDC trusted publishing" | |
| - name: Build all packages | |
| run: npm run build | |
| - name: Reset npm auth config (OIDC prerequisite) | |
| # actions/setup-node@v4 writes a placeholder `_authToken=XXXXX-XXXXX-XXXXX-XXXXX` | |
| # into the user .npmrc (expected to be overridden at publish time via | |
| # NODE_AUTH_TOKEN env). npm CLI picks it up as a bearer token and never | |
| # attempts OIDC — publishing silently 404s at /oidc/token/exchange. The | |
| # safest fix is to wipe the user .npmrc entirely and recreate it with | |
| # only the registry URL. | |
| run: | | |
| set -euo pipefail | |
| NPMRC="${NPM_CONFIG_USERCONFIG:-$HOME/.npmrc}" | |
| rm -f "$NPMRC" "$HOME/.npmrc" | |
| mkdir -p "$(dirname "$NPMRC")" | |
| printf 'registry=https://registry.npmjs.org/\n' > "$NPMRC" | |
| # OIDC Trusted Publishing: npm CLI automatically uses id-token for auth. | |
| # No NPM_TOKEN needed! Provenance is published automatically. | |
| # | |
| # REQUIRES on npm side (per package): | |
| # Settings → Publishing access → Trusted Publisher | |
| # Publisher: GitHub Actions | |
| # Organization or user: FractalizeR (case-sensitive!) | |
| # Repository: mcp_servers | |
| # Workflow filename: release.yml (just the filename, no path) | |
| # Environment name: npm-publish | |
| # | |
| # Common gotcha: Organization is case-sensitive. `fractalizer` lowercase | |
| # silently 404s while OIDC claims carry `FractalizeR` from GitHub. | |
| - name: Publish packages to NPM (OIDC Trusted Publishing) | |
| env: | |
| RELEASE_VERSION: ${{ needs.release.outputs.new_release_version }} | |
| # Override setup-node's placeholder. setup-node@v4 exports | |
| # NODE_AUTH_TOKEN=XXXXX-XXXXX-XXXXX-XXXXX as a literal placeholder. | |
| # If npm CLI picks this up from env (independently of .npmrc), it | |
| # treats it as a valid bearer token and never attempts OIDC. | |
| NODE_AUTH_TOKEN: '' | |
| run: | | |
| set -euo pipefail | |
| # Packages published in dependency order: | |
| # framework (infrastructure → cli/core → search) | |
| # → scoped servers → unscoped wrappers | |
| PACKAGES=( | |
| "@fractalizer/mcp-infrastructure" | |
| "@fractalizer/mcp-cli" | |
| "@fractalizer/mcp-core" | |
| "@fractalizer/mcp-search" | |
| "@fractalizer/mcp-server-yandex-tracker" | |
| "@fractalizer/mcp-server-yandex-wiki" | |
| "@fractalizer/mcp-server-ticktick" | |
| "mcp-server-yandex-tracker" | |
| "mcp-server-yandex-wiki" | |
| "mcp-server-ticktick" | |
| ) | |
| TOTAL=${#PACKAGES[@]} | |
| echo "📦 Publishing $TOTAL packages @ $RELEASE_VERSION" | |
| echo "🔐 Using GitHub OIDC (no NPM_TOKEN)" | |
| echo "" | |
| # Phase 1: publish (idempotent — skip if already on registry) | |
| for i in "${!PACKAGES[@]}"; do | |
| PKG="${PACKAGES[$i]}" | |
| NUM=$((i + 1)) | |
| printf "[%d/%d] %s@%s ... " "$NUM" "$TOTAL" "$PKG" "$RELEASE_VERSION" | |
| if npm view "$PKG@$RELEASE_VERSION" version \ | |
| --registry=https://registry.npmjs.org/ >/dev/null 2>&1; then | |
| echo "already published, skipping" | |
| continue | |
| fi | |
| echo "publishing..." | |
| # No `||` masking: any failure aborts the job (set -e). | |
| npm publish --workspace="$PKG" --access public | |
| echo " ✅ published" | |
| done | |
| # Phase 2: verify all versions are visible on registry with retry. | |
| # npm publish may take a few seconds to propagate; downstream jobs | |
| # (build-mcpb) need packages resolvable before they `npm ci`. | |
| echo "" | |
| echo "🔍 Verifying propagation on registry (timeout 60s per package)..." | |
| for PKG in "${PACKAGES[@]}"; do | |
| printf " %s@%s ... " "$PKG" "$RELEASE_VERSION" | |
| for attempt in 1 2 3 4 5 6 7 8 9 10 11 12; do | |
| if npm view "$PKG@$RELEASE_VERSION" version \ | |
| --registry=https://registry.npmjs.org/ >/dev/null 2>&1; then | |
| echo "ok" | |
| break | |
| fi | |
| if [ "$attempt" = "12" ]; then | |
| echo "NOT VISIBLE after 12 attempts (60s)" | |
| exit 1 | |
| fi | |
| sleep 5 | |
| done | |
| done | |
| echo "" | |
| echo "✅ All $TOTAL packages published and verified @ $RELEASE_VERSION" | |
| # Job 3: Build MCPB bundles for all servers and attach to GitHub release | |
| # Note: Depends on publish-npm to ensure internal dependencies are available on npm registry | |
| build-mcpb: | |
| name: Build MCPB Bundles | |
| needs: [release, publish-npm] | |
| runs-on: ubuntu-latest | |
| if: needs.release.outputs.new_release_published == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: v${{ needs.release.outputs.new_release_version }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22.x' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| # publish-npm verifies each package is visible on registry before | |
| # completing, so no extra propagation wait is needed here. | |
| run: npm ci | |
| - name: Build all packages first | |
| run: npm run build | |
| - name: Build all MCPB bundles | |
| # No `||` masking: any MCPB build failure aborts the job. | |
| run: | | |
| set -euo pipefail | |
| echo "📦 Building MCPB bundles for all servers..." | |
| npm run build:mcpb --workspace=@fractalizer/mcp-server-yandex-tracker | |
| npm run build:mcpb --workspace=@fractalizer/mcp-server-yandex-wiki | |
| npm run build:mcpb --workspace=@fractalizer/mcp-server-ticktick | |
| - name: Rename and upload MCPB files | |
| run: | | |
| VERSION="${{ needs.release.outputs.new_release_version }}" | |
| UPLOAD_FILES="" | |
| # Yandex Tracker | |
| YT_FILE=$(ls fractalizer_mcp_yandex_tracker-*.mcpb 2>/dev/null | head -n 1) | |
| if [ -n "$YT_FILE" ]; then | |
| mv "$YT_FILE" "mcp-server-yandex-tracker.mcpb" | |
| UPLOAD_FILES="$UPLOAD_FILES mcp-server-yandex-tracker.mcpb" | |
| echo "✅ yandex-tracker MCPB ready" | |
| fi | |
| # Yandex Wiki | |
| YW_FILE=$(ls fractalizer_mcp_yandex_wiki-*.mcpb 2>/dev/null | head -n 1) | |
| if [ -n "$YW_FILE" ]; then | |
| mv "$YW_FILE" "mcp-server-yandex-wiki.mcpb" | |
| UPLOAD_FILES="$UPLOAD_FILES mcp-server-yandex-wiki.mcpb" | |
| echo "✅ yandex-wiki MCPB ready" | |
| fi | |
| # TickTick | |
| TT_FILE=$(ls fractalizer_mcp_ticktick-*.mcpb 2>/dev/null | head -n 1) | |
| if [ -n "$TT_FILE" ]; then | |
| mv "$TT_FILE" "mcp-server-ticktick.mcpb" | |
| UPLOAD_FILES="$UPLOAD_FILES mcp-server-ticktick.mcpb" | |
| echo "✅ ticktick MCPB ready" | |
| fi | |
| if [ -z "$UPLOAD_FILES" ]; then | |
| echo "⚠️ No MCPB files found, skipping upload" | |
| exit 0 | |
| fi | |
| echo "" | |
| echo "📤 Uploading to release v${VERSION}..." | |
| # Upload all MCPB files to GitHub release | |
| gh release upload "v${VERSION}" $UPLOAD_FILES --clobber | |
| echo "✅ All MCPB bundles uploaded!" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Job 4: Notify success | |
| notify-success: | |
| name: Notify Release Success | |
| needs: [release, publish-npm, build-mcpb] | |
| runs-on: ubuntu-latest | |
| if: needs.release.outputs.new_release_published == 'true' | |
| steps: | |
| - name: Success message | |
| run: | | |
| echo "🎉 Release ${{ needs.release.outputs.new_release_version }} completed successfully!" | |
| echo "✅ Semantic Release: version determined and tagged" | |
| echo "✅ NPM packages published with OIDC Trusted Publishing" | |
| echo "✅ Provenance attestations generated automatically" | |
| echo "✅ MCPB bundle attached to release" |