Skip to content

Add installer tests for official Python wheels - #580

Merged
ttk (Theekshna) merged 13 commits into
mainfrom
dev/tkotian/official-wheel-install-smoke
Sep 22, 2026
Merged

ttk (Theekshna) merged 13 commits into
mainfrom
dev/tkotian/official-wheel-install-smoke

Conversation

@Theekshna

@Theekshna ttk (Theekshna) commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds a release gate to the Official Python Wheels Build that clean-installs and exercises every final wheel after signing, ODBC injection, and Linux repair/retagging, before the platform artifact is published.

This closes a gap left by build, signing, and packaging checks: those checks can succeed while the released wheel is missing the injected driver, contains it under the wrong architecture path, depends on libraries available only in the build image, or was damaged by a final artifact transformation.

The release build produces a single stable-ABI (cp310-abi3) wheel per platform, forward-compatible with every supported interpreter (Requires-Python >=3.10). The gate covers the full 9-wheel release matrix, each wheel installed and exercised under every supported interpreter (Python 3.10-3.14, except win_arm64 which starts at 3.11):

  • Windows x64 and ARM64 (2 wheels)
  • Linux x64 and ARM64 across manylinux_2_28, manylinux_2_34, and musllinux_1_2 (6 wheels)
  • macOS universal2 (1 wheel)

For each platform, the test:

  1. Selects the single released cp310-abi3 wheel for that platform.
  2. For each supported interpreter, creates a fresh virtual environment.
  3. Installs the wheel by exact path with python -m pip install --no-index --no-deps.
  4. Verifies distribution metadata and imports mssql_py_core.
  5. Locates and dynamically loads the bundled mssqlodbc library.
  6. Calls SQLAllocHandle(SQL_HANDLE_ENV) and SQLFreeHandle.

Linux installation tests use the stock PyPA manylinux/musllinux images mirrored at ghcr.io/microsoft/mssql-rs/import/python-build/.... This avoids both the custom Rust build images, which can mask undeclared runtime dependencies, and a direct dependency on quay.io egress from the official pipeline.

The macOS job uses macOS 15 to match the macosx_15_0_universal2 deployment tag. The hosted Intel runner validates installation and the x64 native slice; native ARM64 execution still requires an Apple Silicon agent.

This is an installation, native-load, and basic ODBC ABI smoke gate. It intentionally does not require SQL Server credentials or duplicate the separate database-connected test suite.

Related Issues

AB#48227

Validation

  • Official Python Wheels Build 177092 succeeded at f21884a89dec0329b01edc627fa21c96ec479be5 (current head). All 9 final wheels (one per platform, cp310-abi3) completed clean installation, package import, native driver load, SQLAllocHandle, and SQLFreeHandle verification under every supported interpreter; all platform artifacts were published only after their installer gates succeeded; Linux logs confirmed all stock test images were pulled through the Microsoft GHCR mirror.
  • Packaging test suite: python -m pytest scripts/test_inject_odbc.py scripts/test_verify_python_wheels.py scripts/test_release_pipeline.py scripts/test_validation_pipeline.py scripts/test_repair_glibc_wheels.py scripts/test_bump_released_crate_versions.py scripts/test_python_wheel_install.py -q — 286 passed.
  • bash -n scripts/test-python-wheel-installs-linux.sh
  • Changed pipeline YAML parsed with PyYAML.
  • git diff --check
  • cargo bfmt

Checklist

  • cargo bfmt passes
  • cargo bclippy not run (no Rust changes)
  • cargo btest not run (focused Python packaging and official wheel validation used instead)
  • New/changed functionality has tests
  • Public API changes are documented (no public API changes)

@Theekshna ttk (Theekshna) changed the title Test final Python wheels in clean environments Add installer tests for official Python wheels Sep 16, 2026
@github-actions

github-actions Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

📊 Code Coverage Report

🔥 Diff Coverage

100%

🎯 Overall Coverage

94.0%

📦 Project: mssql-tds + mssql-odbc + mssql-py-core
ℹ️ Note: diff coverage is reported, not enforced.


Diff Coverage

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

No lines with coverage information in this diff.


🔗 Quick Links

View Azure DevOps Build · Coverage Report

@Theekshna
ttk (Theekshna) marked this pull request as ready for review September 17, 2026 06:42
@Theekshna
ttk (Theekshna) requested a review from a team as a code owner September 17, 2026 06:42
Copilot AI balanced review requested due to automatic review settings September 17, 2026 06:42

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

Driver selection does not reject incorrect package paths on Linux and Windows, allowing a wheel unusable by the consumer resolver to pass.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds installation and native-library smoke gates for all 44 official Python wheels before artifact publication.

Changes:

  • Adds isolated wheel installation and ODBC ABI verification.
  • Integrates platform-specific gates into official builds.
  • Adds pipeline and helper-script tests.
File summaries
File Description
scripts/test-python-wheel-installs-linux.sh Tests Linux wheels in mirrored stock images.
scripts/test-python-wheel-install.py Installs and validates one wheel.
scripts/test_release_pipeline.py Verifies gate placement and matrix parameters.
scripts/test_python_wheel_install.py Tests installer helper behavior.
.pipeline/templates/validation-stages.yml Runs the new tests in validation.
.pipeline/templates/test-python-wheel-installs-template.yml Defines platform-specific installation steps.
.pipeline/OneBranch/stages.yml Places gates before artifact publication.
.pipeline/OneBranch/OfficialPythonWheelsBuild.yml Enables gates for official builds.
Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/test-python-wheel-install.py Outdated

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.

This review came from an unattended sweep; its findings were not checked by a human first.

Verdict: the existing driver-selection issue remains outstanding; no additional findings from this inspection. This is not an approval.

Reviewed the complete merge-base diff and the affected build, injection, installation and artifact-publication paths. The installer gates cover the intended 44-wheel matrix in configuration; this is source inspection, not confirmation that those wheels executed successfully at this head.

Blocking: No new findings. The existing unresolved concern is tracked in the driver-selection thread; I have not duplicated or reclassified it.

Suggestion: No new findings.

Nit: None.

The performance pass found no substantiated additional finding in the installer/setup paths; no timing or memory measurements were made. Independent critique produced scope clarifications, not additional findings: the macOS runner change also applies to non-official uses of the shared job, and Linux installs are sequential within each architecture job rather than across both jobs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated review — generated by GitHub Copilot on behalf of Vahid Beiranvand (@Vahid-b). This is not an approval and does not satisfy the human review requirement. Findings may be incomplete or wrong; push back on anything that looks off.

Summary

Reviewed the full merge-base diff (0185d708 → 0ea6599b, 8 files) plus the surrounding injection, repair/retag, and artifact-publication paths. The gate is placed correctly in all five build jobs, the expected package paths match the existing injection/verification contract, and the ODBC symbol contract matches what mssql-odbc actually exports. I found no blocking issues. Two suggestions below are about drift resistance and template reuse, not correctness of the current pipeline.

The driver-selection concern from the earlier Copilot review is addressed by the --wheel-name / expected_driver_path rework in 78882c46; I re-checked it and did not reclassify it.

Verification performed

  • Confirmed repository microsoft/mssql-rs, PR #580, head 0ea6599bcac7f9f522baa1d20a0ab7c789e37e40, merge base 0185d708561de0f8f64348fe515b96c8500280ef against origin/main. Reviewed in an isolated detached worktree.
  • Cross-checked every mapping in expected_driver_path against the two existing contracts — scripts/inject-odbc-into-wheels.py (_GLIBC_X64/_MUSL_ARM64/…) and .pipeline/scripts/verify-python-wheels.ps1 (Get-ExpectedOdbcMembers). All eight platform → member mappings agree.
  • Cross-checked all 39 entries of REQUIRED_ODBC_SYMBOLS against pub extern "C" symbols in mssql-odbc/src: all 39 are exported (50 exported in total), so the export contract cannot fail on a typo.
  • Verified step ordering in stages.yml for all five jobs: the gate follows the ODBC injection, the glibc-2.28 injection, and both auditwheel repair / retag steps, and precedes PublishPipelineArtifact@1.
  • Confirmed MACOSX_DEPLOYMENT_TARGET=15.0 is set unconditionally in build-python-wheels-template.yml, so the macOS-14 → macOS-15 move is required for pip install to accept the macosx_15_0_universal2 tag and for the dylib to load — not incidental.
  • Confirmed architecture: 'arm64' for UsePythonVersion@0 is an established pattern in this repo (PublishFeeds-Sandbox.yml), and that the Windows_ARM64 job already runs the Node.js agent workaround before the new steps.
  • Confirmed evaluate() in test_release_pipeline.py maps and(...) to n-ary all_, so the new three-argument compile-time condition expands correctly.
  • bash -n scripts/test-python-wheel-installs-linux.sh → clean; also confirmed the empty-array printf "${wheels[@]}" error path is safe under set -u on bash ≥ 4.4 (all three image families qualify).
  • Not run: the pytest suites. This machine has no non-stub Python interpreter, so I relied on static review plus the referenced build 175810 rather than installing one.

