Publish mssql-py-core debug symbols to symbol servers (WI 45990) - #137
Draft
Saurabh Singh (saurabh500) wants to merge 9 commits into
Draft
Publish mssql-py-core debug symbols to symbol servers (WI 45990)#137Saurabh Singh (saurabh500) wants to merge 9 commits into
Saurabh Singh (saurabh500) wants to merge 9 commits into
Conversation
Mirrors the msodbcsql symbol-publishing pipeline pattern for mssql-rs. Changes: * mssql-py-core/Cargo.toml: add [profile.release] with debug="full", split-debuginfo="packed", strip="debuginfo". Shipped .so/.pyd stays small while a build-id-linked .dwp/.pdb/.dSYM is emitted separately. * scripts/build-python-wheels-in-container.sh: capture .dwp + matching .so into $SYMBOLS_OUTPUT_DIR/cpXY/ immediately after each maturin build (target/release/deps is overwritten between interpreters). * .pipeline/templates/build-python-wheels-template.yml: mount a symbols volume into the manylinux/musllinux containers; capture .dSYM.tgz on macOS and .pdb on Windows per Python version. * .pipeline/templates/publish-symbols.yml (new): reusable template with three modes — ADOOnly (SqlClientDrivers ADO Artifacts symbol server only, no service connection needed), Private (also promotes to Microsoft Internal Symbol Server), Public (also promotes to msdl.microsoft.com). Uses UseNetCoreClientTool=true + IndexableFileFormats=All for DWARF/ELF. * .pipeline/OneBranch/stages.yml: new PublishSymbols stage runs after Build, skipped on PR builds, consolidates per-target symbols and invokes template in ADOOnly mode. * .pipeline/OneBranch/NonOfficialPythonWheelsPublish.yml: wires publishSymbolsToADO=true with 30-day retention. Every main/nightly build publishes to the SqlClientDrivers ADO org symbol server. * .pipeline/OneBranch/OfficialPythonWheelsRelease.yml: adds GetSymbolsVersion + InternalSymbolServer + PublicSymbolServer stages (mirrors msodbcsql-Symbol-Server.yml). Fixes a pre-existing version-drift bug — release version is now read from Cargo.toml at resources.pipeline.officialBuild.sourceCommit, plus a wheel-filename cross-check aborts release if the built payload doesn't match. Default symbol retention on release is 0 (indefinite); Public stage always forces 0 per Microsoft policy. Prerequisites (require ADO admin action, not in this PR): * Create ADO service connection SymbolsPublishing-mssql-rs (WIF, patterned on SymbolsPublishing-ADO.Net). Required only for release-time promotion to Microsoft Internal/Public symbol servers; ADOOnly mode does not need it. * Register the mssql-rs project namespace with the Microsoft Symbols Publishing service (symbolrequestprod.trafficmanager.net/projects/mssql-rs). Follow-ups (deliberately out of scope): * macOS dSYMs are captured as pipeline artifacts but not indexed by any symbol server yet — Mach-O/dSYM support on the ADO/MS symbol services needs a validation pass first. * Public symbol server publishing is plumbed but defaults off. Rust debug="full" DWARF/PDB includes source paths and private types; a public-symbol-stripping / source-path-rewriting flow is needed before enabling. * End-to-end retrieval validation (WinDbg + gdb/debuginfod-find lookup by GUID/build-id) before considering the non-official flow production-ready.
…mbols-wi45990 # Conflicts: # .pipeline/OneBranch/OfficialPythonWheelsRelease.yml
Contributor
There was a problem hiding this comment.
Pull request overview
Adds cross-platform debug-symbol capture and publishing for mssql-py-core wheels.
Changes:
- Enables full split debug information for release builds.
- Captures Windows, Linux, and macOS symbol artifacts.
- Adds ADO and Microsoft symbol-server publishing stages with retention controls.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/build-python-wheels-in-container.sh |
Collects Linux .dwp and .so artifacts. |
mssql-py-core/Cargo.toml |
Configures release debug information. |
.pipeline/templates/publish-symbols.yml |
Adds reusable symbol publishing and promotion. |
.pipeline/templates/build-python-wheels-template.yml |
Captures platform-specific symbols. |
.pipeline/OneBranch/stages.yml |
Adds non-official symbol publishing. |
.pipeline/OneBranch/OfficialPythonWheelsRelease.yml |
Adds official symbol promotion and version validation. |
.pipeline/OneBranch/NonOfficialPythonWheelsPublish.yml |
Enables ADO symbol publishing by default. |
- Replace .dwp/strip=debuginfo with objcopy --only-keep-debug + --add-gnu-debuglink so the published debug file is actually usable - Split debug info out of the built wheel and repack, guaranteeing the shipped .so matches the published debug file - Fail the build when no PDB/dSYM/.debug is produced instead of silently shipping a target without symbols - Search dSYMs from CARGO_TARGET_DIR and keep per-triple bundles - Template the macOS symbol destination path - Pass SymbolExpirationInDays so the advertised retention applies - Set failOnStandardError: false for the az CLI promotion step - Tag stage now consumes the Release stage's resolved version/commit Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
📊 Code Coverage Report
Diff CoverageDiff: main...HEAD, staged and unstaged changesNo lines with coverage information in this diff. 🔗 Quick Links |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…info wheel unpack/pack only preserves Unix permission bits from wheel 0.42 onward, and regenerates the filename from the WHEEL tags rather than reusing it. Rewrite the archive entry-by-entry instead so filename, member order, permissions, timestamps and compression are all preserved and only the .so payload plus its RECORD line change. Also assert the build-id is unchanged across the strip. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The manylinux and musllinux container steps of a Linux job share the same wheels output directory, so globbing it for the Python tag could return a wheel built by the previous step. Build into a per-tag staging directory and move the wheel out after splitting. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16bf260c-bdbf-4f01-a95d-31ba3cf3323c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses WI 45990 — publishes
mssql-py-coredebug symbols (Windows PDB, Linux separate.debug+ stripped.so, macOS.dSYM) to symbol servers so customer crash dumps can be symbolicated, while keeping shipped wheels small.Mirrors the
msodbcsqlpublishing pattern (msodbcsql-Symbol-Serverpipeline in thesqlclientdriversADO org).What runs where
GH-Non-Official Python Wheels Publish(main / nightly, PRs skipped)https://artifacts.dev.azure.com/sqlclientdrivers/_apis/symbol/symsrv)Official Python Wheels Build(stable)ADO-Release Nuget Python Wheels(manual release)Payload per build target
Windows x64/ARM64, Linux glibc/musl x64/ARM64, macOS universal2 — for each Python 3.10–3.14:
mssql_py_core*.pdbmssql_py_core.cpython-3XX-*.so.debug(full DWARF, ~60 MB) plus the matching stripped.sothat ships in the wheel — both carry the same GNU build-id, which is what the symbol server indexes on.dSYMbundles as pipeline artifacts only (not indexed pending Mach-O validation)Each wheel is built into its own staging directory and the debug split runs against the
.soinside that wheel, so the published.debugalways belongs to exactly the binary we ship. Per-build staging is load-bearing: the manylinux and musllinux container steps of a Linux job share the same wheels output directory, so globbing it by Python tag would pick up the previous step's already-stripped wheel — yielding ~880 KB stub debug files and leaving the musllinux wheels unsplit at ~14.6 MB.Cargo.toml release profile
Added to
mssql-py-core/Cargo.toml:debug = "full"is the load-bearing setting;strip = "none"is technically redundant (Cargo already defaultsstriptononewhen debug info is requested) but is kept explicit so the intent survives future edits. This is still a fully optimized release build that additionally carries debug metadata — not a debug build.Linux overrides
split-debuginfotooff(viaCARGO_PROFILE_RELEASE_SPLIT_DEBUGINFOin the container build script) and uses the conventionalobjcopy --only-keep-debug/--strip-debug/--add-gnu-debuglinkflow. Split-DWARF was prototyped and benchmarked in the production manylinux container and rejected on two counts: the.dwpcarries no build-id at all (readelf -nis empty), so it cannot be indexed by build-id; and skeleton DWARF is not small — ~8.5 MB of.debug_*stays in the shipped.so, inflating the wheel by ~77%.The wheel is rewritten in place by
scripts/split-wheel-debuginfo.py, which copies every ZIP entry verbatim (name, permissions, timestamp, order, compression) and swaps only the.sopayload and itsRECORDline. This avoidswheel unpack/wheel pack, which loses Unix permission bits on olderwheelversions and reconstructs the output filename from theWHEELTag:lines.Validation — end-to-end against real published symbols
Validated on
GH-Non-Official Python Wheels Publishbuild 164646 (succeeded), which includes the staging fix.Symbol request
mssql_rs_ADOOnlySymbols_0.1.8-dev.20260805.164646_d3d43a43…sealedSymbolExpirationInDaysis applied; the task default of ~36530 days would land in 2126)All 20 Linux targets (glibc/musl × x64/arm64 × cp310–cp314) produced distinct build-ids and full debug files — no duplicates across libc variants, no ~880 KB stubs:
.debug.soRetrieval — all 20 build-ids resolve on the ADO symbol server, with published sizes matching the build logs:
{so}/elf-buildid-{buildid}/{so}→ 200_.debug/elf-buildid-sym-{buildid}/_.debug→ 200{so}.debug/elf-buildid-{buildid}/{so}.debug→ 200Deep check on musllinux x64 cp311 (
c15e4899d4fb0da0453e0ebef2f3a0f0791e4036), downloaded from the symbol server:.so— 0.debug_*sections,.gnu_debuglinkpresent,.symtabretained.debug— same GNU build-id, 9.debug_*sections, 621 compile units, 3.6 MB of.debug_lineNote that DWARF records container-absolute source paths such as
/workspace/mssql-py-core/src/connection.rs. That is fine for the internal servers and substantiates keeping the Public symbol server stage off by default.Known non-issue: the musllinux cp310 extension is named
…-linux-gnu.sorather than…-linux-musl.so. This is upstream CPython behaviour — the cp310 interpreter in the musllinux image reportsEXT_SUFFIX = .cpython-310-x86_64-linux-gnu.so(the musl triplet only landed in 3.11+), so this is exactly the name that interpreter looks for at import time. Build-ids confirm the binary is genuinely compiled separately from the glibc one.Prerequisites (require ADO admin action — not in this PR)
SymbolsPublishing-mssql-rs(Workload Identity Federation, patterned onSymbolsPublishing-ADO.Netin the ADO.Net project).ADO.Netandmsodbcsqlboth have theirs;mssql-rsdoes not. Required only for release-time promotion to Microsoft Internal/Public — the non-official flow is validated and works today without it. Note thatpublishSymbolsInternaldefaults totrueinOfficialPythonWheelsRelease.yml, so the first official release will fail until this exists.mssql-rsproject namespace with the Microsoft Symbols Publishing service (symbolrequestprod.trafficmanager.net/projects/mssql-rs).Follow-ups (deliberately out of scope)
.dSYMindexing — needs a validation pass for Mach-O UUID support on the Microsoft symbol services.mssql-js(and future BCP bindings) — WI 45990 covers those too, but the workspace-root[profile.release]still ships them stripped with no separate debug file.debug="full"PDBs/DWARF contain source paths and private types. The Public stage is plumbed but defaults off; needs a stripping / source-path-rewriting flow first.Design bug caught & fixed
The existing
OfficialPythonWheelsRelease.ymlread version from the release-run checkout ofCargo.toml, not from the commit the Official Build actually ran against — so ifstablemoved between build and release, the NuGet version and shipped wheel version could disagree. Version is now read viagit show :mssql-py-core/Cargo.tomland a wheel-filename cross-check aborts the release if they don't match.