mirror of
https://github.com/sbroenne/mcp-server-excel.git
synced 2026-09-19 07:53:08 +08:00
5eafcbfc8f
Co-authored-by: Stefan Broenner <stbrnner@microsoft.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
207 lines
8.3 KiB
YAML
207 lines
8.3 KiB
YAML
# CI Gate — the authoritative status checks for pull requests.
|
|
#
|
|
# Both jobs ALWAYS run on every PR to `main` (no path filters), so they can be
|
|
# safely marked as required status checks without the "required check never
|
|
# runs on path-filtered PRs" deadlock.
|
|
#
|
|
# `Docs Site` builds and audits the MkDocs website. `CI Gate` ports the
|
|
# Excel-free pre-commit gates (scripts/pre-commit.ps1) into CI so
|
|
# that the correctness checks are enforced server-side even if a contributor
|
|
# does not have the local hook installed. The Excel-dependent gates — the CLI
|
|
# workflow smoke test and the MCP smoke test — are intentionally NOT run here:
|
|
# this job uses the GitHub-hosted `windows-latest` runner, which does not have
|
|
# Microsoft Excel installed. Those two gates remain local prerequisites and are
|
|
# explicitly attested in the pull request testing checklist.
|
|
|
|
name: CI Gate
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [ main ]
|
|
push:
|
|
branches: [ main ]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: ci-gate-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# The documentation site is the primary distribution channel for this project
|
|
# (README.md is a landing page that links to excelmcpserver.dev), but until
|
|
# this job existed nothing validated it before merge: the Pages workflow only
|
|
# builds on push to `main`, and scripts/pre-commit.ps1 classifies `docs/`,
|
|
# `gh-pages/` and `*.md` as a docs-only fast path that skips almost every
|
|
# gate. A broken --strict build or audit regression therefore surfaced only
|
|
# after merge, on the deploy run. Runs unfiltered like the CI Gate job below
|
|
# so it can safely be a required check.
|
|
docs:
|
|
name: Docs Site
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
with:
|
|
# hooks.py derives each sitemap <lastmod> from `git log`, so the full
|
|
# history is required. A shallow clone would date every page to the
|
|
# tip commit; audit_site.py fails the build if it detects that.
|
|
fetch-depth: 0
|
|
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v7
|
|
with:
|
|
python-version: '3.13'
|
|
cache: pip
|
|
cache-dependency-path: gh-pages/requirements.txt
|
|
|
|
- name: Install dependencies
|
|
run: pip install -r gh-pages/requirements.txt
|
|
|
|
- name: Build with MkDocs
|
|
working-directory: gh-pages
|
|
run: mkdocs build --strict --clean
|
|
|
|
- name: Audit built site
|
|
working-directory: gh-pages
|
|
run: python audit_site.py
|
|
|
|
# Guards against the deploy workflow's hand-written paths: filter drifting
|
|
# from the canonical sources hooks.py mirrors, which would publish a
|
|
# silently stale site until the nightly cron caught up.
|
|
- name: Verify deploy path filter covers every mirrored source
|
|
working-directory: gh-pages
|
|
run: python check_deploy_paths.py
|
|
|
|
ci-gate:
|
|
name: CI Gate
|
|
runs-on: windows-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Npm lockfile portability regression tests
|
|
timeout-minutes: 2
|
|
shell: pwsh
|
|
run: ./scripts/Test-NpmLockfiles.ps1
|
|
|
|
- name: Npm lockfile portability
|
|
timeout-minutes: 2
|
|
shell: pwsh
|
|
run: ./scripts/check-npm-lockfiles.ps1
|
|
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v6
|
|
with:
|
|
dotnet-version: 10.0.x
|
|
|
|
- name: Restore
|
|
run: dotnet restore Sbroenne.ExcelMcp.sln
|
|
|
|
# Release build validates compilation and runs the source generators, so
|
|
# the audit scripts below see the generated CLI/MCP surface. Mirrors the
|
|
# pre-commit Release build gate (NuGetAudit disabled here — the Dependency
|
|
# Review workflow owns vulnerability scanning).
|
|
- name: Build (Release)
|
|
run: dotnet build Sbroenne.ExcelMcp.sln --configuration Release --no-restore -p:NuGetAudit=false
|
|
|
|
- name: Pre-commit hook regression tests
|
|
run: dotnet test tests/ExcelMcp.SkillGeneration.Tests/ExcelMcp.SkillGeneration.Tests.csproj --configuration Release --no-build --no-restore --filter "Feature=PreCommit" --blame-hang-timeout 60s
|
|
|
|
# --- Excel-free correctness gates (ported from scripts/pre-commit.ps1) ---
|
|
|
|
- name: COM object leak check
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/check-com-leaks.ps1
|
|
if ($LASTEXITCODE -ne 0) { throw "COM object leaks detected. All dynamic COM objects must be released in finally blocks." }
|
|
|
|
- name: Core coverage + naming audit
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/audit-core-coverage.ps1 -CheckNaming -FailOnGaps
|
|
if ($LASTEXITCODE -ne 0) { throw "Coverage or naming gaps detected. Every Core method must be exposed via the MCP Server with a matching name." }
|
|
|
|
- name: MCP actions have Core implementations
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/check-mcp-core-implementations.ps1
|
|
if ($LASTEXITCODE -ne 0) { throw "MCP enum actions without a matching Core Command implementation were found." }
|
|
|
|
- name: Success flag check
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/check-success-flag.ps1
|
|
if ($LASTEXITCODE -ne 0) { throw "Success flag violations detected (Success=true with an ErrorMessage set)." }
|
|
|
|
- name: Shared bootstrap template drift check
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/Build-BootstrapScripts.ps1 -Check
|
|
if ($LASTEXITCODE -ne 0) { throw "Bootstrap drift detected. Regenerate the canonical download.ps1 template output before committing." }
|
|
|
|
- name: Documentation tool/operation counts
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/check-doc-counts.ps1 -SkipBuild
|
|
if ($LASTEXITCODE -ne 0) { throw "A doc advertises a tool/operation count that does not match the code-derived canonical count." }
|
|
|
|
- name: Dynamic cast audit (documented ((dynamic)) casts)
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/check-dynamic-casts.ps1
|
|
if ($LASTEXITCODE -ne 0) { throw "Undocumented ((dynamic)) casts detected. Each cast needs a justification comment." }
|
|
|
|
- name: Plugin README check
|
|
shell: pwsh
|
|
run: |
|
|
& scripts/check-plugin-readmes.ps1
|
|
if ($LASTEXITCODE -ne 0) { throw "Plugin README validation failed." }
|
|
|
|
# --- Excel-free build smoke checks (absorbed from the old Build CLI /
|
|
# Build MCP Server workflows) ---
|
|
|
|
- name: Verify CLI build + help (no Excel required)
|
|
shell: pwsh
|
|
run: |
|
|
$exe = "src/ExcelMcp.CLI/bin/Release/net10.0-windows/excelcli.exe"
|
|
if (-not (Test-Path $exe)) { throw "excelcli.exe not found at $exe" }
|
|
$help = & $exe --help 2>&1
|
|
if ($LASTEXITCODE -ne 0) { throw "excelcli --help failed with exit code $LASTEXITCODE" }
|
|
Write-Host "excelcli --help OK"
|
|
|
|
- name: Verify MCP Server build
|
|
shell: pwsh
|
|
run: |
|
|
$exe = "src/ExcelMcp.McpServer/bin/Release/net10.0-windows/Sbroenne.ExcelMcp.McpServer.exe"
|
|
if (-not (Test-Path $exe)) { throw "MCP Server exe not found at $exe" }
|
|
if (-not (Test-Path "src/ExcelMcp.McpServer/bin/Release/net10.0-windows/.mcp/server.json")) {
|
|
Write-Warning "MCP server.json configuration not found"
|
|
}
|
|
Write-Host "MCP Server build OK"
|
|
|
|
- name: Integration tests note
|
|
shell: pwsh
|
|
run: |
|
|
Write-Host "Full Excel integration tests, the CLI workflow smoke test, and the MCP smoke test all require Microsoft Excel."
|
|
Write-Host "This GitHub-hosted 'windows-latest' runner has no Excel, so this job does not run them."
|
|
Write-Host "Run '& .\scripts\Test-E2E.ps1' locally and attest the result in the pull request testing checklist."
|
|
|
|
- name: Upload CLI build artifacts
|
|
if: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }}
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: ExcelMcp-CLI-${{ github.sha }}
|
|
path: src/ExcelMcp.CLI/bin/Release/net10.0-windows/
|
|
if-no-files-found: error
|
|
|
|
- name: Upload MCP Server build artifacts
|
|
if: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }}
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: ExcelMcp-MCP-Server-${{ github.sha }}
|
|
path: src/ExcelMcp.McpServer/bin/Release/net10.0-windows/
|
|
if-no-files-found: error
|