Findings

Blocking

None.

Suggestion

  1. The Linux release matrix is asserted against itself, so drift is invisible. scripts/test-python-wheel-installs-linux.sh hardcodes PYTHON_TAGS=(cp310 … cp314) and PLATFORM_TAGS=(manylinux_2_34 manylinux_2_28 musllinux_1_2), and test_linux_installs_cover_release_matrix verifies those by matching the same literal strings back out of the same file. The canonical matrix lives in .pipeline/scripts/verify-python-wheels.ps1 ($pythonTags / $platforms), which is what the release gates actually enforce. They agree today, but when a Python version is added there, the shell script silently stops covering it and both assertions still pass — exactly the class of gap this PR exists to close. Consider parsing verify-python-wheels.ps1 (or a shared source) in that test instead of restating the literals.

    The same applies more weakly to the Linux rows of test_python_wheel_install_gate_precedes_artifact_publication: they assert pythonVersions falls back to the template default, but the template documents that Linux ignores that parameter, so those particular assertions do not constrain Linux coverage.

  2. The new gate steps omit the PR-reason guard that every step producing their input carries. The injection, glibc-2.28 injection, repair, and retag steps are all condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')); the template's steps have no runtime condition, and the compile-time ${{ if }} keys only off testPythonWheelInstalls / buildOdbcNative / buildPythonWheels. That is safe today solely because OfficialPythonWheelsBuild.yml is the only consumer setting the flag and it declares pr: none. But stages.yml is shared with NonOfficialPythonWheelsPublish.yml, which runs on PRs into main and on a nightly schedule — the natural place someone would enable this next. There, PR runs would hand the gate wheels with no injected driver and it would fail rather than skip. Adding the same ne(Build.Reason, 'PullRequest') condition to the template's steps would make the gate self-consistent with everything it depends on.

Nit

  • scripts/test-python-wheel-installs-linux.sh and .pipeline/templates/test-python-wheel-installs-template.yml have no trailing newline, while the other files added in this PR do. (git diff --check does not catch this.)

Relevant required-CI failures

coverage-report fails with ❌ Timeout: coverage artifact not found within 75 minutes — the merged Cobertura artifact never appeared across 10 polls, while the per-platform coverage artifacts all published. Every other listed check passes, including the full mssql-rs Pull request validation pipeline, and the coverage bot already posted 100% diff coverage / 93.9% overall for this branch. This reads as artifact/timing infrastructure rather than anything in this change; a re-run should clear it. No CI failure traceable to the diff.

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.

Unattended automated review — this review was posted without human confirmation. It is a COMMENT only, not an approval.

Summary

Reviewed the full merge-base diff (0185d708 → 0ea6599b, 8 files), the linked AB#48227 task, all existing review threads/bodies/top-level comments, and the directly affected wheel injection, matrix verification, repair/retag, and artifact-publication paths. I found no genuine new findings beyond the current-head suggestions already recorded in review 5236091696, so I have not duplicated them.

Blocking

None.

Medium

None.

Low

None.

Suggestion

None new.

Nit

None new.

Validation

  • uv run --python 3.13 python -m py_compile scripts/test-python-wheel-install.py scripts/test_python_wheel_install.py scripts/test_release_pipeline.py
  • bash -n scripts/test-python-wheel-installs-linux.sh
  • git diff --check 0185d708561de0f8f64348fe515b96c8500280ef..HEAD
  • Focused pytest execution was attempted, but fetching pytest/PyYAML failed non-interactively with a PyPI TLS handshake error. The PR validation pipeline passes on this head.
  • The sole failing check is coverage-report, which timed out waiting for the merged coverage artifact; the existing coverage comment reports 100% diff coverage and 93.9% overall coverage.

@Theekshna
ttk (Theekshna) enabled auto-merge (squash) September 17, 2026 14:56
@Theekshna

Copy link
Copy Markdown
Contributor Author

Vahid Beiranvand (@Vahid-b) Thanks — addressed both suggestions in 9ed77aa:

  1. test_linux_installs_cover_release_matrix now parses .pipeline/scripts/verify-python-wheels.ps1 and cross-checks PYTHON_TAGS/PLATFORM_TAGS against it instead of asserting literals from the same file. Verified it actually catches drift (added a fake cp315 to the ps1 matrix and confirmed the test fails).
  2. Added condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) to all three OS steps in test-python-wheel-installs-template.yml, matching the injection/repair steps upstream. No-op today, but closes the gap if NonOfficialPythonWheelsPublish.yml ever sets testPythonWheelInstalls: true.

Also fixed the trailing-newline nit on both files. Left the weaker Linux-coverage point on test_python_wheel_install_gate_precedes_artifact_publication as-is since it's just documenting the template default fallback, not asserting Linux-specific coverage.

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.

Unattended automated review — posted without human confirmation. This is a COMMENT only, not an approval.

Summary

Reviewed the complete merge-base diff (0185d708 → 9ed77aa7, 8 files), all existing inline threads, review bodies, top-level comments, checks, and the directly affected wheel build, ODBC injection, repair/retag, installer, and artifact-publication paths. The latest commit addresses the previously posted matrix-drift, PR-guard, and newline feedback; I found no genuine new findings.

Blocking

None.

Medium

None.

Low

None.

Suggestion

None.

Nit

None.

Targeted validation

  • Python 3.13 py_compile for the three changed Python scripts
  • bash -n scripts/test-python-wheel-installs-linux.sh
  • git diff --check 0185d708561de0f8f64348fe515b96c8500280ef..HEAD
  • Focused pytest was attempted, but pytest/PyYAML retrieval failed non-interactively with a PyPI TLS handshake error; all current PR checks pass, including the packaging tests in PR validation.

@shiwanigupta0809

Copy link
Copy Markdown
Contributor

Unattended automated code review posted: #580 (review)

Category counts: Blocking 0, Medium 0, Low 0, Suggestion 0, Nit 0.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unattended automated review — generated without human confirmation. This is a COMMENT only, not an approval, and does not satisfy the human review requirement. Findings may be wrong; push back on anything that looks off.

Summary

Reviewed the complete merge-base diff (0185d708 → 9ed77aa7, 8 files) in an isolated detached worktree, plus the surrounding ODBC injection, glibc-2.28 repair/retag, wheel-verification and artifact-publication paths. The gate is placed after every artifact-transforming step and before PublishPipelineArtifact@1 in all five build jobs, the expected package paths agree with the existing injection/verification contract, and the driver-selection concern from the earlier Copilot review is genuinely closed by the --wheel-name / expected_driver_path rework. No blocking issues. One suggestion about drift resistance that the latest commit fixed for Linux but not for Windows/macOS, and one nit.

I did not duplicate the already-answered driver-selection thread, nor the matrix-drift/PR-guard/newline items from review 5236091696 — all three are addressed in 9ed77aa7 and I re-verified the fixes rather than restating them.

Verification performed

  • Confirmed microsoft/mssql-rs, PR #580, author Theekshna, head 9ed77aa74503668820f7961a860223f4805f89c8, merge base 0185d708561de0f8f64348fe515b96c8500280ef against a freshly fetched origin/main.
  • Re-derived the drift-detection logic in test_linux_installs_cover_release_matrix by hand against the actual verify-python-wheels.ps1: \$pythonTags\s*=\s*(.+) matches line 77 only (. excludes newlines, and the later $pythonTags occurrences on lines 89/94 are not assignments), and the DOTALL @\((.*?)\) capture terminates on line 87 because the array body contains no parentheses. Filtering to manylinux/musllinux and stripping the arch suffix yields exactly {manylinux_2_34, manylinux_2_28, musllinux_1_2}. Adding cp315 to the canonical $pythonTags does make the assertion fail. The fix is real and it now tracks the canonical source.
  • Checked step ordering in stages.yml for all five jobs: the template is inserted after the ODBC injection, after the glibc-2.28 injection, and after both auditwheel repair / retag steps, immediately before PublishPipelineArtifact@1.
  • Verified the Windows step's python ... --wheel $wheels[0].FullName actually passes the resolved path: PowerShell evaluates index and member access in native-command argument mode (tested locally — it is not subject to the "$a[0]" expandable-string gotcha).
  • Confirmed select_driver matches str(file) against a forward-slash path, which is what importlib.metadata RECORD entries use on Windows as well, so the Windows arms are not silently unmatchable.
  • Confirmed the unconditioned UsePythonVersion@0 tasks in the new template are not a new PR-build failure risk: build-python-wheels-template.yml already runs the identical version/architecture selections in the same jobs without a PR guard, including architecture: arm64 for 3.11-3.14.
  • Not run: the pytest suites. This machine has no non-stub Python interpreter (only the Microsoft Store python.exe alias; no py, uv, or installed distribution), so I relied on static derivation plus the referenced build 175810. This is the same gap reported by the two prior unattended reviews.
  • gh pr checks 580: all 19 checks pass, including coverage-report and the full mssql-rs Pull request validation pipeline. No CI failure to attribute to this diff.

