Skip to content

FEAT: Add PR Performance Report (Profiler) - #779

Open
Gaurav Sharma (bewithgaurav) wants to merge 20 commits into
mainfrom
bewithgaurav/profiler-ci
Open

Gaurav Sharma (bewithgaurav) wants to merge 20 commits into
mainfrom
bewithgaurav/profiler-ci

Conversation

@bewithgaurav

@bewithgaurav Gaurav Sharma (bewithgaurav) commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Work Item / Issue Reference

AB#44819

Follow-up to #552.

Summary

Add an advisory PR Performance Report backed by paired profiler benchmarks across 20 database workloads.

  • Organize benchmark measurement, workloads, validation, and rendering in the source-only eng/profiler_benchmarks package, separate from the runtime profiler and standalone benchmark scripts.
  • Compare the exact base and PR revisions through the same workloads in fresh processes, reusing profiling-enabled candidate builds with recording disabled during pytest.
  • Cover Windows and macOS with SQL Server 2022/2025, plus Ubuntu with SQL Server 2022.
  • Lead the report with the observed performance impact, affected database tasks, and environment coverage. Keep phase diagnostics, all timings, commits, and methodology available in expandable details.
  • Preserve the existing advisory thresholds, paired sampling policy, workloads, time budgets, and sticky-comment identity. Replace the legacy perf-baseline-* artifacts with authenticated per-environment profiler-* artifacts consumed by the new publisher.
  • Execute publication only from trusted base code. Authenticate build provenance and benchmark producers, validate bounded artifacts as data, and prevent downloaded reports from overwriting workflow code.
  • Run benchmark and artifact-publication steps only for pull request validation; main-branch builds retain their existing test flow without the additional benchmark budget.

Validation
4,846 tests passed, 108 skipped, and 42 deselected. The focused benchmark and workflow suite passed 120 tests. Clean and single-regression report previews were generated from retained paired measurements.

Rollout
The reporting workflow becomes active after merging into the base branch. Results remain advisory and do not block merging. Instrumented timings are diagnostic comparisons, not production-wheel latency estimates.

Replace historical CI benchmark comparisons with twenty shared workloads covering every profiler scenario and the existing large-query and insert benchmarks.

Reuse profiling-enabled candidate builds for correctness tests with recording off, then compare base and candidate in fresh benchmark processes on the same agent and database. Keep default-build coverage and release build configuration separate.

Publish bounded per-leg measurements and an advisory, commit-bound PR comment with slowdown signals, phase deltas and call-count changes. Run the comment publisher only from trusted base code and mark missing or invalid measurements incomplete.

Co-authored-by: Copilot <[email protected]>
Copilot AI lite review requested due to automatic review settings September 10, 2026 18:25
@github-actions github-actions Bot added the pr-size: large Substantial code update label Sep 10, 2026
Comment thread tests/test_036_profiler_ci.py Dismissed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

benchmarks/profiler_ci.py uses tarfile.extractall(..., filter="data"), which breaks execution on older supported Python versions (local/dev) and needs a compatibility fallback.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR adds an end-to-end CI benchmarking + reporting pipeline for the internal profiler, shifting from historical baseline comparisons to paired base/PR measurements and publishing an advisory regression report comment on PRs.

Changes:

  • Introduces benchmarks/profiler_ci.py to build base + candidate revisions (profiling-enabled) and run a fixed 20-workload suite in isolated processes, producing a bounded report.json.
  • Adds benchmarks/profiler_report.py and a privileged pull_request_target workflow + script to validate ADO artifacts as data and update a SHA-bound PR comment.
  • Updates the Azure DevOps PR validation pipeline to produce and publish paired profiler measurement artifacts across the targeted platform/SQL legs.
File summaries
File Description
tests/test_036_profiler_ci.py Contract tests covering report validation, artifact safety checks, and trusted-base comment publishing behavior.
profiler/README.md Links to the new paired CI benchmark guide for profiler builds and PR reporting.
eng/pipelines/pr-validation-pipeline.yml Switches CI perf runs to paired profiler comparisons; publishes per-leg profiler-* artifacts; adds profiling build legs where intended.
benchmarks/README.md Documents the new paired CI benchmark approach, workload coverage, and advisory thresholds/reporting model.
benchmarks/profiler_workloads.py Defines the fixed 20-workload registry shared by base and candidate measurements.
benchmarks/profiler_report.py Validates bounded report data and renders an advisory per-leg comparison comment (with escaping).
benchmarks/profiler_ci.py Orchestrates revision resolution, isolated checkouts/builds, and paired measurements into a single report.
.github/workflows/pr-profiler-report.yml Adds privileged pull_request_target workflow that checks out only base SHA and runs the publisher.
.github/scripts/post_profiler_comment.py Fetches ADO artifacts safely, validates provenance + schema, and creates/updates the PR comment.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread benchmarks/profiler_ci.py Outdated
Restore libodbcinst2 before installing the ODBC driver so its post-install script can run after pytest cleanup.

