chore(deps): give a Microsoft.Extensions bump one line it can land on - #172
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Two newly introduced guards/comments are slightly misleading or non-self-contained (a test can pass with a missing net10 floor; a props comment over-attributes safety to the ignore rule), and should be tightened to match the PR’s intent.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adjusts the repo’s centrally managed Microsoft.Extensions per-TFM dependency floors so Dependabot patch bumps reliably land on the net10 floor line (not the net8 floor), and adds/extends tests that enforce this layout and pinning strategy.
Changes:
- Reorders the per-TFM floor ItemGroups so
net10.0is declared beforenet8.0. - Pins the net10 floor through a single
$(MEVersion10)property instead of repeating literals. - Adds/updates guard tests to enforce ordering, pinning-via-property, and correct major-floor validation (including property resolution).
File summaries
| File | Description |
|---|---|
tests/UiPath.Caching.Tests/PackageVersionFloorTests.cs |
Adds new guard tests and resolves $(Prop) references when validating floor majors. |
Directory.Packages.props |
Introduces MEVersion10 and restructures per-TFM Microsoft.Extensions floor declarations to be Dependabot-safe. |
.github/dependabot.yml |
Updates documentation comments to reflect Dependabot’s behavior and why the layout/tests are required. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Five Dependabot PRs this week each rewrote the net8.0 floor to 10.0.12 while their titles said 10.0.11 to 10.0.12. Dependabot does not evaluate the TargetFramework conditions, so it reads one version per package ID, takes the highest (the net10 one), and edits the first PackageVersion line it finds for that ID. The net8 group was declared first, so that is the line it got, and a 10.x patch never looked major to the semver-major ignore that was supposed to stop it. PackageVersionFloorTests caught all five in build-linux, which is the only reason none landed. #134 was the same bug a few weeks earlier. The net10 group is now declared first, so the line Dependabot reaches is the one it may have, and its versions come from $(MEVersion10): the family ships in lockstep, so a bump has one line to change rather than eleven that have to agree. The net8 floor keeps its literals below, hand-managed, each package on its own 8.x patch — they are not uniform, which is why a single $(MEVersion8) would not express them. Bumping to 10.0.12 showed the version had two more homes. The family asks for its own version of Microsoft.Extensions.Logging.Abstractions, pinned unconditionally, so leaving that behind failed restore with NU1605. UiPath.Caching.Azure carries a VersionOverride on Options that has to move with the floor too; #134 aligned it by hand, which is exactly what broke this time, so it now reads $(MEVersion10) instead of repeating the number. Logging.Abstractions stays unconditional. StackExchange.Redis 3.x declares it >= 10.0.5 in every dependency group, net8.0 included, so an 8.0.x floor for it cannot restore, and 10.x ships a net8.0 asset so a net8.0 consumer still resolves a net8-targeted assembly. That was decided in #85 and the reason lived only in its commit message, which was long enough ago that reading the props file, the floor tests and the Dependabot config left me calling the pin a hole in the policy. It now sits next to the pin. Everything load-bearing here is guarded, and each guard was checked by making the mistake it exists for: - TheNet10FloorIsDeclaredFirst pins the order, and asserts both groups were found: a missing net10 group leaves -1, which is less than any index and would otherwise pass with no floor to order. - TheNet10FloorIsPinnedThroughOneProperty pins the property. - FloorGroupStaysOnItsOwnMajor resolves a property reference before judging the major. - EveryShippedExtensionsPackageIsFlooredExceptLoggingAbstractions keeps the exception to one package. It reads the shipped projects rather than the props file, because a floor only reaches a consumer through a published dependency group: Http.Resilience and ServiceDiscovery are pinned unconditionally too and belong to nobody's, since only the Aspire sample references them. Published floors verified against the packed nuspec: net10.0 asks for 10.0.12 across the family, net8.0 for 8.0.1 / 8.0.2 / 8.0.30 as before, with Logging.Abstractions at 10.0.12 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsPw6MZHPGmpbo6WDuLzF1 Signed-off-by: Cosmin Staicu <cosmin.staicu@uipath.com>
There was a problem hiding this comment.
🟢 Approval recommended
The change is narrowly scoped to dependency-floor layout and adds explicit tests to enforce the new invariants that prevent the prior Dependabot mis-edit behavior.
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
b7b105c to
728b5f5
Compare
|