Findings

Blocking

None.

Suggestion

  1. The Windows and macOS halves of the install matrix still restate literals, so the drift gap this PR exists to close remains open for 32 of the 44 wheels. 9ed77aa7 fixed this for Linux, but test-python-wheel-installs-template.yml carries its own hardcoded pythonVersions default (3.10-3.14) that duplicates the independent default in build-python-wheels-template.yml, and test_python_wheel_install_gate_precedes_artifact_publication asserts the effective versions against the same literal list it is meant to constrain. Add 3.15 to the build template and to $pythonTags in verify-python-wheels.ps1 and the result is: Linux fails loudly (good), while Windows x64, Windows ARM64 and macOS silently keep install-testing only 3.10-3.14 — both assertions still pass and the new version's wheels ship without ever being clean-installed. Deriving the default from, or cross-checking it against, verify-python-wheels.ps1 the way the Linux test now does would close the remaining two thirds. (Windows ARM64 is a third copy, since stages.yml passes 3.11-3.14 explicitly to both templates.)

Nit

  • scripts/test-python-wheel-install.py:13 — import sys is unused, and the corresponding monkeypatch.setattr(wheel_install.sys, "platform", "darwin") in test_select_driver_uses_native_slice_for_universal2 is dead setup: expected_driver_path keys off the wheel's platform tag and platform.machine() and never reads sys.platform. The platform.machine patch alone is what makes that test meaningful.

Comment thread .pipeline/templates/test-python-wheel-installs-template.yml
Comment thread scripts/test-python-wheel-install.py Outdated

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.

Unattended automated code review — this review was posted without human confirmation. It is a COMMENT only, not an approval.

Summary

Reviewed the complete merge-base diff (0185d708 → d7eb72a7), the linked AB#48227 task, all existing inline threads, review bodies, top-level comments, checks, and the directly affected wheel build, ODBC injection, repair/retag, installation, and artifact-publication paths. The latest commit closes the remaining Windows/macOS matrix-drift coverage and removes the dead macOS test setup; no genuine new findings were identified.

Blocking

None.

Medium

None.

Low

None.

Suggestion

None.

Nit

None.

Targeted validation

  • All current PR checks pass, including the full PR validation pipeline and coverage-report; the existing coverage report states 100% diff coverage and 93.9% overall coverage.
  • uv run --python 3.13 --no-project python -m py_compile passed for the three changed Python files.
  • bash -n scripts/test-python-wheel-installs-linux.sh passed.
  • git diff --check 0185d708561de0f8f64348fe515b96c8500280ef..HEAD passed.
  • Focused pytest execution was attempted, but dependency retrieval failed noninteractively with a PyPI TLS handshake error.

@shiwanigupta0809

Copy link
Copy Markdown
Contributor

Unattended automated code review posted with no findings: #580 (review)

Category counts: Blocking 0, Medium 0, Low 0, Suggestion 0, Nit 0.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unattended automated review — generated by GitHub Copilot on behalf of Vahid Beiranvand (@Vahid-b), without human confirmation. This is a COMMENT only, not an approval, and does not satisfy the human review requirement. Findings may be wrong; push back on anything that looks off.

Summary

Reviewed the complete merge-base diff (0185d708 -> d7eb72a7, 8 files) in an isolated detached worktree, plus the surrounding ODBC injection, glibc-2.28 repair/retag, wheel-verification and artifact-publication paths, the AB#48227 reference in the description, every inline thread, all prior review bodies and top-level comments, and gh pr checks. The two items I raised at 9ed77aa7 are genuinely fixed at this head and I have not restated them: test_windows_and_macos_install_matrix_tracks_release_python_tags now cross-checks the template default and the Windows ARM64 override against verify-python-wheels.ps1, and the dead sys import plus its monkeypatch line are gone.

No blocking issues. One item is about the evidence backing the change rather than the code; one is a narrow residual of the drift-hardening work.

Verification performed

  • Confirmed microsoft/mssql-rs, PR #580, author Theekshna, head d7eb72a724177a679f1fae7b5b158218cef3d97a, merge base 0185d708561de0f8f64348fe515b96c8500280ef against a freshly fetched origin/main.
  • Re-checked all 39 entries of REQUIRED_ODBC_SYMBOLS against mssql-odbc/src/api/exports.rs: all 39 are exported unconditionally; the file's only #[cfg(...)]-gated export is the non-Windows ANSI SQLSetConnectAttr, which is not in the list. The export contract cannot fail on a typo or a platform gate.
  • Confirmed testPythonWheelInstalls is set by OfficialPythonWheelsBuild.yml only, and that all five ${{ if }} sites in stages.yml additionally require buildOdbcNative and buildPythonWheels.
  • Re-verified gate placement in all five build jobs: the template lands after ODBC injection, after the glibc-2.28 injection, and after both auditwheel repair / retag / cp steps, immediately before PublishPipelineArtifact@1.
  • Re-derived _canonical_python_versions() and test_linux_installs_cover_release_matrix by hand against the actual verify-python-wheels.ps1: $pythonTags yields {3.10..3.14}, and the DOTALL @\((.*?)\) capture of $platforms filtered to manylinux/musllinux and stripped of the arch suffix yields exactly {manylinux_2_34, manylinux_2_28, musllinux_1_2}, matching PLATFORM_TAGS.
  • Confirmed the Windows step's python ... --wheel $wheels[0].FullName passes the resolved path: PowerShell evaluates index plus member access in native-command argument mode (retested locally on this host).
  • Confirmed shopt -s nullglob is in effect for the macOS extensions=(...) glob, so a missing extension yields a count of 0 and a loud failure rather than a literal path.
  • gh pr checks 580: all checks pass at this head, including the full mssql-rs Pull request validation and coverage-report. No CI failure attributable to the diff.
  • Not run: the pytest suites. This machine has no non-stub Python interpreter (only the Microsoft Store python.exe/python3.exe aliases; no py, no uv, no installed distribution), so I relied on static derivation plus the packaging tests that PR validation runs via validation-stages.yml.

Findings

Blocking

None.

Suggestion

  1. The cited official-build evidence is five commits stale, and the parts of this gate it would exercise are unreachable from PR CI - see the inline comment on .pipeline/OneBranch/OfficialPythonWheelsBuild.yml.
  2. The Windows ARM64 half of the new drift guard re-hardcodes the cp310 exclusion instead of deriving it - see the inline comment on scripts/test_release_pipeline.py.

Nit

None.

Scope note (not a finding)

The "depends on libraries available only in the build image" class is closed for Linux only: those 30 wheels are installed in the stock PyPA manylinux/musllinux images, while the 9 Windows and 5 macOS installs run on the build agent itself, which carries the toolchain that produced the binaries. The description is explicit about the Linux rationale, so this is a stated scope boundary rather than a defect - worth keeping in mind if a future consumer-side load failure slips through this gate.

Comment thread .pipeline/OneBranch/OfficialPythonWheelsBuild.yml
Comment thread scripts/test_release_pipeline.py Outdated

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.

Unattended automated code review — posted without human confirmation. This is a COMMENT only, not an approval.

Reviewed the complete merge-base diff, linked AB#48227, all existing discussions/checks, and the directly affected wheel build, injection, repair/retag, installation, and publication paths. No genuine new findings were identified. The PR description already records that the official 44-wheel validation must be rerun at the current head.

Blocking

None.

Medium

None.

Low

None.

Suggestion

None.

Nit

None.

Validation

  • Python 3.13 py_compile passed for the three changed Python files.
  • bash -n scripts/test-python-wheel-installs-linux.sh passed.
  • git diff --check 0185d708561de0f8f64348fe515b96c8500280ef..HEAD passed.
  • Focused pytest was attempted, but dependency retrieval failed non-interactively with a PyPI TLS handshake error.
  • GitHub/CodeQL/coverage checks pass; the current Azure DevOps PR validation run remains pending.

@shiwanigupta0809

Copy link
Copy Markdown
Contributor

Unattended automated code review completed with no findings: #580 (review)

Category counts: Blocking 0, Medium 0, Low 0, Suggestion 0, Nit 0.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unattended automated review — generated by GitHub Copilot on behalf of Vahid Beiranvand (@Vahid-b), without human confirmation. This is a COMMENT only, not an approval, and does not satisfy the human review requirement. Findings may be wrong; push back on anything that looks off.

Summary

Reviewed the complete merge-base diff (0185d708 -> 7891f723, 8 files) in an isolated detached worktree, plus the surrounding ODBC injection, glibc repair/retag, signing, and artifact-publication paths. Since the previous review at d7eb72a7, the only change is 7891f723, which replaces the hard-coded - {"3.10"} in test_windows_and_macos_install_matrix_tracks_release_python_tags with _canonical_win_arm64_python_versions(), derived from verify-python-wheels.ps1's own Where-Object filter.

No blocking, medium, or low findings.

