426 lines
16 KiB
YAML
426 lines
16 KiB
YAML
name: Build and Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: 'Version tag (e.g., v1.32.0)'
|
|
required: true
|
|
type: string
|
|
|
|
jobs:
|
|
# ── Build binaries ───────────────────────────────────────────────────────────
|
|
|
|
build-macos:
|
|
runs-on: macos-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache Cargo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: macos-cargo-${{ hashFiles('Cargo.lock') }}
|
|
restore-keys: macos-cargo-
|
|
|
|
- name: Build release binary
|
|
run: cargo build --release
|
|
|
|
- name: Package binary
|
|
run: |
|
|
mkdir -p dist/mcp-mt5-quant-macos
|
|
cp target/release/mt5-quant dist/mcp-mt5-quant-macos/
|
|
cp -r config dist/mcp-mt5-quant-macos/
|
|
cp README.md dist/mcp-mt5-quant-macos/
|
|
cp -r docs dist/mcp-mt5-quant-macos/
|
|
cd dist
|
|
tar -czf mcp-mt5-quant-macos-arm64.tar.gz mcp-mt5-quant-macos
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: macos-binary
|
|
path: dist/mcp-mt5-quant-macos-arm64.tar.gz
|
|
|
|
build-linux:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache Cargo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: linux-cargo-${{ hashFiles('Cargo.lock') }}
|
|
restore-keys: linux-cargo-
|
|
|
|
- name: Build release binary
|
|
run: cargo build --release
|
|
|
|
- name: Package binary
|
|
run: |
|
|
mkdir -p dist/mcp-mt5-quant-linux
|
|
cp target/release/mt5-quant dist/mcp-mt5-quant-linux/
|
|
cp -r config dist/mcp-mt5-quant-linux/
|
|
cp README.md dist/mcp-mt5-quant-linux/
|
|
cp -r docs dist/mcp-mt5-quant-linux/
|
|
cd dist
|
|
tar -czf mcp-mt5-quant-linux-x64.tar.gz mcp-mt5-quant-linux
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: linux-binary
|
|
path: dist/mcp-mt5-quant-linux-x64.tar.gz
|
|
|
|
# ── Cargo Publish ────────────────────────────────────────────────────────────
|
|
|
|
cargo-publish:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache Cargo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: cargo-publish-${{ hashFiles('Cargo.lock') }}
|
|
restore-keys: cargo-publish-
|
|
|
|
- name: Publish to crates.io
|
|
run: cargo publish --no-verify --allow-dirty
|
|
env:
|
|
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
|
|
# ── GitHub Release ───────────────────────────────────────────────────────────
|
|
|
|
release:
|
|
needs: [build-macos, build-linux, cargo-publish]
|
|
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
env:
|
|
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download macOS artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: macos-binary
|
|
path: dist
|
|
|
|
- name: Download Linux artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: linux-binary
|
|
path: dist
|
|
|
|
- name: Create GitHub Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ env.RELEASE_TAG }}
|
|
name: ${{ env.RELEASE_TAG }}
|
|
files: |
|
|
dist/mcp-mt5-quant-macos-arm64.tar.gz
|
|
dist/mcp-mt5-quant-linux-x64.tar.gz
|
|
draft: false
|
|
prerelease: false
|
|
generate_release_notes: true
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
# ── MCP Package ──────────────────────────────────────────────────────────────
|
|
# Builds the installable MCP package (binary + config + docs),
|
|
# computes its SHA256, and uploads to the release.
|
|
|
|
build-mcp-package:
|
|
needs: release
|
|
runs-on: macos-latest
|
|
permissions:
|
|
contents: write
|
|
outputs:
|
|
sha256: ${{ steps.compute-sha256.outputs.sha256 }}
|
|
env:
|
|
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download macOS binary
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: macos-binary
|
|
path: dist
|
|
|
|
- name: Build MCP package
|
|
run: |
|
|
mkdir -p mcp-package/mcp-server/bin
|
|
cd dist && tar -xzf mcp-mt5-quant-macos-arm64.tar.gz && cd ..
|
|
cp dist/mcp-mt5-quant-macos/mt5-quant mcp-package/mcp-server/bin/
|
|
cp -r config mcp-package/
|
|
cp -r docs mcp-package/
|
|
cp README.md mcp-package/
|
|
cp server.json mcp-package/
|
|
cd mcp-package && tar -czf ../mcp-mt5-quant-macos-arm64.tar.gz . && cd ..
|
|
|
|
- name: Compute SHA256
|
|
id: compute-sha256
|
|
run: |
|
|
SHA256=$(shasum -a 256 mcp-mt5-quant-macos-arm64.tar.gz | awk '{print $1}')
|
|
echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
|
|
echo "MCP Package SHA256: $SHA256"
|
|
|
|
- name: Upload MCP package to release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ env.RELEASE_TAG }}
|
|
files: mcp-mt5-quant-macos-arm64.tar.gz
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Upload MCP package artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: mcp-package
|
|
path: mcp-mt5-quant-macos-arm64.tar.gz
|
|
|
|
# ── Update server.json SHA256 ────────────────────────────────────────────────
|
|
# Commits the computed SHA256 back to master so server.json always
|
|
# reflects the latest published package hash.
|
|
|
|
update-server-json:
|
|
needs: build-mcp-package
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: master
|
|
fetch-depth: 1
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Patch server.json
|
|
env:
|
|
PKG_SHA256: ${{ needs.build-mcp-package.outputs.sha256 }}
|
|
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
|
|
run: |
|
|
VERSION="${RELEASE_TAG#v}"
|
|
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
|
VERSION="$VERSION" PKG_SHA256="$PKG_SHA256" python3 - <<'PYEOF'
|
|
import json, os, re
|
|
|
|
sha256 = os.environ['PKG_SHA256']
|
|
version = os.environ['VERSION']
|
|
|
|
with open('server.json') as f:
|
|
data = json.load(f)
|
|
|
|
data['version'] = version
|
|
for pkg in data.get('packages', []):
|
|
pkg['version'] = version
|
|
pkg['fileSha256'] = sha256
|
|
if 'identifier' in pkg:
|
|
pkg['identifier'] = re.sub(
|
|
r'/v[0-9]+\.[0-9]+\.[0-9]+/',
|
|
f'/v{version}/',
|
|
pkg['identifier']
|
|
)
|
|
|
|
with open('server.json', 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
f.write('\n')
|
|
|
|
print(f"Patched: version={version}, sha256={sha256[:16]}...")
|
|
PYEOF
|
|
|
|
- name: Commit server.json
|
|
run: |
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
git add server.json
|
|
if git diff --cached --quiet; then
|
|
echo "server.json unchanged — no commit needed"
|
|
else
|
|
git commit -m "ci: update server.json SHA256 for v${VERSION} [skip ci]"
|
|
git push origin master
|
|
echo "Committed server.json update"
|
|
fi
|
|
|
|
# ── MCP Registry Publish ─────────────────────────────────────────────────────
|
|
|
|
mcp-publish:
|
|
needs: [build-mcp-package, update-server-json]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
id-token: write # Required for GitHub OIDC
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: master # Pull master so server.json has the correct SHA256
|
|
|
|
- name: Download MCP package
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: mcp-package
|
|
path: .
|
|
|
|
- name: Install mcp-publisher
|
|
id: install-publisher
|
|
run: |
|
|
# Fetch the download URL for linux_amd64 directly from the release assets API
|
|
# (asset name format changed in v1.6.0 — look it up rather than constructing it)
|
|
URL=$(curl -sf \
|
|
-H "Accept: application/vnd.github+json" \
|
|
"https://api.github.com/repos/modelcontextprotocol/registry/releases/latest" \
|
|
| python3 -c "
|
|
import sys, json
|
|
r = json.load(sys.stdin)
|
|
tag = r['tag_name']
|
|
assets = r.get('assets', [])
|
|
match = next((a['browser_download_url'] for a in assets
|
|
if 'linux' in a['name'] and 'amd64' in a['name']
|
|
and a['name'].endswith('.tar.gz')
|
|
and 'sbom' not in a['name']
|
|
and 'sigstore' not in a['name']), None)
|
|
if match:
|
|
print(match)
|
|
else:
|
|
print(f'https://github.com/modelcontextprotocol/registry/releases/download/{tag}/mcp-publisher_linux_amd64.tar.gz', file=sys.stderr)
|
|
sys.exit(1)
|
|
" 2>/dev/null)
|
|
|
|
if [[ -z "$URL" ]]; then
|
|
echo "installed=false" >> "$GITHUB_OUTPUT"
|
|
echo "Could not resolve mcp-publisher download URL"
|
|
else
|
|
echo "Downloading: $URL"
|
|
if curl -fsSL -o mcp-publisher.tar.gz "$URL"; then
|
|
tar -xzf mcp-publisher.tar.gz 2>/dev/null || true
|
|
BINARY=$(find . -maxdepth 3 -name "mcp-publisher" ! -path "./.git/*" | head -1)
|
|
if [[ -n "$BINARY" && -f "$BINARY" ]]; then
|
|
chmod +x "$BINARY"
|
|
sudo mv "$BINARY" /usr/local/bin/mcp-publisher
|
|
echo "installed=true" >> "$GITHUB_OUTPUT"
|
|
echo "Installed: $(mcp-publisher --version 2>/dev/null || echo 'ok')"
|
|
else
|
|
echo "installed=false" >> "$GITHUB_OUTPUT"
|
|
echo "Binary not found in archive"
|
|
fi
|
|
rm -f mcp-publisher.tar.gz
|
|
else
|
|
echo "installed=false" >> "$GITHUB_OUTPUT"
|
|
echo "Download failed: $URL"
|
|
fi
|
|
fi
|
|
|
|
- name: Validate server.json before publish
|
|
id: validate
|
|
run: |
|
|
python3 - <<'PYEOF'
|
|
import json, sys
|
|
|
|
with open('server.json') as f:
|
|
data = json.load(f)
|
|
|
|
print(f" name: {data.get('name')}")
|
|
print(f" version: {data.get('version')}")
|
|
|
|
ok = True
|
|
for pkg in data.get('packages', []):
|
|
sha = pkg.get('fileSha256', '')
|
|
ident = pkg.get('identifier', '')
|
|
print(f" sha256: {sha}")
|
|
print(f" url: {ident}")
|
|
if sha in ('', 'TBD_CI_WILL_UPDATE', 'TBD_UPDATED_BY_CI'):
|
|
print('ERROR: fileSha256 is a placeholder — publish aborted')
|
|
ok = False
|
|
|
|
sys.exit(0 if ok else 1)
|
|
PYEOF
|
|
|
|
- name: Publish to MCP Registry
|
|
if: steps.install-publisher.outputs.installed == 'true' && steps.validate.outcome == 'success'
|
|
run: |
|
|
echo "=== Authenticating with GitHub OIDC ==="
|
|
mcp-publisher login github-oidc || {
|
|
echo "OIDC login failed"
|
|
exit 1
|
|
}
|
|
|
|
echo "=== Publishing ==="
|
|
mcp-publisher publish && echo "✓ Published to MCP Registry" || {
|
|
echo ""
|
|
echo "══════════════════════════════════════════════════════════"
|
|
echo " AUTOMATED MCP PUBLISH FAILED — manual steps:"
|
|
echo "══════════════════════════════════════════════════════════"
|
|
echo " 1. Download: https://github.com/modelcontextprotocol/registry/releases"
|
|
echo " 2. ./mcp-publisher login github"
|
|
echo " 3. ./mcp-publisher publish"
|
|
echo " Web UI: https://registry.modelcontextprotocol.io"
|
|
echo "══════════════════════════════════════════════════════════"
|
|
exit 0 # Don't fail the workflow — release succeeded
|
|
}
|
|
|
|
- name: Skip notice
|
|
if: steps.install-publisher.outputs.installed != 'true'
|
|
run: |
|
|
echo "mcp-publisher not installed — skipping automated publish"
|
|
echo "Manual: https://registry.modelcontextprotocol.io"
|
|
|
|
# ── Release Summary ──────────────────────────────────────────────────────────
|
|
|
|
release-info:
|
|
needs: [mcp-publish]
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
|
|
steps:
|
|
- name: Summary
|
|
run: |
|
|
echo ""
|
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
echo "║ Release ${RELEASE_TAG} complete! "
|
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
echo ""
|
|
echo "GitHub Release:"
|
|
echo " https://github.com/masdevid/mt5-quant/releases/tag/${RELEASE_TAG}"
|
|
echo ""
|
|
echo "MCP Registry: io.github.masdevid/mt5-quant"
|
|
echo ""
|
|
echo "── MCP Client Registration ──────────────────────────────────"
|
|
echo ""
|
|
echo "Claude Code:"
|
|
echo " claude mcp add io.github.masdevid/mt5-quant -- ~/.local/bin/mt5-quant"
|
|
echo ""
|
|
echo "Windsurf (~/.codeium/windsurf/mcp_config.json):"
|
|
echo ' {"mcpServers": {"io.github.masdevid/mt5-quant": {"command": "~/.local/bin/mt5-quant"}}}'
|
|
echo ""
|
|
echo "Cursor / VS Code (~/.cursor/mcp.json):"
|
|
echo ' {"mcpServers": {"mt5-quant": {"command": "~/.local/bin/mt5-quant"}}}'
|
|
echo ""
|
|
echo "─────────────────────────────────────────────────────────────"
|