Log and checkpoint each benchmark scenario, capture periodic worker stacks, and replace the four-minute whole-suite limit with a ten-minute worker limit under a shared 35-minute budget. Partial workers remain incomplete rather than producing a regression verdict; the hosted macOS stall still requires confirmation on the next run.

Match coverage discovery to the exact PR head and wait through queued ADO coverage jobs with bounded requests, retries and completion grace. Accept valid coverage artifacts even when an independent matrix leg fails.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings September 11, 2026 05:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two moderate issues remain in build-timeout handling and Python-version compatibility.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

benchmarks/profiler_ci.py:47

  • TarFile.extractall(filter=...) was added in Python 3.12, but this repository supports Python 3.10+ and the README presents this as a local command. On Python 3.10/3.11 every paired comparison fails before building; use a compatible extraction path or explicitly require Python 3.12+.
            tar.extractall(path, filter="data")
  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread .github/scripts/post_profiler_comment.py Outdated
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown

📊 Code Coverage Report

🔥 Diff Coverage

100%


🎯 Overall Coverage

83%


📈 Total Lines Covered: 8437 out of 10091
📁 Project: mssql-python


Diff Coverage

Diff: main...HEAD, staged and unstaged changes

No lines with coverage information in this diff.


📋 Files Needing Attention

📉 Files with overall lowest coverage (click to expand)
mssql_python.pybind.performance_counter.hpp: 0.7%
mssql_python.pybind.logger_bridge.cpp: 57.9%
mssql_python.pybind.ddbc_bindings.h: 61.5%
mssql_python.pybind.logger_bridge.hpp: 70.8%
mssql_python.row.py: 77.6%
mssql_python.pybind.ddbc_bindings.cpp: 77.7%
mssql_python.pybind.connection.connection_pool.cpp: 81.8%
mssql_python.logging.py: 86.2%
mssql_python.pooling.py: 90.1%
mssql_python.pybind.py_type_cache.hpp: 91.6%

🔗 Quick Links

⚙️ Build Summary 📋 Coverage Details

View Azure DevOps Build

Browse Full Coverage Report

Allow all twelve profiler passes to finish within coordinated CI and reporting budgets without reducing workload coverage or measured samples.

Reject malformed report containers per leg and finalize unfinished ADO runs as incomplete at the publisher deadline.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings September 15, 2026 18:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Address the Python compatibility failure, workload-contract drift, and command-line exposure of DB_PASSWORD.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

benchmarks/profiler_ci.py:48

  • This runner is documented for the repository's supported Python >=3.10, but the filter= keyword for TarFile.extractall was added in Python 3.12. On Python 3.10/3.11 every base/candidate checkout fails with TypeError before any benchmark runs; gate this call by Python version or use a compatible safe-extraction helper.
            tar.extractall(path, filter="data")

benchmarks/profiler_report.py:32

  • The report contract duplicates the workload names maintained by profiler_workloads.registry(). If a future change updates only one list, the worker will either generate a report that validate() rejects or fail to produce a scenario that validation requires; add a contract test or derive the authoritative case set from one shared registry.