Verification performed

  • Re-ran the new win_arm64 filter regex against the live .pipeline/scripts/verify-python-wheels.ps1 (.NET regex, same semantics as re.DOTALL): it matches, captures $_ -ne 'cp310', and yields exclusion {3.10}, so expected_arm64_versions resolves to {3.11, 3.12, 3.13, 3.14} — exactly the Windows_ARM64 override in stages.yml. If the filter is ever rewritten (e.g. -notin @(...)), the assert match fires with the explicit message rather than silently passing.
  • Cross-checked every entry of REQUIRED_ODBC_SYMBOLS (39) against mssql-odbc/src/api/exports.rs (50 exported entry points): all 39 are present, none misspelled, no ANSI/W variant mismatch.
  • Cross-checked expected_driver_path() against both sides of the contract — inject-odbc-into-wheels.py's _WIN_*/_GLIBC_*/_MUSL_*/_MACOS_* constants and Get-ExpectedOdbcMembers in verify-python-wheels.ps1 — all eight platform/arch paths agree.
  • Confirmed inject-odbc-into-wheels.py regenerates RECORD, so distribution.files really can see the injected driver; select_driver's exact-path match is therefore meaningful rather than vacuous.
  • Confirmed the gate runs after ESRP driver/wheel signing (Windows) and after injection plus manylinux repair/retag (Linux) and before PublishPipelineArtifact@1 in all five jobs, matching the stated goal.
  • Confirmed the mirrored images the Linux script pulls (import/python-build/{manylinux_2_34,manylinux_2_28,musllinux_1_2}_{x86_64,aarch64}) all exist in .pipeline/sync-container-images.yml.
  • Probed the PowerShell argument-mode expansion of $wheels[0].FullName (index + property in command argument position) — expands correctly, no quoting bug.
  • UsePythonVersion@0 with architecture: arm64 and no PR-build condition mirrors the existing build-python-wheels-template.yml pattern on the same RUST-ARM64-WUS3 pool, so it introduces no new agent assumption.
  • Test-merged origin/main into 7891f723: clean auto-merge, and the merged result still carries all five install-template call sites, macOS-15, and scripts/test_python_wheel_install.py in the packaging pytest list. Both this branch and main grew scripts/test_release_pipeline.py, but in non-overlapping regions.

Blocking

None.

Suggestion

None.

Nit

None.

Merge readiness (not a code finding)

Two gating items are outside the diff itself:

  1. Required validation is red at this head. gh pr checks reports mssql-rs Pull request validation failing (build 176490), specifically Build mssql-python mssql-python suite on mssql-odbc driver (cross-repo). Nothing in this diff touches driver code, and the packaging job that does exercise the new scripts/test_python_wheel_install.py passed — so this looks unrelated. Note the same job passes on PRs #597/#599/#600, and this branch sits five commits behind origin/main, which has since merged substantial mssql-odbc/mssql-tds changes (#586, #602). A rebase onto main and a re-run would confirm whether the failure is stale-base drift rather than a real regression. Per .github/instructions/pr-workflow.instructions.md, validation must be green on the latest commit.
  2. The Official Python Wheels Build re-run is still outstanding, exactly as your own stale-validation note in the description says: 175810 ran at 757299c6, and none of the new install steps, test-python-wheel-installs-linux.sh, or the --wheel/--verify/--verify-driver-exports paths execute under Build.Reason == 'PullRequest'. Five commits have landed in that unexercised region since. Please re-run at 7891f723 (or later) and refresh the Validation section before merging.

With those two items resolved, the PR appears ready for human review. This is not an approval.

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.

Unattended automated code review — posted without human confirmation. This is a COMMENT only, not an approval.

Summary

Reviewed the complete merge-base diff (0185d708 → 7891f723, 8 files), linked AB#48227 (Task, New: “Add ODBC installer tests in official wheel pipeline”), all paginated inline comments/review bodies/top-level comments, checks, and the directly affected wheel build, injection, repair/retag, installation, and publication paths. The existing review threads are addressed, and the PR description explicitly records the remaining stale official-build validation; I found no genuine new code findings.

Blocking

None.

Medium

None.

Low

None.

Suggestion

None.

Nit

None.

Targeted validation

  • git diff --check 0185d708561de0f8f64348fe515b96c8500280ef..HEAD passed.
  • bash -n scripts/test-python-wheel-installs-linux.sh passed.
  • Python 3.13 py_compile passed for the three changed Python files.
  • Focused pytest was attempted, but pytest retrieval failed non-interactively with a PyPI TLS handshake error.
  • Current PR validation is red only in the cross-repo mssql-python suite on mssql-odbc driver job; this diff does not change driver code, and that status was already discussed in prior review.

@shiwanigupta0809

Copy link
Copy Markdown
Contributor

Unattended automated code review completed with no findings: #580 (review)

Category counts: Blocking 0, Medium 0, Low 0, Suggestion 0, Nit 0.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unattended automated review - generated without human confirmation. This is a COMMENT only, not an approval, and does not satisfy the human review requirement. Findings may be wrong; push back on anything that looks off.

Summary

Reviewed the complete merge-base diff (0185d708 -> 7891f723, 8 files) in an isolated detached worktree, plus the surrounding ODBC injection, glibc repair/retag, image-mirroring and artifact-publication paths, the AB#48227 reference, every inline thread, all prior review bodies and top-level comments, and gh pr checks. The previously raised driver-selection, matrix-drift, PR-guard, dead-sys-patch and win_arm64-exclusion items are all genuinely closed at this head; I re-verified each rather than restating them.

Unlike the three prior unattended passes I was able to obtain a real interpreter and run the suites, plus exercise the Windows install path end to end against a real ODBC-exporting DLL. No blocking findings. One suggestion about a property the new pipeline tests do not constrain.

Verification performed

  • Confirmed microsoft/mssql-rs, PR #580, author Theekshna, head 7891f723834b2638614f237f30f1735fef93887b, merge base 0185d708561de0f8f64348fe515b96c8500280ef against a freshly fetched origin/main.
  • Ran the tests. Bootstrapped Python 3.12.7 from the NuGet python package plus pytest 9.1.1 / PyYAML 6.0.3, then python -m pytest scripts/test_python_wheel_install.py scripts/test_release_pipeline.py -q -> 164 passed.
  • Mutation-tested both drift guards and confirmed they are non-vacuous. Adding 'cp315' to $pythonTags in verify-python-wheels.ps1 fails both test_linux_installs_cover_release_matrix and test_windows_and_macos_install_matrix_tracks_release_python_tags. Widening the Where-Object filter to { $_ -ne 'cp310' -and $_ -ne 'cp311' } fails the ARM64 half with {'3.11','3.12','3.13','3.14'} == {'3.12','3.13','3.14'}. Both mutations reverted; worktree clean.
  • Exercised the Windows runtime path end to end, which no check on this PR runs. Built a probe wheel with the real maturin layout (mssql_py_core/__init__.py + mssql_py_core/libs/windows/x64/mssqlodbc.dll) whose payload is C:\Windows\System32\odbc32.dll, so the ODBC entry points genuinely exist, then ran python scripts\test-python-wheel-install.py --wheel <probe>. Result: venv creation, pip install --no-index --no-deps, the -I child with --wheel-name, metadata/version check, select_driver, WinDLL load, SQLAllocHandle(SQL_HANDLE_ENV) and SQLFreeHandle all succeeded - Verified mssql-python-rs 0.1.0: ...\mssql_py_core\libs\windows\x64\mssqlodbc.dll, exit 0. A second probe with a non-PE payload failed loudly at import, as intended.
  • Confirmed select_driver's exact-string match is valid on Windows. pip-installed a probe wheel and dumped importlib.metadata.distribution('mssql-python-rs').files: every entry is forward-slashed ('mssql_py_core/libs/windows/x64/mssqlodbc.dll'), so the posix-style expected never silently fails to match on Windows.
  • Cross-checked REQUIRED_ODBC_SYMBOLS programmatically, not by eye: parsed all 52 no_mangle sites under mssql-odbc/src (50 distinct entry points) with their surrounding #[cfg(...)] attributes. All 39 required symbols are exported, none is platform-gated (the only gated export, non-Windows SQLSetConnectAttr, is correctly absent from the list). The macOS nm -gU gate cannot fail on a typo or a cfg gate.
  • Verified the mirrored image references resolve. .pipeline/sync-container-images.yml line 1349-1354 mirrors exactly import/python-build/{manylinux_2_34,manylinux_2_28,musllinux_1_2}_{x86_64,aarch64}:latest into $(GHCR_NAMESPACE), and an anonymous GHCR manifest probe for manylinux_2_28_x86_64 and musllinux_1_2_aarch64 returned HTTP 200 for both - so the ghcr.io/microsoft/mssql-rs/import/python-build/... path (note the import/ segment, unlike the _rust images already pulled in stages.yml) is correct and anonymously pullable.
  • Confirmed vmImage: macOS-15 on Azure Pipelines is the Intel x64 image (the macOS-15-arm64 preview label was withdrawn), matching the description's claim that the hosted runner validates installation and the x64 slice only; and that 29e9747f introduced the macOS-14 -> macOS-15 move, so it was covered by build 175810.
  • Confirmed expected_driver_path's eight platform/arch mappings match both inject-odbc-into-wheels.py's _WIN_*/_GLIBC_*/_MUSL_*/_MACOS_* constants and Get-ExpectedOdbcMembers in verify-python-wheels.ps1.
  • Probed PowerShell argument-mode expansion of $wheels[0].FullName on this host: index plus property expands to a single correct argument; no quoting bug.
  • Confirmed scripts/test_python_wheel_install.py has exactly one CI call site (validation-stages.yml:130) and that it was updated.

