feat: include git commit SHA in PET info response for telemetry regression tracking#473
Conversation
| println!("cargo:rustc-env=PET_BUILD_ID={build_id}"); | ||
| } | ||
|
|
||
| // BUILD_SOURCEVERSION is set by Azure Pipelines; GITHUB_SHA by GitHub Actions. |
There was a problem hiding this comment.
Copilot generated:
The Skeptic identified (structurally confirmed) that an explicitly-set-but-empty PET_COMMIT_SHA silently suppresses the BUILD_SOURCEVERSION/GITHUB_SHA fallbacks: or_else only fires on None, so Some("") short-circuits the chain and the trailing .filter() then drops it to None, losing the SHA entirely. This is concretely triggerable (a GitHub Actions YAML referencing an unset context yields ""). While the Advocate notes this mirrors the existing build_id logic and may be unreachable in practice, the fix is cheap — filter each candidate before falling back: .ok().filter(|v| !v.is_empty()).or_else(|| std::env::var("BUILD_SOURCEVERSION").ok().filter(|v| !v.is_empty())).... Apply the same hardening to the build_id chain above.
[verified]
There was a problem hiding this comment.
Good catch — fixed in 356f4af. Moved the empty-string .filter() inside each candidate so a Some("") falls through to the next env var instead of being swallowed by the trailing filter. Applied the same hardening to the �uild_id chain.
There was a problem hiding this comment.
Good catch — fixed in 356f4af. Moved the empty-string .filter() inside each candidate so a Some(\"\") falls through to the next env var instead of being swallowed by the trailing filter. Applied the same hardening to the build_id chain.
| println!("cargo:rustc-env=PET_BUILD_ID={build_id}"); | ||
| } | ||
|
|
||
| // BUILD_SOURCEVERSION is set by Azure Pipelines; GITHUB_SHA by GitHub Actions. |
There was a problem hiding this comment.
Copilot generated:
Operational caveat from the Skeptic (Low): Azure Pipelines' BUILD_SOURCEVERSION is the ephemeral merge commit for PR-triggered builds, not the PR head commit. Since the stated goal is correlating regressions to a specific PET commit, verify the CI trigger config resolves to the intended (head) commit — this is a config check, not a code defect.
[verified]
There was a problem hiding this comment.
Acknowledged — treating this as a config check rather than a code change. Shipped PET binaries are built from main / release pipeline runs (not PR-triggered validation), where BUILD_SOURCEVERSION resolves to the real source commit. If we ever change the release pipeline to build from a PR context, I'll set PET_COMMIT_SHA explicitly to the head SHA so this stays correct.
There was a problem hiding this comment.
Acknowledged — treating this as a config check rather than a code change. Shipped PET binaries are built from main / release pipeline runs (not PR-triggered validation), where BUILD_SOURCEVERSION resolves to the real source commit. If we ever change the release pipeline to build from a PR context, I'll set PET_COMMIT_SHA explicitly to the head SHA so this stays correct.
| let info = InfoResponse::current(); | ||
|
|
||
| assert_eq!(info.pet_version, env!("CARGO_PKG_VERSION")); | ||
| // build_id / commit_sha are populated from env vars set at compile time by CI. |
There was a problem hiding this comment.
Copilot generated:
The Skeptic, Advocate, and Architect all noted these assertions are vacuously true: commit_sha.as_deref().is_none_or(|s| !s.is_empty()) passes whenever commit_sha is None, which is every local dev run — and build.rs's own .filter() already guarantees it can never be Some(""). As a result no test positively exercises the build.rs → binary → JSON path the PR claims, so a regression (the empty-string short-circuit, a serde-rename typo, a dropped option_env!) would ship green. Consider a test that, when option_env!("PET_COMMIT_SHA") is Some, asserts the serialized JSON contains a non-empty commitSha key.
[verified]
There was a problem hiding this comment.
Good point. Added test_info_response_serializes_camel_case_and_omits_none in 356f4af that constructs InfoResponse directly and asserts the JSON wire format — both the camelCase rename and the skip_serializing_if behavior. That catches serde-rename typos, dropped option_env!, or accidentally serializing None without requiring CI env vars at compile time. Kept the existing assertion (now renamed to ..._optional_build_metadata) as a light sanity check on the option_env! path; the new test provides the real wire-format protection.
|
GitHub cannot anchor PR review comments to unchanged lines in the diff. Falling back to a general PR comment for crates/pet/src/jsonrpc.rs:L1545. Copilot generated: [verified] |
| let info = client.info().expect("info request failed"); | ||
|
|
||
| assert_eq!(info.pet_version, env!("CARGO_PKG_VERSION")); | ||
| // build_id / commit_sha are populated from env vars set at compile time by CI. |
There was a problem hiding this comment.
Copilot generated:
Same vacuous-assertion concern as the unit test: commit_sha/build_id are None in local and most CI runs, so this assertion can essentially never fail and provides little real coverage of the end-to-end wire format. A round-trip test that sets the env var and asserts the commitSha JSON key would give genuine protection.
[verified]
There was a problem hiding this comment.
Same fix path as the unit-test thread: the new test_info_response_serializes_camel_case_and_omits_none in 356f4af covers the wire format at the serialization layer, which is where a serde-rename / skip_serializing_if regression would actually break. Setting compile-time env vars from an integration test would require rebuilding the binary, so I kept this assertion (renamed to info_reports_pet_version_and_optional_build_metadata) as a smoke check that deserialization still works when a SHA is present in a CI build.
brettcannon
left a comment
There was a problem hiding this comment.
The Copilot comments look reasonable.
…re-format test, rename tests - build.rs: push empty-string filter into each candidate of build_id/commit_sha chains so an explicitly-set-but-empty primary var (e.g. PET_COMMIT_SHA from an unset GitHub Actions context) doesn't short-circuit fallbacks. - jsonrpc.rs: add test_info_response_serializes_camel_case_and_omits_none covering camelCase rename + skip_serializing_if without requiring CI env vars at compile time. - rename existing tests to ..._optional_build_metadata for accurate scope.
|
Addressed Copilot feedback in 356f4af:
|
Background
PET (Python Environment Tools) is a Rust-based JSONRPC server used by the VS Code Python extension to discover Python environments. PET does not send its own telemetry — instead, it returns metadata to the calling extension (vscode-python-environments), which forwards it via telemetry.
To help catch regressions, we need a way to know exactly which PET build a user is running by querying telemetry. PR #470 added a JSONRPC
inforequest that returns PET's version and an optional CI build ID. However, the build number alone isn't enough to pinpoint the exact source code — we also need the git commit hash.This PR extends the
inforesponse to include the git commit SHA baked into the binary at build time. On the extension side, the companion PR (vscode-python-environments#1548) passes this information along to telemetry, so we can correlate user-reported issues or regressions back to the specific PET commit.What Changed
1. Build script (
crates/pet/build.rs)PET_COMMIT_SHA— explicit override (highest priority)BUILD_SOURCEVERSION— set by Azure PipelinesGITHUB_SHA— set by GitHub Actionscargo:rustc-env=PET_COMMIT_SHA=....2. JSONRPC response (
crates/pet/src/jsonrpc.rs)commit_shafield to theInfoResponsestruct.InfoResponse::current()populates it from the compile-timePET_COMMIT_SHAenv var (same pattern used forbuild_id).Noneand omitted from the JSON response.3. JSONRPC documentation (
docs/JSONRPC.md)InfoResponseTypeScript interface to document the newcommitSha?: stringfield, including where the value is sourced from.4. Tests (
crates/pet/src/jsonrpc.rs,crates/pet/tests/jsonrpc_server_test.rs,crates/pet/tests/jsonrpc_client.rs)commit_shafield to the test client'sPetInfoResponsestruct.commit_sha, when present, is non-empty (mirrors existingbuild_idassertion pattern).build_idandcommit_shaareNonein local dev builds and only populated in CI.How It Works
Related PRs
infoJSONRPC request with version and build ID (merged)