Merge pull request #725 from ayush99336/deduplicate-breakpoint-promotion #795
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, CI/CD ] | |
| tags-ignore: [ 'v*' ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| env: | |
| CARGO_TERM_COLOR: always | |
| # Treat *all* compiler warnings as errors across CI (tests/build/bench), including deprecated API usage. | |
| # This is intentionally stricter than clippy alone; contributors must keep the codebase warning-free. | |
| RUSTFLAGS: "-D warnings" | |
| jobs: | |
| check: | |
| name: Compile Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Docs guard (single canonical contributor guide) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| test -f CONTRIBUTING.md | |
| if [[ -f CONTRIBUTION.md ]]; then | |
| lines="$(wc -l < CONTRIBUTION.md | tr -d ' ')" | |
| if [[ "$lines" -gt 20 ]]; then | |
| echo "CONTRIBUTION.md must remain a short redirect stub (<= 20 lines)." | |
| exit 1 | |
| fi | |
| grep -qi "deprecated" CONTRIBUTION.md | |
| grep -q "CONTRIBUTING.md" CONTRIBUTION.md | |
| fi | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Rust Cache | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Cargo Check | |
| run: cargo check --workspace --all-features | |
| test: | |
| name: Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| needs: check | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Rust Cache | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Run Tests | |
| run: cargo test --workspace --all-features | |
| vscode-extension: | |
| name: VS Code Extension | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| cache-dependency-path: extensions/vscode/package-lock.json | |
| # Using our new Makefile target here | |
| - name: Build and Test Extension | |
| run: make test-vscode | |
| - name: Install extension dependencies | |
| run: npm --prefix extensions/vscode ci | |
| - name: Run extension smoke tests | |
| run: npm --prefix extensions/vscode run test:smoke | |
| - name: Run extension DAP E2E tests | |
| run: npm --prefix extensions/vscode run test:dap-e2e | |
| lint: | |
| name: Lint (Clippy & Format) | |
| runs-on: ubuntu-latest | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy, rustfmt | |
| # Using our Makefile targets for consistency | |
| - name: Check Formatting | |
| run: make fmt | |
| - name: Run Clippy | |
| run: make lint | |
| bench: | |
| name: Benchmark Regression Check | |
| runs-on: ubuntu-latest | |
| needs: check | |
| env: | |
| BENCH_WARN_PCT: 10 | |
| BENCH_FAIL_PCT: 20 | |
| # Criterion sampling knobs (tune if CI is too noisy/slow) | |
| BENCH_SAMPLE_SIZE: 20 | |
| BENCH_MEASUREMENT_TIME: 5 | |
| BENCH_WARMUP_TIME: 2 | |
| BENCH_BASE_WORKTREE: /tmp/bench-base-${{ github.run_id }}-${{ github.run_attempt }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Needed to benchmark origin/main in a detached worktree | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Install critcmp | |
| run: cargo install critcmp --version 0.1.7 | |
| - name: Restore benchmark baseline (from default branch) | |
| if: github.event_name == 'pull_request' | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: .bench/baseline.json | |
| key: bench-baseline-${{ runner.os }}-${{ github.sha }} | |
| restore-keys: | | |
| bench-baseline-${{ runner.os }}- | |
| - name: Verify benchmark script isolation behavior | |
| shell: bash | |
| run: bash scripts/test_benchmark_regressions.sh | |
| - name: Run benchmark regression check | |
| shell: bash | |
| run: bash scripts/check_benchmark_regressions.sh | |
| - name: Run benchmarks (current) | |
| run: cargo bench --benches -- --noplot --sample-size $BENCH_SAMPLE_SIZE --measurement-time $BENCH_MEASUREMENT_TIME --warm-up-time $BENCH_WARMUP_TIME | |
| - name: Add main branch worktree for baseline | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Preparing baseline worktree at: $BENCH_BASE_WORKTREE" | |
| git worktree list --porcelain || true | |
| git worktree add "$BENCH_BASE_WORKTREE" main | |
| git worktree list --porcelain || true | |
| - name: Run benchmarks (baseline on main) | |
| working-directory: ${{ env.BENCH_BASE_WORKTREE }} | |
| env: | |
| CARGO_TARGET_DIR: ${{ github.workspace }}/target | |
| run: cargo bench -- --save-baseline base --noplot | |
| - name: Remove main branch worktree | |
| if: always() | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Cleaning baseline worktree at: $BENCH_BASE_WORKTREE" | |
| git worktree list --porcelain || true | |
| if git worktree remove --force "$BENCH_BASE_WORKTREE"; then | |
| echo "Removed baseline worktree cleanly" | |
| else | |
| echo "worktree remove failed; running prune/remove fallback" | |
| git worktree prune --expire now || true | |
| rm -rf "$BENCH_BASE_WORKTREE" || true | |
| fi | |
| git worktree list --porcelain || true | |
| - name: Record current results (JSON) | |
| run: cargo run --quiet --bin bench-regression -- record --criterion target/criterion --out .bench/current.json | |
| - name: Compare against baseline (pass/warn/fail) | |
| if: github.event_name == 'pull_request' | |
| shell: bash | |
| run: | | |
| set -e | |
| report="$(cargo run --quiet --bin bench-regression -- compare \ | |
| --baseline .bench/baseline.json \ | |
| --current .bench/current.json \ | |
| --warn-pct "$BENCH_WARN_PCT" \ | |
| --fail-pct "$BENCH_FAIL_PCT" \ | |
| --annotate-top 20 \ | |
| --max-rows 50 \ | |
| --require-baseline false)" | |
| echo "$report" | |
| echo "$report" >> "$GITHUB_STEP_SUMMARY" | |
| - name: Update baseline on main | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| run: | | |
| mkdir -p .bench | |
| cp .bench/current.json .bench/baseline.json | |
| - name: Save baseline cache (main only) | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: .bench/baseline.json | |
| key: bench-baseline-${{ runner.os }}-${{ github.sha }} | |
| - name: Upload baseline artifact (main only) | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: bench-baseline-${{ runner.os }} | |
| path: .bench/baseline.json | |
| check-manpages: | |
| name: Check man page sync | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Check man pages are up to date | |
| run: make check-man | |
| coverage: | |
| name: Code Coverage | |
| runs-on: ubuntu-latest | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Rust Cache | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Install cargo-llvm-cov | |
| uses: taiki-e/install-action@cargo-llvm-cov | |
| - name: Generate coverage report | |
| run: cargo llvm-cov --workspace --all-features --lcov --output-path lcov.info | |
| - name: Check coverage threshold | |
| id: coverage | |
| run: | | |
| set -euo pipefail | |
| # Use JSON output: structured and stable across cargo-llvm-cov versions | |
| summary_json=$(cargo llvm-cov --workspace --all-features --json --summary-only 2>&1) | |
| echo "$summary_json" | |
| # Parse and validate required schema fields through the shared script helper. | |
| coverage="$(printf '%s' "$summary_json" | bash scripts/check_benchmark_regressions.sh coverage-percent-from-json)" | |
| coverage_pct=$(printf "%.2f" "$coverage") | |
| echo "Current coverage: ${coverage_pct}%" | |
| echo "Required threshold: 50%" | |
| echo "coverage=${coverage_pct}" >> "$GITHUB_OUTPUT" | |
| meets_threshold=$(awk -v cov="$coverage" -v thresh="50" 'BEGIN {print (cov >= thresh)}') | |
| if [ "$meets_threshold" = "0" ]; then | |
| echo "Coverage ${coverage_pct}% is below the required 50% threshold" | |
| exit 1 | |
| else | |
| echo "Coverage ${coverage_pct}% meets the required 50% threshold" | |
| fi | |
| - name: Validate coverage parser on missing required field | |
| shell: bash | |
| run: bash scripts/check_benchmark_regressions.sh selftest-coverage-missing-field | |
| - name: Upload to Codecov | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| file: ./lcov.info | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| - name: Comment PR | |
| if: github.event_name == 'pull_request' | |
| uses: marocchino/sticky-pull-request-comment@v2 | |
| with: | |
| recreate: true | |
| message: | | |
| ## Code Coverage Report | |
| **Coverage: ${{ steps.coverage.outputs.coverage }}%** (Required: 50%) | |
| View the full coverage report on [Codecov](https://codecov.io/gh/${{ github.repository }}/commit/${{ github.sha }}). | |
| Coverage details are available in the [CI logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}). |