Findings

Blocking

None.

Suggestion

  1. The new pipeline tests constrain the gate's position relative to artifact publication but not relative to the steps that produce its input - see the inline comment on scripts/test_release_pipeline.py.

Nit

None.

Merge readiness (not code findings)

  1. Required validation is red at this head. mssql-rs Pull request validation fails (build 176490) in Build mssql-python mssql-python suite on mssql-odbc driver (cross-repo). This diff changes no Rust or driver code, and the packaging job that actually runs the new scripts/test_python_wheel_install.py passes, so it is not attributable to the change. origin/main has since merged #606, which pins both cross-repo Python jobs to an approved commit and removes the floating-main fallbacks - the most likely cause of this failure. Merging main into the branch and re-running should confirm. Per .github/instructions/pr-workflow.instructions.md, validation must be green on the latest commit.
  2. The Official Python Wheels Build re-run is still outstanding, as your own staleness note says. I independently confirmed the exposure: every step in test-python-wheel-installs-template.yml carries ne(variables['Build.Reason'], 'PullRequest') and testPythonWheelInstalls is set only by OfficialPythonWheelsBuild.yml (which declares pr: none), so test-python-wheel-installs-linux.sh and the --wheel/--verify/--verify-driver-exports paths never execute under any check here. Since the cited build 175810 at 757299c6, PLATFORM_TAGS, the macOS extract/lipo/nm block and the three runtime condition: keys all changed. My end-to-end probe above covers the Windows leg on real code; the Linux and macOS legs still need the official run at 7891f723 or later.

With those two resolved, the PR looks ready for human review. This is not an approval.

Comment thread scripts/test_release_pipeline.py

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.

Unattended automated code review — posted without human confirmation. This is a COMMENT only, not an approval.

Summary

Reviewed the complete merge-base diff (0185d708 → 7891f723, 8 files), linked AB#48227, all paginated inline comments/review bodies/top-level comments, current checks, and the directly affected wheel build, injection, repair/retag, installation, and publication paths. I found no genuine new findings; the existing current-head suggestion about asserting that the gate follows every wheel-transforming step was not duplicated.

Blocking

None.

Medium

None.

Low

None.

Suggestion

None.

Nit

None.

Targeted validation

  • git diff --check 0185d708561de0f8f64348fe515b96c8500280ef..HEAD passed.
  • bash -n scripts/test-python-wheel-installs-linux.sh passed.
  • Python 3.13 py_compile passed for the three changed Python files.
  • Focused pytest was attempted, but PyYAML retrieval failed non-interactively with a PyPI TLS handshake error.
  • Current checks remain red only in the previously discussed cross-repo mssql-python suite on mssql-odbc driver job; packaging, CodeQL, coverage, linked-issue, and other platform jobs pass.

@shiwanigupta0809

Copy link
Copy Markdown
Contributor

Unattended automated code review completed with no new findings: #580 (review)

Category counts: Blocking 0, Medium 0, Low 0, Suggestion 0, Nit 0.

Copilot AI review requested due to automatic review settings September 21, 2026 06:37
@Theekshna
ttk (Theekshna) force-pushed the dev/tkotian/official-wheel-install-smoke branch from 7891f72 to c38149b Compare September 21, 2026 06:37

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.

Copilot review overview

🟡 Changes recommended

The macOS gate uses invalid lipo argument ordering, and the corrected current head still needs an official validation run.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity · 1 Low severity

Open (2)
Resolved since last review (1)

Comment thread .pipeline/templates/test-python-wheel-installs-template.yml Outdated
Comment thread .pipeline/OneBranch/OfficialPythonWheelsBuild.yml

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.

Copilot review overview

🔵 Needs a closer look

The cross-platform release gate has not been executed at the current head after several changes to platform-specific paths.

Review effort: Balanced
Findings: None

Resolved since last review (2)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated review — generated by GitHub Copilot on behalf of Vahid Beiranvand (@Vahid-b), without human confirmation. This is a COMMENT only, not an approval, and it does not satisfy the human review requirement. Findings may be incomplete or wrong; push back on anything that looks off.

Summary

Reviewed the complete merge-base diff (6a11b315 → 91392208, 8 files) in a detached isolated worktree, plus the surrounding ODBC injection / glibc repair / retag / artifact-publication steps, the AB#48227 reference, every review thread, all prior review bodies and top-level comments, and gh pr checks.

Note the merge base moved since the last automated pass: the branch was rebased onto newer main, so 7891f723..91392208 also drags in unrelated main work (C++ CodeQL, ODBC Miri legs, the Alpine 3.19/3.20 matrix trim). Restricted to the eight files this PR actually owns, the only change since the last reviewed head is 91392208, which adds the ordering assertion requested in the previous round.

No blocking findings, no suggestions, no nits. I re-derived the previously raised items rather than restating them, ran the suites, mutation-tested the new assertion, and adjudicated the one disputed thread — the author is correct there and the bot is wrong.

Verification performed

  • Confirmed live repo microsoft/mssql-rs, PR #580, author Theekshna, head 9139220866f05543e2bb568deb9ff33a0eeb87d4, not draft, OPEN; merge base 6a11b315128cabd154f60bbc2024dc4396cd9e52 against a freshly fetched origin/main. Revalidated immediately before posting.
  • Ran the suites. Bootstrapped Python 3.12.7 (NuGet) + pytest 9.1.1 / PyYAML 6.0.3, then python -m pytest scripts/test_python_wheel_install.py scripts/test_release_pipeline.py -q → 178 passed.
  • Mutation-tested 91392208's new assertion and confirmed it is non-vacuous. Moved the Linux x64 install-gate template from after Repair glibc-2.28 wheels (Linux x64) to before Repair glibc wheels into manylinux (Linux x64). Result: test_python_wheel_install_gate_precedes_artifact_publication[Linux_x64-...] fails with assert 16 < 15 / where 16 = max([11, 13, 14, 16]); the other 4 parametrizations still pass. Reverted; git status --porcelain is empty.
  • Confirmed the assertion's anchors exist in every gated job, so assert transform_indices cannot silently pass on an empty list: Windows x64/ARM64 and macOS match Inject ODBC driver into ...; Linux x64/ARM64 match both Inject ODBC driver into wheels (Linux …) and Repair glibc … (steps at stages.yml:367/383/396/414, gate at 417). A rename of those steps fails loudly rather than degrading to a no-op.
  • Re-derived the ODBC export contract at this head (worth redoing — the rebase pulled real mssql-odbc changes in). Parsed every #[unsafe(no_mangle)] pub … extern "C" fn under mssql-odbc/src: 49 exports; all 39 entries of REQUIRED_ODBC_SYMBOLS are present and none is #[cfg]-gated. The single gated export in the driver is SQLSetConnectAttr under not(windows), correctly absent from the required list. So the macOS nm -gU gate cannot fail on a typo or a cfg gate.
  • Confirmed maturin build --target universal2-apple-darwin (build-python-wheels-template.yml:106) makes the extension a genuine fat binary, while stages.yml:14 documents the ODBC driver slices as separate thin binaries — so -verify_arch x86_64 arm64 on the extension and single-arch verifies on each libs/macos/<arch>/lib/mssqlodbc.dylib are each the right assertion for their target.
  • Checked UsePythonVersion@0 with architecture: arm64: already established in-repo practice (build-python-wheels-template.yml:172, PublishFeeds-Sandbox.yml:430), not a new risk.
  • Checked the $(echo … | tr -d '.') command substitution inside the macOS script: block against ADO macro syntax; the repo already relies on this exact behaviour ($(whoami) in stages.yml), so it is consistent rather than novel.
  • Confirmed all review threads are currently resolved, and that no copilot-auto-review v3 marker exists for this head (prior markers: 326af0e8, 0ea6599b, 9ed77aa7, 7891f723).

Adjudication of the open lipo thread — the author is right

The bot finding on test-python-wheel-installs-template.yml:80-82 claimed the input file must follow -verify_arch. That is backwards, and applying the suggested reorder would break the macOS gate. From the lipo(1) man page:

-verify_arch arch_type ... — Take one input file and verify the specified arch_types are present in the file. … Because more than one arch_type can be verified at once, all of the input files must appear before the -verify_arch flag on the command-line.

