Skip to content

Release 0.3.10: fit_time_series + demo gallery wave 2 #56

Release 0.3.10: fit_time_series + demo gallery wave 2

Release 0.3.10: fit_time_series + demo gallery wave 2 #56

Workflow file for this run

name: Release
# Triggered by pushing a version tag. Builds wheel + sdist + standalone
# Windows .exe and publishes to PyPI (via trusted publishing) plus the
# GitHub Release for the tag. See spec §13 Phase 6.
#
# Setup once before the first real release:
# 1. Create a PyPI project (https://pypi.org/manage/account/publishing/)
# and add a trusted publisher pointing at this repo + this workflow
# under the environment name "pypi". No tokens to manage.
# 2. (Optional) Create a separate "test-pypi" trusted publisher if you
# want to dry-run with `*.dev*` tags.
on:
push:
tags:
- "v*.*.*"
- "v*.*.*-*"
permissions: {}
jobs:
build-wheel:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
wheel: ${{ steps.find.outputs.wheel }}
sdist: ${{ steps.find.outputs.sdist }}
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true
- name: Set up Python 3.13
run: uv python install 3.13
- name: Build wheel and sdist
run: uv build
- name: Find artifact filenames
id: find
shell: bash
run: |
wheel=$(ls dist/*.whl | head -n 1)
sdist=$(ls dist/*.tar.gz | head -n 1)
echo "wheel=$wheel" >> "$GITHUB_OUTPUT"
echo "sdist=$sdist" >> "$GITHUB_OUTPUT"
- name: Upload Python artifacts
uses: actions/upload-artifact@v4
with:
name: python-distributions
path: dist/*
build-windows-exe:
runs-on: windows-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true
- name: Set up Python 3.13
run: uv python install 3.13
- name: Install dependencies (incl. dev for pyinstaller)
run: uv sync --extra dev
- name: Build single-file .exe
run: uv run pyinstaller modelrisk_mcp.spec --clean --noconfirm
- name: Verify .exe boots and answers MCP initialize
shell: bash
run: |
INIT='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"ci","version":"0.1"}}}'
OUT=$(echo "$INIT" | timeout 15 ./dist/modelrisk-mcp.exe || true)
echo "$OUT"
echo "$OUT" | grep -q '"serverInfo"' || (echo "exe did not return a serverInfo block" && exit 1)
echo "$OUT" | grep -q '"modelrisk-mcp"' || (echo "exe did not identify as modelrisk-mcp" && exit 1)
- name: Scan exe for plain activation key
shell: bash
run: |
uv run python scripts/scan_exe_for_key.py dist/modelrisk-mcp.exe
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: windows-exe
path: dist/modelrisk-mcp.exe
- name: Build .mcpb Desktop Extension
# Wrap the standalone exe in a one-click Claude Desktop Extension
# bundle. Version is injected from the tag so it matches the release.
shell: bash
run: |
uv run python scripts/build_mcpb.py dist/modelrisk-mcp.exe "${GITHUB_REF_NAME#v}" dist/modelrisk-mcp.mcpb
- name: Upload .mcpb Desktop Extension
uses: actions/upload-artifact@v4
with:
name: mcpb-bundle
path: dist/modelrisk-mcp.mcpb
publish-pypi:
needs: build-wheel
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write # for PyPI trusted publishing
steps:
- name: Download Python artifacts
uses: actions/download-artifact@v4
with:
name: python-distributions
path: dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
publish-mcp-registry:
# PyPI must publish first — the registry verifies ownership by
# fetching the package's README from PyPI and looking for the
# `mcp-name: <server-name>` marker. If PyPI doesn't have the new
# version yet the verification fails.
needs: publish-pypi
runs-on: ubuntu-latest
permissions:
id-token: write # for GitHub OIDC against the registry
contents: read
steps:
# Bug #37 (alpha.38): the alpha.37 release hit a transient
# GitHub auth outage that caused `actions/checkout@v4` to fail
# three times in a row with "fatal: could not read Username".
# The retried attempts inside the action all hit the same blip.
# PyPI publish for that tag succeeded; only the registry step
# was lost. Hardening: try checkout up to 3 times across
# separate step invocations (which re-trigger token issuance),
# and only treat the last attempt as fatal. Cheap insurance
# against a class of outage we hit at least once already.
- name: Checkout (attempt 1)
id: co1
uses: actions/checkout@v4
continue-on-error: true
- name: Checkout (attempt 2, 30s later)
if: steps.co1.outcome == 'failure'
id: co2
uses: actions/checkout@v4
continue-on-error: true
- name: Sleep before final checkout attempt
if: steps.co1.outcome == 'failure' && steps.co2.outcome == 'failure'
run: sleep 30
- name: Checkout (attempt 3, fatal if it fails)
if: steps.co1.outcome == 'failure' && steps.co2.outcome == 'failure'
uses: actions/checkout@v4
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz" \
| tar xz mcp-publisher
chmod +x mcp-publisher
- name: Sync server.json version to the release tag
# server.json's version is otherwise hand-maintained and easy to
# forget; if it lags pyproject the registry rejects the publish as
# "cannot publish duplicate version" (happened on v0.3.3). Derive it
# from the tag (vX.Y.Z -> X.Y.Z) so the manifest always matches what
# PyPI just published — no manual bump required. Edits the CI
# workspace copy only; not committed back.
run: |
VERSION="${GITHUB_REF_NAME#v}"
echo "Setting server.json version to $VERSION"
jq --arg v "$VERSION" '.version = $v | .packages[].version = $v' server.json > server.json.tmp
mv server.json.tmp server.json
cat server.json
- name: Wait for PyPI to surface the new version
# PyPI's CDN can take 30-60s to make a freshly-published
# version visible to the registry's verifier. Give it room.
run: sleep 60
- name: Authenticate to the MCP Registry (GitHub OIDC, with retry)
# Same outage class as the checkout case — wrap in a shell
# retry loop so a single transient OIDC failure doesn't lose
# the registry update for this tag.
run: |
for i in 1 2 3; do
if ./mcp-publisher login github-oidc; then
exit 0
fi
echo "Login attempt $i failed; sleeping 20s"
sleep 20
done
echo "All 3 login attempts failed"
exit 1
- name: Publish server.json to the MCP Registry (with retry)
run: |
for i in 1 2 3; do
if ./mcp-publisher publish; then
exit 0
fi
echo "Publish attempt $i failed; sleeping 30s"
sleep 30
done
echo "All 3 publish attempts failed"
exit 1
github-release:
needs: [build-wheel, build-windows-exe]
runs-on: ubuntu-latest
permissions:
contents: write # to upload release assets
steps:
- uses: actions/checkout@v4
- name: Download Python artifacts
uses: actions/download-artifact@v4
with:
name: python-distributions
path: artifacts/python
- name: Download Windows artifact
uses: actions/download-artifact@v4
with:
name: windows-exe
path: artifacts/windows
- name: Download .mcpb Desktop Extension
uses: actions/download-artifact@v4
with:
name: mcpb-bundle
path: artifacts/mcpb
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
body_path: CHANGELOG.md
files: |
artifacts/python/*
artifacts/windows/modelrisk-mcp.exe
artifacts/mcpb/modelrisk-mcp.mcpb
generate_release_notes: false
prerelease: ${{ contains(github.ref_name, '-') }}