Release v1.3.0: name the model behind every sentiment score #14
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 container image to GHCR | |
| # Builds the remote-HTTP (`node server/index.js --http`) image OFF-host on | |
| # GitHub-hosted runners and pushes it to GHCR, so the single-CPU IWAC-docker host | |
| # only ever does a lightweight `docker pull` (no on-host build contention). | |
| # | |
| # Triggers on a version tag (v*), or manually. Version tags also publish the | |
| # Claude Desktop / stdio .mcpb bundles and the .agents research skill zip as | |
| # GitHub release assets, then publish the server to the official MCP Registry | |
| # (registry.modelcontextprotocol.io) as io.github.fmadore/iwac-mcp-server. | |
| # | |
| # Ordering is deliberate: typecheck + lint + the full hermetic test suite run | |
| # FIRST, then the release assets are packed, then the image is smoke-tested in a | |
| # container, and only THEN is anything pushed. A red test or a broken pack | |
| # script can no longer ship an image (previously the image — including | |
| # `latest` — was pushed before any verification ran, and no tests ran on the | |
| # tag path at all). | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} # fmadore/iwac-mcp-server | |
| # Single source of truth for the Node major used to build and test releases. | |
| # Keep in step with ci.yml, mcpb/Dockerfile and mcpb/package.json `engines`. | |
| # NOTE: this is the BUILD baseline only. The shipped .mcpb still targets | |
| # node18 (scripts/bundle.mjs) and declares `runtimes.node: ">=18.0.0"` | |
| # (manifest.json), because Claude Desktop runs the extension on its OWN | |
| # bundled Node — raising that floor without knowing Desktop's version would | |
| # stop the extension installing. Those two move together, or not at all. | |
| NODE_VERSION: 24 | |
| # Pin a specific mcp-publisher release (e.g. "v1.4.0") for reproducible, | |
| # supply-chain-safer publishes; "latest" keeps the old auto-tracking | |
| # behaviour. TODO: set a concrete version after checking | |
| # https://github.com/modelcontextprotocol/registry/releases. | |
| MCP_PUBLISHER_VERSION: latest | |
| jobs: | |
| build-and-push: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| packages: write | |
| id-token: write # MCP Registry publish via GitHub OIDC (no secret needed) | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Set up Node | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: npm | |
| cache-dependency-path: mcpb/package-lock.json | |
| - name: Install dependencies | |
| working-directory: mcpb | |
| run: npm ci | |
| # Release gate: the same hermetic suite ci.yml runs on PRs. Nothing below | |
| # (image push, release assets, registry publish) happens if this fails. | |
| - name: Typecheck, lint, build, and test | |
| working-directory: mcpb | |
| run: | | |
| npm run typecheck | |
| npm run lint | |
| npm run build | |
| npm test | |
| - name: Check tag matches package.json/manifest.json versions | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| node -e ' | |
| const fs = require("fs"); | |
| const tag = process.env.TAG.replace(/^v/, ""); | |
| const pkg = JSON.parse(fs.readFileSync("mcpb/package.json", "utf8")).version; | |
| const man = JSON.parse(fs.readFileSync("mcpb/manifest.json", "utf8")).version; | |
| if (tag !== pkg || tag !== man) { | |
| console.error(`version mismatch: tag ${tag}, package.json ${pkg}, manifest.json ${man}`); | |
| process.exit(1); | |
| } | |
| console.log(`versions consistent: ${tag}`); | |
| ' | |
| - name: Build MCPB and skill release assets | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| working-directory: mcpb | |
| run: npm run release | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v4.5.2 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Derive image tags and labels | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| # `latest` only moves on version tags — a manual workflow_dispatch | |
| # from a branch must not repoint it. | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} | |
| type=sha,format=short | |
| - name: Build image (local, for smoke test) | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: mcpb | |
| file: mcpb/Dockerfile | |
| platforms: linux/amd64 | |
| load: true | |
| tags: iwac-mcp-smoke:ci | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # The Dockerfile's own comment says "a missing binding is a runtime crash, | |
| # not a build error" — so actually boot the container before pushing: | |
| # /health must come up, and /mcp must enforce the bearer token. | |
| - name: Container smoke test | |
| run: | | |
| docker run -d --rm --name iwac-smoke \ | |
| -e IWAC_MCP_BEARER_TOKEN=ci-smoke -p 8000:8000 iwac-mcp-smoke:ci | |
| ok="" | |
| for i in $(seq 1 30); do | |
| if curl -fsS http://127.0.0.1:8000/health >/dev/null 2>&1; then ok=1; break; fi | |
| sleep 1 | |
| done | |
| if [ -z "$ok" ]; then | |
| echo "container never became healthy"; docker logs iwac-smoke || true; exit 1 | |
| fi | |
| code=$(curl -s -o /dev/null -w '%{http_code}' -X POST http://127.0.0.1:8000/mcp) | |
| if [ "$code" != "401" ]; then | |
| echo "expected 401 without bearer token, got $code"; exit 1 | |
| fi | |
| docker stop iwac-smoke | |
| - name: Push image (linux/amd64) | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: mcpb | |
| file: mcpb/Dockerfile | |
| platforms: linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Upload GitHub release assets | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| gh release view "$TAG" >/dev/null 2>&1 || gh release create "$TAG" --title "$TAG" --notes "Release $TAG" | |
| gh release upload "$TAG" \ | |
| mcpb/iwac-mcp-server-windows.mcpb \ | |
| mcpb/iwac-mcp-server-macos.mcpb \ | |
| iwac-mcp-skill.zip \ | |
| --clobber | |
| # MCP Registry publish. server.json is generated HERE, in the same job | |
| # that packed and uploaded the .mcpb assets, so the embedded fileSha256 | |
| # hashes always match the exact uploaded bytes. Registry versions are | |
| # immutable: re-running this workflow for an already-published tag fails | |
| # at this step by design (re-packed zips hash differently) — bump the | |
| # version instead of re-publishing. | |
| - name: Generate server.json | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| TAG: ${{ github.ref_name }} | |
| run: node mcpb/scripts/make-server-json.mjs "$TAG" | |
| - name: Install mcp-publisher | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| run: | | |
| os=$(uname -s | tr '[:upper:]' '[:lower:]') | |
| arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') | |
| if [ "$MCP_PUBLISHER_VERSION" = "latest" ]; then | |
| url="https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_${os}_${arch}.tar.gz" | |
| else | |
| url="https://github.com/modelcontextprotocol/registry/releases/download/${MCP_PUBLISHER_VERSION}/mcp-publisher_${os}_${arch}.tar.gz" | |
| fi | |
| curl -fL "$url" | tar xz mcp-publisher | |
| - name: Publish to MCP Registry | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| run: | | |
| ./mcp-publisher login github-oidc | |
| ./mcp-publisher publish |