with synopsis lipo input_file command [option...]. The current form — lipo "${extensions[0]}" -verify_arch x86_64 arm64 — is exactly the documented one. ttk (@Theekshna)'s rebuttal stands; no change needed. (Copilot's latest overview at 9139220 has already dropped this finding.)

Findings

Blocking

None.

Suggestion

None.

Nit

None.

Required CI

No required-CI failures. mssql-rs Pull request validation (build 176870) is still pending at this head — several Build Stage legs and coverage-report are mid-run; Build MacOS, Build Windows ARM, Kerberos, the cross-repo mssql-python suite on mssql-odbc driver, CodeQL and CLA are green. The cross-repo failure flagged in the previous round is resolved at this head. Per .github/instructions/pr-workflow.instructions.md, validation still needs to land green on the final commit.

Merge readiness (not a code finding)

The staleness note in your description is accurate and remains the one real residual risk, so I am not re-filing it as a finding — only confirming the exposure independently. Every step in test-python-wheel-installs-template.yml carries ne(variables['Build.Reason'], 'PullRequest'), and testPythonWheelInstalls: true is set only by OfficialPythonWheelsBuild.yml, which triggers on stable. So test-python-wheel-installs-linux.sh and the --wheel / --verify / --verify-driver-exports paths of test-python-wheel-install.py execute under no check on this PR — only the pytest units do. Since the cited build 175810 at 757299c6, the macOS extract/lipo/nm block, PLATFORM_TAGS, the driver-path resolver and the runtime condition: keys have all changed, so the macOS and Linux runtime legs have never executed as written. An Official Python Wheels Build at 9139220 (or later) before merge is the thing that closes it.

With the validation run refreshed and PR validation green, this PR appears ready for human review. It has not been approved.

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.

Unattended automated code review — posted without human confirmation. This is a COMMENT only, not an approval, and does not satisfy the human review requirement.

Summary

Reviewed the complete merge-base diff (6a11b315 → 91392208, 8 files) in a dedicated worktree, PR title/body, linked AB#48227, all paginated inline comments/reviews/top-level comments, current checks, and the directly affected wheel build, signing/injection, repair/retag, installation, and publication paths. Prior findings are addressed or already tracked; I found no new code findings.

Blocking

None.

Medium

None.

Low

None.

Suggestion

None.

Nit

None.

Validation

  • All current GitHub and Azure DevOps PR checks pass at head 91392208, including PR validation, cross-repo jobs, CodeQL, and coverage.
  • git diff --check 6a11b315128cabd154f60bbc2024dc4396cd9e52..HEAD passed.
  • bash -n scripts/test-python-wheel-installs-linux.sh passed.
  • Python 3.12 py_compile passed for the three changed Python files.
  • Focused pytest was attempted, but pytest/PyYAML retrieval failed non-interactively with a PyPI TLS handshake error. The same focused suites passed in current-head review evidence and PR validation.
  • AB#48227 lookup succeeded: Task, New, “Add ODBC installer tests in official wheel pipeline”; the PR scope matches it and the work item links PR #580.

The PR description cites Official Python Wheels Build 176920 succeeding at the current head across all 44 final wheels, closing the previously documented end-to-end validation gap.

@shiwanigupta0809

Copy link
Copy Markdown
Contributor

Unattended automated code review completed with no findings: #580 (review)

Category counts: Blocking 0, Medium 0, Low 0, Suggestion 0, Nit 0.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Note

This is an automated review generated by GitHub Copilot. It is advisory only, has not been vetted by a human, and is not an approval. Please verify each point before acting on it.

Summary

This PR adds a release gate to the Official Python Wheels Build that clean-installs and smoke-exercises all 44 final wheels after signing, ODBC injection, and Linux repair/retagging, before each platform artifact is published. The design is sound: the gate runs in-job after every wheel-transforming step and before PublishPipelineArtifact@1, Linux testing uses stock PyPA manylinux/musllinux images (mirrored through Microsoft GHCR) rather than the custom build images so undeclared runtime dependencies cannot be masked, and the verifier drives a real SQLAllocHandle/SQLFreeHandle round trip through ctypes rather than only asserting file presence.

The PR-CI-side unit tests are the strongest part of the change, because the gate itself never executes in PR validation (every runtime step carries ne(variables['Build.Reason'], 'PullRequest')). I verified by mutation that the two cross-check tests added during review are non-vacuous. No blocking issues found. All three findings below are the same class those cross-check tests exist to close: literals in the new code that restate a canonical source without being derived from or checked against it. Each fails loudly in the Official build rather than shipping a bad wheel, so they are shift-left gaps, not correctness defects.

All 8 prior review threads are resolved, the Validation section has been refreshed to Official build 176920 at this exact head, and all required checks are green.

Verification performed

  • Confirmed live repository microsoft/mssql-rs and live author Theekshna before reading the diff and again immediately before posting. Head SHA 9139220866f05543e2bb568deb9ff33a0eeb87d4; not a draft.
  • Merge base against origin/main (3248bcef): 6a11b315128cabd154f60bbc2024dc4396cd9e52. Reviewed the full $BASE..HEAD diff (8 files, +992/-2) in a detached worktree, not the main checkout.
  • Read the PR title/body, all reviews, all issue comments, and all 8 review threads (pulls/580/reviews, pulls/580/comments, issues/580/comments, plus reviewThreads via GraphQL for resolution state). Nothing below duplicates an existing thread.
  • gh pr checks 580 — 19/19 passing, including mssql-rs Pull request validation (ADO build 176870), coverage-report, CodeQL, and both cross-repo mssql-python legs. No required failures.
  • Ran the PR's own tests: python3 -m pytest scripts/test_python_wheel_install.py -q → 20 passed; python3 -m pytest scripts/test_release_pipeline.py -q -k 'wheel_install_gate or install_matrix_tracks or macos_wheel_install_gate' → 7 passed.
  • bash -n scripts/test-python-wheel-installs-linux.sh → clean.
  • Mutation, confirming the review-added drift tests are not vacuous: added 'cp315' to $pythonTags in .pipeline/scripts/verify-python-wheels.ps1 → test_linux_installs_cover_release_matrix fails and test_windows_and_macos_install_matrix_tracks_release_python_tags fails. Good.
  • Mutation behind finding 1: changed libs/linux/glibc/x86_64/lib/mssqlodbc.so → libs/linux/glibc/x86_64/mssqlodbc.so in both canonical sources (Get-ExpectedOdbcMembers in verify-python-wheels.ps1 and _GLIBC_X64 in inject-odbc-into-wheels.py) → all 27 new tests still pass.
  • Mutation behind finding 2: changed macosx_15_0_universal2 → macosx_16_0_universal2 in verify-python-wheels.ps1's $platforms → all 27 new tests still pass.
  • Measured finding 3 by extracting pub unsafe extern "C" fn SQL* from mssql-odbc/src/api/exports.rs (50 symbols) and diffing against REQUIRED_ODBC_SYMBOLS (39): no required symbol is missing from the driver (so no false-failure risk), 11 exported entry points are outside the gate.
  • Verified in PowerShell that $wheels[0].FullName resolves correctly in native-command argument position (& cmd /c echo $wheels[0].FullName → the path), so the Windows step is not affected by the argument-mode parsing trap.
  • Checked that the new template's unconditioned UsePythonVersion@0 matches the existing pattern in build-python-wheels-template.yml (lines 93-94, 167-172) — consistent with house style, not filed.
  • All mutations reverted; git status --porcelain in the worktree is empty.
  • Not verified: the ADO work item AB#48227 and Official Python Wheels Build 176920 (no Azure DevOps access from this session), so the "44 wheels verified at this head" claim rests on the author's report. I also could not execute any of the pipeline-side code — the Linux Docker flow, the macOS lipo/nm block, and the --wheel/--verify/--verify-driver-exports runtime paths are all PR-guarded and run only in the Official build. No msodbcsql or SqlClient checkout exists on this host; the diff contains no Rust or ODBC-surface changes, so parity review is not applicable.

Findings

Blocking

None.

Suggestion

1. scripts/test-python-wheel-install.py:84-108 — expected_driver_path restates the canonical package layout instead of deriving it, and nothing cross-checks the two.

The injected package paths now exist in three independent places: _GLIBC_X64/_MUSL_X64/etc. in scripts/inject-odbc-into-wheels.py:47-50, Get-ExpectedOdbcMembers in .pipeline/scripts/verify-python-wheels.ps1, and the new expected_driver_path. test_expected_driver_path_matches_consumer_resolver pins the third against its own transcribed literals, so a coordinated change to the first two goes unnoticed here.

Measured, not inferred: I changed the glibc x86_64 path in both canonical sources (dropping the /lib/ segment) and all 20 tests in scripts/test_python_wheel_install.py plus the 7 targeted test_release_pipeline.py tests still passed. Mutation reverted.