CASES = (
    "connect",
    "select",
    "insert",
    "executemany",
    "fetchall",
    "fetchone",
    "fetchmany",
    "commit_rollback",
    "arrow",
    "insertmanyvalues",
    "fetchmany_100",
    "fetchmany_10000",
    "prepared_qmark",
    "prepared_named",
    "legacy_insertmany",
    "setinputsizes",
    "join_aggregation",
    "large_fetch",
    "fetch_1_2m",
    "cte",
  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread eng/pipelines/pr-validation-pipeline.yml Outdated
@bewithgaurav
Gaurav Sharma (bewithgaurav) marked this pull request as ready for review September 15, 2026 19:08
@bewithgaurav
Gaurav Sharma (bewithgaurav) marked this pull request as draft September 15, 2026 19:28
Merge the current main branch and correct the deadline contract that failed every platform test suite by selecting an unrelated step timeout.

Keep database credentials out of Docker command arguments, support safe archive extraction on Python 3.10 and 3.11, and lock the report scenarios to the executed workload registry.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings September 15, 2026 19:47
@bewithgaurav
Gaurav Sharma (bewithgaurav) marked this pull request as ready for review September 15, 2026 19:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Address the unpinned privileged action and the benchmark timeout and subset-report completeness issues.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (3)

.github/workflows/pr-profiler-report.yml:26

  • This privileged pull_request_target job runs with pull-requests: write, so the action implementation itself must be immutable; a mutable @v5 tag can change outside a reviewed base commit and execute different code. Existing workflows pin this action to a commit SHA (for example .github/workflows/lint-check.yml:36).
      - uses: actions/setup-python@v5

benchmarks/profiler_ci.py:26

  • The deadline is smaller than the documented worst-case work. run() can perform 12 worker passes, each allowed up to WORKER_TIMEOUT (10 minutes), plus a 15-minute base build and preflight, which can require 136 minutes; local runs also build the candidate and need another 15 minutes. With the current 80-minute deadline, a slow but still permitted worker is killed before all five pairs complete, and the README's local command cannot reliably finish. Align the worker timeout/budget and the 90-minute pipeline step (or explicitly make local mode use a separate budget) so the advertised complete comparison is achievable.
BENCHMARK_TIMEOUT = 80 * 60
WORKER_TIMEOUT = 10 * 60

benchmarks/profiler_ci.py:259

  • When --scenarios is supplied, the worker emits only that subset, but this unconditional complete status produces a report that profiler_report.validate() must reject because complete reports require every CASES entry. The documented local subset path therefore finishes with an invalid report; mark subset runs as incomplete (or add a validated scenario-list schema).
    report["status"] = "complete"
  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread .github/workflows/pr-profiler-report.yml Outdated
Accelerate long-horizon workflow fixtures so macOS validates the polling budget without hundreds of real shell iterations.

Recover coverage reporting onto newer exact-head ADO runs, pin privileged actions, align benchmark deadlines with worker limits, and keep subset reports incomplete.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings September 16, 2026 04:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical security and benchmark-validation findings require changes before approval.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

.github/scripts/post_profiler_comment.py:177

  • This loop treats every status == "completed" run as terminal, including result == "canceled". If ADO cancels that run and queues a newer run for the same PR head, the publisher immediately reads the canceled run's likely-missing artifacts and posts a final incomplete report instead of waiting for the replacement; the coverage poller already handles this replacement case. Continue polling/select a newer exact-head build when the selected run is canceled before finalizing.
        if build and build["status"] == "completed":
            break
  • Files reviewed: 11/11 changed files
  • Comments generated: 4
  • Review effort level: Lite

Comment thread .github/scripts/post_profiler_comment.py Outdated
Comment thread .github/workflows/pr-code-coverage.yml Outdated
Comment thread .github/workflows/pr-code-coverage.yml Outdated
Comment thread benchmarks/profiler_ci.py Outdated
Read coverage reports from fixed outputs without extracting untrusted archive paths into the checkout.

Require authenticated source and base trees to use identical benchmark producers, and continue polling when an exact-head ADO run is canceled.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings September 16, 2026 04:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Three unresolved moderate issues affect coverage extraction, malformed report handling, and canceled-build polling.

Review details

Suppressed comments (3)

Previously missed (1) — in code that hasn't changed since the last review.

.github/workflows/pr-code-coverage.yml:140

  • The polling loop accepts an artifact and breaks before checking the selected build's lifecycle. If a canceled ADO run has already published a coverage artifact, this path consumes that partial/stale artifact and never searches for the newer replacement that the later cancellation branch is intended to select. Check the build status before accepting the artifact, or discard the artifact when the run is canceled and continue replacement polling.

.github/scripts/extract_coverage_artifact.py:42

  • The XML selector falls back to every .xml member when no filename contains coverage, so an archive containing only test-results XML is treated as a valid coverage report. This can feed unrelated data to diff-cover instead of rejecting the artifact; restrict candidates to the known unified-coverage/coverage.xml, coverage.xml, or coverage-named files.
        elif kind == "xml" and path.suffix.lower() == ".xml":
            name = path.name.lower()
            priority = (
                0
                if str(path).endswith("unified-coverage/coverage.xml")
                else (1 if name == "coverage.xml" else 2 if "coverage" in name else 3)
            )
            candidates.append((priority, member))

.github/scripts/post_profiler_comment.py:234

  • A deeply nested but size-bounded report.json can make json.loads raise RecursionError. That exception is not handled here, so one malformed leg aborts the publisher instead of being recorded as an invalid artifact while valid legs are still rendered; include RecursionError in the per-leg rejection path.
        except (ValueError, KeyError, TypeError, URLError, zipfile.BadZipFile):
            # Invalid data is visibly incomplete, never converted to a success verdict.
            issues.append(leg + " (invalid artifact)")
  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 17, 2026 09:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved moderate findings remain in coverage artifact filtering, ADO URL validation, and malformed-report handling.

Review details

Suppressed comments (5)

.github/scripts/extract_coverage_artifact.py:30

  • The candidate filter does not exclude ZIP directory entries. A member such as Code Coverage Report/index.html/ or coverage.xml/ is normalized by PurePosixPath to the same basename/suffix as a file, so it can be selected and copied as an empty report; the workflow then treats selection as successful and fails later in parsing. Exclude member.is_dir() before adding candidates.
            or member.file_size > MAX_REPORT_BYTES

.github/workflows/pr-code-coverage.yml:180

  • ADO_URL is copied verbatim from the replacement build's _links.web.href and is later interpolated into the PR comment's Markdown link. The length/newline checks do not constrain the host or Markdown syntax, so malformed or compromised API metadata can publish an arbitrary link; construct this URL from the already validated numeric BUILD_ID and the fixed ADO host (as the normal path does), or apply the same URL allowlist used by the publisher.
                  ADO_URL=$(jq -r '._links.web.href // empty' <<< "$REPLACEMENT")
                  if [[ -z "$ADO_URL" || ${#ADO_URL} -gt 500 || "$ADO_URL" == *$'\n'* || "$ADO_URL" == *$'\r'* ]]; then
                    echo "Invalid replacement Azure DevOps build URL"
                    exit 1

benchmarks/README.md:15

  • This replaces the existing documentation for benchmarks/perf-benchmarking.py instead of adding the profiler section. The standalone script remains in the repository, so this change leaves it undocumented; retain its heading/description and introduce the profiler comparisons as the next section.
### 2. Profiler benchmark comparisons

Profiler benchmarks are engineering infrastructure, separate from these standalone
scripts and from the runtime profiler. See
[`eng/profiler_benchmarks/README.md`](../eng/profiler_benchmarks/README.md).
Their reviewer-facing output is the impact-first **PR Performance Report**.

eng/profiler_benchmarks/README.md:33

  • This documentation contradicts the publisher contract: a completed ADO run with result == "failed" is still processed, and validated artifacts can produce a partial or complete advisory report (post_profiler_comment.py:229-253, report.py:294-320). Please describe failed runs as usable when their authenticated artifacts validate, rather than saying all failed results remain unavailable.
heads. Missing, malformed, canceled, or failed results remain unavailable.

eng/profiler_benchmarks/report.py:193

  • Malformed reports with a missing required key are not normalized to the validator's ValueError contract: for example, omitting environment raises KeyError at this indexing operation. assess() happens to catch that, but the standalone report CLI calls validate() directly and emits an unhandled traceback; use guarded lookups (and the same treatment for the later scenarios, layer, and counter fields) so invalid data is rejected consistently.
            env = sample["environment"]
            if not isinstance(env, dict) or set(env) != {
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 17, 2026 10:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Resolve the two moderate artifact polling and decompression-error handling findings.

Review details

Suppressed comments (2)

.github/scripts/post_profiler_comment.py:284

  • The publisher only waits two minutes for the artifact listing after the ADO build becomes completed, then publishes an unavailable result. Artifact publication/listing is eventually consistent and can lag a completed build; this contradicts the documented 220-minute publication window and can discard valid paired results. Keep artifact polling within the existing overall deadline (while preserving the workflow's publication buffer) instead of starting a fixed 120-second deadline here.
    artifact_deadline = time.monotonic() + 120

eng/profiler_benchmarks/report.py:318

  • A ZIP with a valid central directory but corrupt deflate data can raise zlib.error from archive.read(member). That exception is not in this validation catch list, so a malformed PR artifact can abort assess() before it publishes the final unavailable report and leave the sticky comment pending; normalize decompression errors as an invalid artifact here.
        except (
            KeyError,
            RecursionError,
            TypeError,
            ValueError,
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 17, 2026 11:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Three moderate findings remain regarding artifact contracts, main-branch benchmark execution, and timeout termination.

Review details

Suppressed comments (3)

eng/pipelines/pr-validation-pipeline.yml:423

  • The PR summary says the existing artifact names are preserved, but the pipeline replaces the established perf-baseline-* artifacts with profiler-* names (the analogous Windows/macOS/Linux changes are also present). That is a contract change for ADO consumers and reruns; either retain the existing names or update the description and all dependent contracts explicitly.
      artifact: 'profiler-Windows-$(sqlVersion)'

eng/pipelines/pr-validation-pipeline.yml:409

  • This benchmark step is not PR-only: the pipeline is also triggered by pushes to main, and the condition below still runs it for every SQL matrix leg. Those main-branch artifacts cannot be selected by post_profiler_comment.py, which requires triggerInfo.pr.number and triggerInfo.pr.sourceSha, so each merge now incurs up to the 90-minute benchmark budget without producing a PR report. Please gate these expensive benchmark/publication steps to PR validation runs, or add an explicit in-repo consumer for main runs.
      python -m eng.profiler_benchmarks.controller --reuse-candidate --leg "Windows-$(sqlVersion)" --output profiler-results

eng/profiler_benchmarks/controller.py:81

  • If the process exits between the timeout and taskkill, taskkill returns nonzero but process.poll() is no longer None, so this branch raises RuntimeError even though the tree is already gone. That race can turn a completed/clean timeout into a failed benchmark leg; treat an already-exited process as successfully terminated and only escalate when it is still alive.
        if result.returncode:
            if process.poll() is None:
                process.kill()
                process.wait()
            raise RuntimeError(f"Failed to terminate build process tree: {result.stdout.strip()}")
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

gargsaumya
gargsaumya previously approved these changes Sep 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Two moderate issues remain in build-result validation and main-branch profiling gates.

Review details

Suppressed comments (2)

.github/scripts/post_profiler_comment.py:233

  • complete treats every completed build whose result is not exactly canceled as publishable. Because build_items does not require or validate result, a malformed/unsupported terminal response (for example a missing or unknown result) can proceed to provenance and artifact validation and potentially publish a verdict. Accept only the known terminal results (succeeded, partiallySucceeded, and failed) and finalize unsupported completed results as unavailable rather than treating them as complete.
            complete = (
                build is not None
                and build.get("status") == "completed"
                and build.get("result") != "canceled"
            )

eng/pipelines/pr-validation-pipeline.yml:65

  • These matrix values are unconditional, so the pipeline's main-branch runs (the trigger: main at lines 3-7) now build the profiling extension and publish profiling-named binding artifacts even though only the benchmark/artifact steps below are gated to Build.Reason == 'PullRequest'. That changes the main test binary and adds profiler overhead, contrary to the stated requirement that main-branch builds retain their existing flow; gate the profiling build/check/artifact selection on PR runs, and apply the same gating to the macOS/Linux build assignments.
        profilerBuild: '1'
        profilerCheck: 'on'
        bindingArtifact: 'ddbc_bindings-profiling-SQL2022'
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 17, 2026 13:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two critical and four moderate workflow findings remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (4)

.github/workflows/pr-code-coverage.yml:73

  • The new head matching only selects the build for the event that started this run. Because this workflow has no per-PR concurrency cancellation or final current-head check, a long-running coverage run for head A can finish after head B is pushed and overwrite the sticky coverage comment for the PR with results from superseded code. Cancel older runs per PR or revalidate the current PR head immediately before posting.
            BUILD_INFO=$(jq -c --arg PR "$PR_NUMBER" --arg SHA "$PR_HEAD_SHA" --arg BRANCH "$PR_BRANCH" '
              [.value[]? | select(
                .definition.id == 2128 and .sourceBranch == $BRANCH and
                (.triggerInfo["pr.number"] | tostring) == $PR and
                .triggerInfo["pr.sourceSha"] == $SHA
              )] | .[0] // empty' <<< "$API_RESPONSE")

eng/pipelines/pr-validation-pipeline.yml:825

  • The Ubuntu container is also always built with profiling enabled, so main runs receive the same native/test-flow change even though the benchmark step itself is PR-only. This contradicts the stated rollout constraint that main-branch builds retain the existing flow; gate PROFILER_BUILD=1 and the corresponding check on Build.Reason == 'PullRequest'.
      if [ "$(distroName)" = "Ubuntu" ]; then
        PROFILER_BUILD=1
        PROFILER_CHECK=on

eng/pipelines/pr-validation-pipeline.yml:64

  • These profiling matrix values are unconditional, while this pipeline also triggers on main. Consequently main-branch runs now build profiling binaries, run the profiler check/tests, and publish differently named binding artifacts, rather than retaining the existing test flow described in the PR summary. Gate the profiling configuration (and related artifact naming) on Build.Reason == 'PullRequest' if main should remain on the normal build.
        profilerBuild: '1'
        profilerCheck: 'on'

eng/pipelines/pr-validation-pipeline.yml:563

  • This hard-codes profiling for every macOS matrix run, including the top-level main trigger. That changes the native build and enables profiler-only tests on main even though the PR summary says main retains its existing test flow and only PR validation receives the benchmark changes. Make this build mode conditional on pull-request validation, or otherwise preserve the normal main-branch build.
      ( cd mssql_python/pybind && ENABLE_PROFILING=1 ./build.sh )
  • Files reviewed: 14/14 changed files
  • Comments generated: 2
  • Review effort level: Lite

echo "Trying to extract with verbose output for debugging..."
unzip -l coverage-report.zip || echo "Failed to list archive contents"
INDEX_FILE="$RUNNER_TEMP/coverage-index.html"
if ! python .github/scripts/extract_coverage_artifact.py html "$COVERAGE_ARCHIVE" "$INDEX_FILE"; then
Comment on lines +422 to 426
diff-cover "$COVERAGE_XML" \
--compare-branch=main \
--html-report patch-coverage.html \
--json-report patch-coverage.json \
--markdown-report patch-coverage.md || {
Prevent stale coverage publication, keep profiling configuration off main, and reject unsupported terminal ADO results.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings September 17, 2026 13:51
Use mutually exclusive build and artifact tasks because Azure matrix variables are read-only.

Co-authored-by: Copilot <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The unresolved critical and moderate workflow issues must be addressed before approval.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

.github/workflows/pr-code-coverage.yml:366

  • This XML step consumes the first URL from a filter that also matches the HTML Code Coverage Report artifact. If ADO lists that artifact first, copy_report(..., "xml") rejects it with No coverage xml even though the unified XML artifact is present, so the coverage job fails based on artifact ordering. Select an XML-specific artifact or try the matching URLs until the XML reader succeeds.
            if ! python .github/scripts/extract_coverage_artifact.py xml "$COVERAGE_XML_ARCHIVE" "$COVERAGE_XML"; then
  • Files reviewed: 14/14 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread eng/pipelines/pr-validation-pipeline.yml
Copilot AI review requested due to automatic review settings September 17, 2026 14:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The report contains one critical diagnostic-count mismatch and two moderate malformed-artifact handling issues.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

eng/profiler_benchmarks/report.py:178

  • These regex checks assume the commit and suite-identity fields are strings. A malformed report such as head_commit: 1 makes re.fullmatch raise TypeError, which escapes validate() and produces an unhandled traceback in the standalone report CLI instead of the validator's normal ValueError rejection. Check the value types before applying the regex (or normalize this TypeError in validate).
    for key in ("head_commit", "source_commit", "base_commit"):
        if not re.fullmatch(r"[0-9a-f]{40}", report.get(key, "")):
            raise ValueError("Invalid commit identity")
    if not re.fullmatch(r"[0-9a-f]{64}", report.get("suite_hash", "")):
        raise ValueError("Invalid workload identity")

eng/profiler_benchmarks/report.py:319

  • A valid ZIP member using an unsupported compression method raises NotImplementedError from archive.read (and truncated members can raise EOFError), but neither exception is handled here. Because profiler artifacts are treated as untrusted data, one malformed artifact can abort the publisher before it posts the unavailable/invalid-artifact result; normalize these zipfile read failures as invalid artifacts.
        except (
            KeyError,
            RecursionError,
            TypeError,
            ValueError,
  • Files reviewed: 14/14 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment on lines +546 to +547
f"{total_diagnostics - diagnostics} additional diagnostic rows are available "
"in the raw ADO artifacts.",
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: large Substantial code update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants