Repository navigation
fix(javascript): catch the first call of a first-declared function breakpoint and explain a late entry stop (#858) #1792
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: CI | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main ] | |
| # Default types only. Adding 'labeled'/'unlabeled' would re-run the WHOLE | |
| # matrix per label event - Dependabot applies each of its default labels | |
| # twice at creation, so 3-5 simultaneous full runs per bot PR - to fix a | |
| # race the gate itself now avoids by reading labels live (issue #580). | |
| workflow_dispatch: # on-demand run when main lands commits without a push event | |
| # (auto-merge pushes with GITHUB_TOKEN, which suppresses triggers) | |
| permissions: | |
| contents: read | |
| jobs: | |
| build-and-test: | |
| name: Build and Test | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest] | |
| node-version: [22.x] | |
| python-version: ['3.11'] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 | |
| # version comes from package.json "packageManager" (issue #478) | |
| - name: Setup Node.js ${{ matrix.node-version }} | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: 'pnpm' | |
| - name: Setup Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --require-hashes -r requirements/pip.txt | |
| python -m pip install --require-hashes -r requirements/debugpy.txt | |
| - name: Setup Go | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version: '1.21' | |
| - name: Install Delve debugger | |
| run: go install github.com/go-delve/delve/cmd/dlv@v1.24.2 | |
| - name: Setup Java 21 | |
| uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0 | |
| with: | |
| ruby-version: '3.3' | |
| - name: Verify rdbg (bundled debug gem) | |
| run: rdbg --version | |
| - name: Install Node dependencies | |
| run: pnpm install --frozen-lockfile | |
| env: | |
| SKIP_ADAPTER_VENDOR: 'true' | |
| - name: Audit dependencies | |
| run: pnpm audit --prod --audit-level=high | |
| - name: Vendor adapter binaries | |
| run: pnpm run vendor:adapters | |
| continue-on-error: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build project | |
| run: pnpm run build:ci | |
| - name: Run linting | |
| run: pnpm run lint | |
| # The PyPI launcher publishes on every release but previously had zero | |
| # test execution anywhere (issue #641). | |
| - name: Run PyPI launcher unit tests | |
| run: python -m unittest tests.test_commands -v | |
| working-directory: mcp_debugger_launcher | |
| # Use test:ci-coverage which includes Python tests but excludes e2e tests | |
| - name: Run tests with coverage | |
| run: pnpm run test:ci-coverage | |
| env: | |
| CI: true | |
| # Hard-fail on process-listener leaks (issues #159/#183) | |
| LEAK_GUARD_STRICT: '1' | |
| - name: Upload Windows test diagnostics | |
| if: failure() && matrix.os == 'windows-latest' | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: windows-test-diagnostics | |
| path: | | |
| tests/**/*.log | |
| dist/**/*.log | |
| logs/tests/**/*.log | |
| logs/tests/adapters/failures/**/*.json | |
| test-results.json | |
| if-no-files-found: warn | |
| - name: Upload coverage reports | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: matrix.os == 'ubuntu-latest' | |
| with: | |
| name: coverage-report | |
| path: coverage/ | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 | |
| if: matrix.os == 'ubuntu-latest' | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: ./coverage/coverage-final.json | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| windows-python-integration: | |
| name: Windows Python Integration Focus | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 | |
| # version comes from package.json "packageManager" (issue #478) | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 22.x | |
| cache: 'pnpm' | |
| - name: Setup Python 3.11 | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.11' | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --require-hashes -r requirements/pip.txt | |
| python -m pip install --require-hashes -r requirements/debugpy.txt | |
| - name: Setup Java 21 | |
| uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Install Node dependencies | |
| run: pnpm install --frozen-lockfile | |
| env: | |
| SKIP_ADAPTER_VENDOR: 'true' | |
| - name: Build project (CI) | |
| run: pnpm run build:ci | |
| - name: Run targeted Python integration tests | |
| env: | |
| CI: true | |
| run: pnpm vitest run tests/adapters/python/integration/python-discovery.test.ts tests/adapters/python/integration/python_debug_workflow.test.ts | |
| - name: Upload targeted test diagnostics | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: windows-python-integration-logs | |
| path: | | |
| logs/tests/**/*.log | |
| logs/tests/adapters/failures/**/*.json | |
| tests/**/*.log | |
| if-no-files-found: warn | |
| lint: | |
| name: Lint Code | |
| runs-on: ubuntu-latest | |
| # The changelog gate reads the PR's labels live (issue #580); the | |
| # workflow-level token grants contents:read only, which does not cover the | |
| # pull-requests API `gh pr view` calls. | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| # Full history so the changelog gate can diff against the PR base. | |
| fetch-depth: 0 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 | |
| # version comes from package.json "packageManager" (issue #478) | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: '22.x' | |
| cache: 'pnpm' | |
| - name: Setup Java 21 | |
| uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| env: | |
| SKIP_ADAPTER_VENDOR: 'true' | |
| - name: Run ESLint | |
| run: pnpm run lint | |
| # Type-only checks, no build needed: ~3 s for the sources and ~11 s for the ratchet | |
| # (Lint Code goes from ~25 s to ~40 s). `tsc -b -f .` in `build` stays the | |
| # authoritative compile; this catches type errors before the build job does. | |
| # | |
| # Deliberately the same command a developer runs locally and pre-push runs, so a | |
| # green working tree cannot mean a red required check (issue #562). | |
| # Keyed on the PR's AUTHOR, not github.actor: the actor is whoever triggered | |
| # this particular run, so a human reopening a Dependabot PR, running | |
| # `gh pr update-branch` on it, or pushing to the bot branch would take the | |
| # strict path and reproduce the failure the split exists to avoid (#581). | |
| - name: Type-check sources and tests | |
| if: github.event_name != 'pull_request' || github.event.pull_request.user.login != 'dependabot[bot]' | |
| run: pnpm run typecheck:all | |
| # Dependabot cannot re-record the ratchet baseline, so a bump that makes the | |
| # suite type-CLEANER (a better @types package) would otherwise fail its own | |
| # PR on a stale baseline it has no way to refresh. Increases and newly | |
| # erroring files still fail; a decrease warns (issue #581). The ratchet | |
| # raises a ::warning annotation and a job-summary line when that happens, | |
| # because this PR can auto-merge with GITHUB_TOKEN — which suppresses push | |
| # CI on main — leaving the baseline stale until a human PR refreshes it. | |
| - name: Type-check sources and tests (dependabot) | |
| if: github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]' | |
| run: | | |
| pnpm run typecheck | |
| pnpm run typecheck:tests -- --allow-improvement | |
| - name: Check for personal information | |
| run: pnpm run check:all-personal-paths | |
| # Docs here are hand-maintained -- nothing generates them -- so they drift | |
| # silently. This catches the two classes a machine can catch: relative links | |
| # that no longer resolve, and counts that fell behind the code ("28 tools", | |
| # "eight languages"). Everything else still needs a human reviewer. | |
| - name: Check documentation consistency | |
| run: pnpm run check:docs | |
| - name: Validate changelog fragments | |
| run: pnpm run changelog:check | |
| # A user-visible change must carry a changelog fragment, or its entry never | |
| # reaches the release notes (issues #546, #462). Test-only changes are exempt | |
| # automatically; apply the 'no-changelog' label for genuine no-op PRs. | |
| # | |
| # Labels are read LIVE rather than from the event payload: `gh pr create | |
| # --label` applies labels in a follow-up API call, so the payload of the | |
| # 'opened' event this job runs from can still show none, failing a PR that | |
| # was correctly labelled a second later (issue #580). By the time this step | |
| # runs the label is there. A label added LATER still needs a re-run, but | |
| # "Re-run failed jobs" now picks it up instead of needing an empty push. | |
| # `gh pr view` needs only read access, and works for fork PRs. | |
| - name: Require a changelog fragment | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| # Without pipefail the pipeline below reports `paste`'s status, so an | |
| # auth or API failure from `gh` would read as "this PR has no labels" | |
| # and fail the PR for the wrong reason. An unlabelled PR still yields | |
| # an empty string, which is a legitimate answer. | |
| set -o pipefail | |
| CHANGED_FILES="$(git diff --name-only "$BASE_REF...$HEAD_SHA")" | |
| export CHANGED_FILES | |
| PR_LABELS="$(gh pr view "$PR_NUMBER" \ | |
| --repo "$GH_REPO" --json labels -q '.labels[].name' | paste -sd, -)" \ | |
| || { echo "::error::Could not read the PR's labels; refusing to guess."; exit 1; } | |
| export PR_LABELS | |
| echo "Labels read live: ${PR_LABELS:-<none>}" | |
| node scripts/changelog-fragments.mjs --ci | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| # Passed as env rather than spliced into the script body: a branch name is | |
| # attacker-controlled on a fork PR, and `${{ }}` interpolates straight into the | |
| # shell. The gate also reads BASE_REF/HEAD_SHA itself, to diff each changed | |
| # package.json and let a devDependencies-only bump through (issue #629). | |
| BASE_REF: origin/${{ github.base_ref }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| GH_REPO: ${{ github.repository }} | |
| # Separate job for container tests on Linux only | |
| container-tests: | |
| name: Container Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 | |
| # version comes from package.json "packageManager" (issue #478) | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: '22.x' | |
| cache: 'pnpm' | |
| - name: Setup Java 21 | |
| uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| env: | |
| SKIP_ADAPTER_VENDOR: 'true' | |
| - name: Vendor adapter binaries | |
| run: pnpm run vendor:adapters | |
| continue-on-error: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Run linting | |
| run: pnpm run lint | |
| - name: Build project | |
| run: pnpm run build | |
| env: | |
| SKIP_ADAPTER_VENDOR: 'true' | |
| - name: Build Docker image | |
| run: docker build -t mcp-debugger:local . | |
| - name: Run container tests | |
| run: | | |
| mkdir -p artifacts/cobol | |
| pnpm run test:e2e:container --reporter=default --reporter=json --outputFile=artifacts/cobol/container-tests.json | |
| - name: Require both COBOL attach cases to pass | |
| run: | | |
| node --input-type=module <<'NODE' | |
| import { readFileSync } from 'node:fs'; | |
| const report = JSON.parse(readFileSync('artifacts/cobol/container-tests.json', 'utf8')); | |
| const suite = report.testResults?.find(result => result.name.endsWith('/docker-smoke-cobol-attach.test.ts')); | |
| const cases = suite?.assertionResults ?? []; | |
| if (cases.length !== 2 || cases.some(test => test.status !== 'passed')) { | |
| throw new Error('Both COBOL attach cases must pass; missing or skipped cases fail this lane'); | |
| } | |
| console.log('COBOL Linux attach: 2 passed, 0 skipped'); | |
| NODE | |
| - name: Upload container validation evidence | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: cobol-linux-attach | |
| path: artifacts/cobol/ | |
| if-no-files-found: warn | |
| cobol-host: | |
| name: COBOL Host (GnuCOBOL 3.1.2) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: '22.x' | |
| cache: 'pnpm' | |
| - name: Install and verify GnuCOBOL 3.1.2 | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends gnucobol3 | |
| cobc --version | tee /tmp/cobc-version.txt | |
| head -1 /tmp/cobc-version.txt | grep -E '^cobc \(GnuCOBOL\) 3\.1\.2([. ]|$)' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build project | |
| run: pnpm build | |
| - name: Run COBOL host smoke and logpoints | |
| run: | | |
| mkdir -p artifacts/cobol | |
| cp /tmp/cobc-version.txt artifacts/cobol/ | |
| pnpm exec vitest run --project e2e tests/e2e/mcp-server-smoke-cobol.test.ts tests/e2e/mcp-server-logpoints.test.ts -t 'COBOL|\(cobol\)' --reporter=default --reporter=json --outputFile=artifacts/cobol/host-tests.json | |
| node scripts/check-cobol-e2e-report.mjs artifacts/cobol/host-tests.json | |
| - name: Upload COBOL validation evidence | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: cobol-host-312 | |
| path: artifacts/cobol/ | |
| if-no-files-found: warn | |
| test-summary: | |
| name: Test Summary | |
| needs: [build-and-test, windows-python-integration, lint, container-tests, cobol-host] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Check test results | |
| run: | | |
| echo "build-and-test: ${{ needs.build-and-test.result }}" | |
| echo "windows-python-integration: ${{ needs.windows-python-integration.result }}" | |
| echo "lint: ${{ needs.lint.result }}" | |
| echo "container-tests: ${{ needs.container-tests.result }}" | |
| echo "cobol-host: ${{ needs.cobol-host.result }}" | |
| if [ "${{ needs.build-and-test.result }}" != "success" ] \ | |
| || [ "${{ needs.windows-python-integration.result }}" != "success" ] \ | |
| || [ "${{ needs.lint.result }}" != "success" ] \ | |
| || [ "${{ needs.container-tests.result }}" != "success" ] \ | |
| || [ "${{ needs.cobol-host.result }}" != "success" ]; then | |
| echo "❌ One or more required jobs did not succeed" | |
| exit 1 | |
| fi | |
| echo "✅ All required jobs succeeded" |