To be fair to the change: the failure mode is loud — select_driver raises ODBC driver not found at expected package path and the Official build fails, so no bad wheel ships. But this is exactly the argument that motivated test_linux_installs_cover_release_matrix and test_windows_and_macos_install_matrix_tracks_release_python_tags in this same PR: the layout change would be caught at release time instead of in PR CI, which is the only place this gate's wiring can be checked at all. Cheap to close in the same style — parse Get-ExpectedOdbcMembers's switch -Wildcard arms out of verify-python-wheels.ps1 and assert expected_driver_path agrees for each wheel-name pattern.

2. .pipeline/templates/test-python-wheel-installs-template.yml:74 and .pipeline/OneBranch/stages.yml:586 — the macOS platform tag is now a five-way literal coupling with no cross-check.

macosx_15_0_universal2 / 15.0 / macOS-15 must agree across: $platforms in verify-python-wheels.ps1, the wheel tags --platform-tag macosx_15_0_universal2 retag in build-python-wheels-template.yml, export MACOSX_DEPLOYMENT_TARGET=15.0 (same file, line 103), the new install template's wheel glob, and the vmImage: macOS-15 this PR bumps. Nothing ties them together.

Measured: bumping $platforms to macosx_16_0_universal2 in verify-python-wheels.ps1 leaves all 27 new tests green. The macOS gate would then match zero wheels and fail with Expected one cpXXX macOS universal2 wheel, found 0 — again loud, again only at release. Deriving the glob's platform tag from $platforms (the way the Linux script's PLATFORM_TAGS now is) would close it, and would also make the vmImage ↔ deployment-target coupling explicit.

3. scripts/test-python-wheel-install.py:22-59 — REQUIRED_ODBC_SYMBOLS has no provenance and no cross-check against the driver's actual export surface.

mssql-odbc/src/api/exports.rs declares 50 #[unsafe(no_mangle)] pub unsafe extern "C" fn SQL* entry points; this list names 39. I confirmed every one of the 39 does exist in exports.rs, so there is no false-failure risk today. The 11 excluded are SQLCloseCursor, SQLConnectW, SQLGetDescFieldW, SQLGetDescRecW, SQLGetDiagFieldW, SQLGetEnvAttr, SQLGetFunctions, SQLNativeSqlW, SQLNumParams, SQLSetConnectAttr, SQLSetDescRec.

A curated consumer-contract subset is a defensible choice, but the list carries no comment saying that is what it is or where it came from, so the next reader cannot tell a deliberate subset from a stale one — and an export silently disappearing from the driver (SQLCloseCursor or SQLNumParams, say) would pass this gate. Either add a one-line comment stating the list is the mssql-python consumer contract and naming its source, or derive it from exports.rs so additions/removals surface in PR CI.

Nit

4. .pipeline/OneBranch/stages.yml:586 — the macOS-14 → macOS-15 bump changes the toolchain for every shipped macOS artifact, not just the install-test runner.

The MacOS_universal2 job builds the wheels (build-python-wheels-template.yml) and both ODBC dylibs (build-odbc-macos-template.yml, x64 and ARM64) before it install-tests them, so this one line moves the Xcode/SDK used to produce the released macOS binaries. The change looks correct and necessary — pip rejects a macosx_15_0_universal2 wheel on a macOS 14 runner, so the gate cannot work otherwise, and MACOSX_DEPLOYMENT_TARGET=15.0 is already pinned so the ABI target is unchanged. It is mentioned in the description, but only as a test-runner detail; it is the only line in this diff that changes what ships, and is worth calling out as such for whoever reviews the next macOS regression.

5. scripts/test-python-wheel-installs-linux.sh:49-50 — the release gate pulls :latest image tags.

docker pull is explicit so there is no stale-cache problem, but a release-blocking gate whose six test environments can change between the validated run and the actual release is worth pinning by digest (or an immutable tag). Low risk given the images are Microsoft-mirrored, but the cost of pinning is one line each.

Required CI failures

None. All 19 checks on 9139220866f05543e2bb568deb9ff33a0eeb87d4 are passing, including mssql-rs Pull request validation (ADO 176870), coverage-report, CodeQL, Analyze, check, license/cla, and both cross-repo mssql-python legs. mergeStateStatus is BLOCKED pending review approval only.


The findings above are all shift-left suggestions; none of them should block. This PR appears ready for human review, but it has not been approved — a maintainer still needs to review and approve it.

Theekshna Kotian and others added 12 commits September 22, 2026 10:24
… drift

- Add Build.Reason != PullRequest condition to the three install-test
  steps in test-python-wheel-installs-template.yml, matching the pattern
  used for ODBC driver injection. Currently a no-op since the only caller
  passing testPythonWheelInstalls: true has pr: none, but protects the
  path if NonOfficialPythonWheelsPublish.yml starts opting in.
- Rewrite test_linux_installs_cover_release_matrix to parse the canonical
  matrix from .pipeline/scripts/verify-python-wheels.ps1 and cross-check
  it against the bash script's PYTHON_TAGS/PLATFORM_TAGS, instead of
  asserting literals restated from the same file under test.
- Add missing trailing newlines.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ys patch

- Add test_windows_and_macos_install_matrix_tracks_release_python_tags,
  cross-checking test-python-wheel-installs-template.yml's pythonVersions
  default and the Windows ARM64 override (in both build-python-wheels and
  install-test template calls) against verify-python-wheels.ps1's canonical
  \. Closes the same self-referential gap the Linux fix in
  9ed77aa addressed, now for Windows x64/ARM64 and macOS. Verified
  non-vacuous: adding a fake cp315 to the ps1 matrix fails the new test.
- Remove the unused sys import in test-python-wheel-install.py and the
  dead monkeypatch.setattr(wheel_install.sys, ...) in its test, since
  expected_driver_path selects the macOS slice from the wheel platform
  tag plus platform.machine() and never reads sys.platform.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
test_windows_and_macos_install_matrix_tracks_release_python_tags previously
subtracted a hardcoded '3.10' to get the expected Windows ARM64 matrix,
reintroducing the literal-restatement pattern it was meant to remove.
Parse the Where-Object filter in Get-ExpectedWheelNames's win_arm64 loop
instead, so a change to that exclusion is caught rather than silently
diverging from the canonical release matrix.

Verified non-vacuous: widening the ps1 filter to also exclude cp311
(while stages.yml still ships 3.11 on Windows ARM64) fails the test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Extends test_python_wheel_install_gate_precedes_artifact_publication to
require every 'Inject ODBC driver into' / 'Repair glibc' step precede the
install-test gate, not just the publish step. Previously the test only
proved the gate ran before publish, so a misordered gate that install-tests
an un-injected wheel would still pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
PR #624 (merged to main) changed the Python wheel build from one wheel
per Python version per platform to a single cp310-abi3 stable-ABI
wheel per platform (Requires-Python >=3.10), forward-compatible with
every supported interpreter. This broke the wheel-selection glob in
the Windows/macOS install-test template and the Linux install script,
both of which computed a per-version wheel filename that no longer
exists, and invalidated the \\\-based drift-detection
assertions in test_python_wheel_install.py and test_release_pipeline.py.

The core test-python-wheel-install.py script needed no changes: it
only ever inspects a wheel's platform-tag suffix, never its Python/ABI
tag, and always runs against whichever interpreter set up the venv -
selection of *which wheel* and *which interpreters test it* were
already decoupled.

- test-python-wheel-installs-template.yml (Windows/macOS): glob the
  fixed cp310-abi3-<platform> wheel instead of a computed per-version
  tag; pythonVersions still drives which interpreters install-test it.
- test-python-wheel-installs-linux.sh: select the single cp310-abi3
  wheel once per (platform, arch), then loop PYTHON_TAGS purely as
  interpreters to test that fixed wheel with.
- test_python_wheel_install.py: wheel-name fixtures updated to
  cp310-abi3; test_linux_installs_cover_release_matrix now checks the
  interpreter floor against verify-python-wheels.ps1's Requires-Python
  assertion instead of a nonexistent \ list.
- test_release_pipeline.py: replaced \_canonical_python_versions\/
  \_canonical_win_arm64_python_versions\ with a
  \_wheel_requires_python_floor\ helper; the Windows/macOS matrix
  drift test now checks the pythonVersions floor and the win_arm64
  exclusion against that floor.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 22, 2026 05:17
@Theekshna
ttk (Theekshna) force-pushed the dev/tkotian/official-wheel-install-smoke branch from 9139220 to f21884a Compare September 22, 2026 05:17

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.

Copilot review overview

🟢 Approval recommended

The release gates cover the canonical wheel matrix, run after final transformations, and have focused automated coverage.

Review effort: Balanced
Findings: None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Note

Unattended automated review generated by GitHub Copilot on behalf of Vahid Beiranvand (@Vahid-b), without human confirmation. This is a COMMENT only, not an approval, and does not satisfy the human review requirement. Findings may be wrong; push back on anything that looks off.

Summary