Follow-up to closing #167–#171. All five rewrote the net8.0 floor in
Directory.Packages.propsto10.0.12while their titles claimed10.0.11 → 10.0.12.Why they got through the ignore rule
Dependabot does not evaluate the
$(TargetFramework)conditions. It reads one version per package ID, takes the highest (the net10 one,10.0.11), and then edits the firstPackageVersionline it finds for that ID — each of those five diffs was +1/−1, so it is a single-line edit. The net8 group was declared first, so that is the line it got. And because its notion of "current" was10.0.11, a move to10.0.12never looked major, soignore: version-update:semver-majorforMicrosoft.Extensions.*was never going to fire.PackageVersionFloorTests.FloorGroupStaysOnItsOwnMajorfailed on four of them inbuild-linux(#167 didn't get that far — it failed restore withNU1605, a downgrade ofOptionsfrom 10.0.12 to 10.0.11). That guard is the only reason none of them landed.What changes
$(MEVersion10). The family ships in lockstep, so a bump has one line to change instead of eleven that have to agree, and there is no way to leave the group disagreeing with itself.8.0.0/8.0.1/8.0.2/8.0.30— they are genuinely not uniform, which is why a single$(MEVersion8)would not express it).Net10 patch bumps keep flowing. If Dependabot updates the property, that is one clean line; if it writes a literal onto a
PackageVersionline instead, the floor test still passes and the next run normalizes it; if it cannot resolve the property and skips the family, that is the same outcome as ignoring the family outright. All three are safe, which is the point.Guards
The order and the property are both load-bearing now, so both are pinned:
TheNet10FloorIsDeclaredFirst— fails if the groups are swapped back.TheNet10FloorIsPinnedThroughOneProperty— fails if a literal creeps into the net10 group.FloorGroupStaysOnItsOwnMajor— now resolves a$(Prop)reference before judging the major.I checked each of the two new ones by making the mistake it exists for and watching it fail, not by assuming.
Verification
Published floors are unchanged, read back from the packed nuspec:
Full suite green: net10 1703, net8 1682, 0 failures.
On Logging.Abstractions
An earlier revision of this description called the unconditional
Microsoft.Extensions.Logging.Abstractionspin a pre-existing hole in the per-TFM policy. That was wrong, and I retract it: b2ca821 (#85) raised it to 10.x on net8.0 on purpose, as the prerequisite for the StackExchange.Redis 3.0 upgrade. Both halves of that reasoning still hold at the pins we have today, checked against the two nuspecs rather than taken from the old commit message:Microsoft.Extensions.Logging.Abstractions >= 10.0.5in every dependency group,.NETFramework8.0included. A net8 floor of 8.0.x cannot restore against it.Logging.Abstractions10.0.12 ships anet8.0lib asset, so net8.0 consumers resolve a net8-targeted assembly rather than a downlevel one.So it stays unconditional. What was actually missing is that the reason lived only in #85's commit message — reading the props file, the floor tests and the Dependabot config left me mis-diagnosing it. b7b105c puts the reason next to the pin and adds
EveryShippedExtensionsPackageIsFlooredExceptLoggingAbstractions, which keeps the exception to one package: everyMicrosoft.Extensions.*asrcproject references has to be floored per TFM, and anything else escaping has to be argued for in that test.It reads the shipped projects rather than the props file, because a floor only reaches a consumer through a published dependency group.
Microsoft.Extensions.Http.Resilienceand.ServiceDiscoveryare also pinned unconditionally and are correctly ignored — only the Aspire sample references them, so they are in nobody's dependency group. The first draft of the test flagged them, which is how I found that out. Verified to fail on a shipped package dropped out of the floors.🤖 Generated with Claude Code
https://claude.ai/code/session_01NsPw6MZHPGmpbo6WDuLzF1