Delta re-review at f21884a8. My last pass was at 9139220; since then the branch merged main (which landed #624, the cp310-abi3 stable-ABI switch) and added f21884a8 to adapt this gate to it. The adaptation itself is correct and well-reasoned: the wheel-selection globs in the Windows/macOS template and the Linux script now target the fixed cp310-abi3-<platform> name, and PYTHON_TAGS/pythonVersions correctly degrade from "which wheels exist" to "which interpreters install-test the one wheel". The commit message's claim that test-python-wheel-install.py needed no changes holds — expected_driver_path only ever reads the trailing platform tag, never the Python/ABI tag.

Also resolved since my last pass: the Validation section now cites Official Python Wheels Build 177092 at this exact head, which closes the staleness finding from 2026-09-18.

No blocking issues. One suggestion, one nit — both new in this delta.

Verification

  • Confirmed live repository microsoft/mssql-rs (id 1018255296) and live author Theekshna before reading the diff and again immediately before posting. Head f21884a89dec0329b01edc627fa21c96ec479be5, open, not a draft.
  • Merge base against current origin/main (b758050e) is b758050e itself — the branch is fully current with main. Full PR diff is 8 files, +999/-2; reviewed in a detached worktree, not the main checkout.
  • Read the PR body, all 27 reviews, all 7 issue comments, and all review threads across pulls/580/reviews, pulls/580/comments and issues/580/comments. Nothing below restates an existing thread.
  • gh pr checks 580 — no failing checks at this head; Analyze, CodeQL, check, coverage-report, license/cla and the ADO validation legs (build 177091) all pass. mergeStateStatus is BLOCKED pending review approval only. Remaining ADO legs are pending, not failed.
  • Ran the PR's suites: python3 -m pytest scripts/test_python_wheel_install.py -q → 20 passed; python3 -m pytest scripts/test_release_pipeline.py -q -k 'wheel_install_gate or install_matrix_tracks or macos_wheel_install_gate' → 7 passed.
  • bash -n scripts/test-python-wheel-installs-linux.sh → clean.
  • Mutation behind finding 1: narrowed PYTHON_TAGS in test-python-wheel-installs-linux.sh from (cp310 cp311 cp312 cp313 cp314) to (cp310 cp311 cp312) — i.e. the Linux release gate silently stops install-testing Python 3.13 and 3.14. All 20 test_python_wheel_install.py tests and all 7 targeted test_release_pipeline.py tests still passed.
  • Control mutation (confirms the gap is Linux-specific, not general): dropped '3.14' from the install template's pythonVersions default — 5 tests failed, including test_windows_and_macos_install_matrix_tracks_release_python_tags and four test_python_wheel_install_gate_precedes_artifact_publication parametrizations. So Windows/macOS narrowing is caught; only the Linux list is unguarded.
  • All mutations reverted; git status --porcelain in the worktree is empty and both suites re-verified green afterwards.
  • Not verified: ADO work item AB#48227 and Official build 177092 (no Azure DevOps access from this session), so the "9 wheels verified at this head" claim rests on your report. 62 of 158 test_release_pipeline.py tests error with PermissionError: [Errno 13] Permission denied: 'pwsh' on this host — an environment gap (no PowerShell in the Linux test environment), unrelated to this PR; none of them are in the set this PR touches. The PR-guarded runtime paths (--wheel/--verify/--verify-driver-exports, the Linux Docker flow, the macOS lipo/nm block) still never execute in PR CI, so they remain covered only by the Official build. No Rust or ODBC-surface changes, so parity review is not applicable.

Findings

Blocking

None.

Suggestion

1. scripts/test-python-wheel-installs-linux.sh:4 — the Linux interpreter matrix lost its only cross-check in this delta, reopening the gap the review-added tests were written to close.

At 9139220, test_linux_installs_cover_release_matrix asserted set equality against the canonical list:

assert set(script_python_tags_match[1].split()) == canonical_python_tags   # from $pythonTags

f21884a8 necessarily dropped that — #624 removed $pythonTags from verify-python-wheels.ps1 entirely — and replaced it with a floor-only check:

assert min(script_python_minors) == floor_minor

That constrains the bottom of the list and nothing else. Measured, not inferred: narrowing PYTHON_TAGS to (cp310 cp311 cp312) leaves all 20 tests in test_python_wheel_install.py and all 7 targeted test_release_pipeline.py tests green. The wheel still declares Requires-Python >=3.10 with no upper bound and is installable on 3.13/3.14, but the Linux half of the gate would stop exercising them, silently.

The control mutation above shows this is specific to Linux: the same narrowing on the Windows/macOS side fails 5 tests, because test_python_wheel_install_gate_precedes_artifact_publication pins the full pythonVersions list. PYTHON_TAGS has no equivalent.

To be fair to the change: this is a shift-left gap, not a shipped-defect risk — a narrowed matrix tests less, it does not pass a bad wheel. And the ceiling genuinely has no canonical source anymore; 3.14 is now restated independently in stages.yml:247,272, build-python-wheels-template.yml:20, test-python-wheel-installs-template.yml:19, validation-stages.yml:258, containers/PYTHON_WHEELS_README.md:34 and this script, with nothing tying them together.

Cheap to close in the style already in this file: since the Windows/macOS list is already pinned, tie Linux to it rather than to the ps1, so all three platforms move together:

default_versions = next(
    parameter["default"]
    for parameter in install_template["parameters"]
    if parameter["name"] == "pythonVersions"
)
assert set(script_python_tags_match[1].split()) == {
    "cp" + version.replace(".", "") for version in default_versions
}

That keeps the existing floor assertion meaningful and restores detection of both narrowing and drift.

Nit

2. .pipeline/templates/test-python-wheel-installs-template.yml:64-90 — the macOS block now repeats wheel-invariant verification once per interpreter.

The whole - script: body sits inside ${{ each pythonVersion in parameters.pythonVersions }}, so with the default five interpreters the release gate performs the extract, all three lipo -verify_arch calls and both --verify-driver-exports (nm) passes five times against the identical wheel. Before #624 that was correct — each iteration selected a different per-version wheel. Now there is one cp310-abi3 wheel per platform, and only the pip install + import + SQLAllocHandle round trip actually varies by interpreter; the archive contents do not.

Hoisting the extract/lipo/nm block into a single step ahead of the loop would cut roughly 4/5 of that work off the macOS critical path with no loss of coverage. Note test_macos_wheel_install_gate_verifies_both_architectures asserts template.count("--verify-driver-exports") == 2, which counts occurrences in the template text, so it would still hold after the hoist.

Still open from my 2026-09-21 pass

Not re-filed, and none blocking — listed only so they are not lost behind the abi3 rebase: the expected_driver_path layout literals with no cross-check against Get-ExpectedOdbcMembers/inject-odbc-into-wheels.py; the five-way macosx_15_0_universal2 coupling; REQUIRED_ODBC_SYMBOLS having no stated provenance (39 of the driver's 50 exports); the macOS-14 → macOS-15 bump changing the toolchain for shipped macOS artifacts; and the :latest image tags in the Linux gate.


Both findings above are shift-left suggestions; neither should block. This PR appears ready for human review, but it has not been approved — a maintainer still needs to review and approve it.

…st macOS wheel verification out of interpreter loop

- test_linux_installs_cover_release_matrix: cross-check PYTHON_TAGS
  against the install template's own pythonVersions default (the same
  source that already gates Windows/macOS), instead of only checking
  the Requires-Python floor. Restores detection of both narrowing and
  drift on the Linux side after #624 removed the old \ list
  this test previously checked against.
- test-python-wheel-installs-template.yml (macOS): the wheel's
  architecture layout and driver exports are invariant across every
  interpreter under test post-#624 (one cp310-abi3 wheel per platform).
  Hoist the extract/lipo/nm verification into a single step ahead of
  the pythonVersions loop instead of repeating it once per interpreter;
  only the pip install + import + SQLAllocHandle round trip still
  varies by interpreter.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 22, 2026 07:45
@Theekshna

ttk (Theekshna) commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for the delta re-review at f21884a8 -- both findings addressed in 118305dc:

  • Suggestion 1 (Linux PYTHON_TAGS lost its cross-check): test_linux_installs_cover_release_matrix now asserts PYTHON_TAGS equals the install template's own pythonVersions default (the same source already gating Windows/macOS), instead of only checking the Requires-Python floor. Verified your narrowing mutation ((cp310 cp311 cp312)) now fails this test.
  • Nit 2 (macOS repeats extract/lipo/nm per interpreter): hoisted that verification into a single step ahead of the pythonVersions loop; only the pip-install/import/SQLAllocHandle round trip still varies per interpreter. test_macos_wheel_install_gate_verifies_both_architectures still passes since it's a template-text check.

Full packaging suite (286 tests) and YAML parse re-verified green at the new head.

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.

Copilot review overview

🟢 Approval recommended

The release gates cover the canonical wheel matrix and were validated successfully at the current head.

Review effort: Balanced
Findings: None

@Theekshna
ttk (Theekshna) merged commit a36e4b4 into main Sep 22, 2026
19 of 20 checks passed
@Theekshna
ttk (Theekshna) deleted the dev/tkotian/official-wheel-install-smoke branch September 22, 2026 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants