Skip to content

chore(deps): give a Microsoft.Extensions bump one line it can land on - #172

Merged
cosmin-staicu merged 1 commit into
mainfrom
chore/dependabot-floor-property
Sep 10, 2026
Merged

chore(deps): give a Microsoft.Extensions bump one line it can land on#172
cosmin-staicu merged 1 commit into
mainfrom
chore/dependabot-floor-property

Conversation

@cosmin-staicu

@cosmin-staicu cosmin-staicu commented Sep 10, 2026

Copy link
Copy Markdown
Member

Follow-up to closing #167#171. All five rewrote the net8.0 floor in Directory.Packages.props to 10.0.12 while their titles claimed 10.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 first PackageVersion line 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" was 10.0.11, a move to 10.0.12 never looked major, so ignore: version-update:semver-major for Microsoft.Extensions.* was never going to fire.

PackageVersionFloorTests.FloorGroupStaysOnItsOwnMajor failed on four of them in build-linux (#167 didn't get that far — it failed restore with NU1605, a downgrade of Options from 10.0.12 to 10.0.11). That guard is the only reason none of them landed.

What changes

  • The net10 group is declared first, so the line Dependabot reaches is the one it may have.
  • Its versions come from $(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.
  • The net8 floor keeps its literals, below, hand-managed, each package on its own 8.x patch (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 PackageVersion line 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:

net10.0: Caching.Memory>=10.0.11  Configuration.Binder>=10.0.11  HealthChecks.Abstractions>=10.0.11  Hosting.Abstractions>=10.0.11  Options>=10.0.11
net8.0:  Caching.Memory>=8.0.1    Configuration.Binder>=8.0.2     HealthChecks.Abstractions>=8.0.30    Hosting.Abstractions>=8.0.1     Options>=8.0.2

Full suite green: net10 1703, net8 1682, 0 failures.

On Logging.Abstractions

An earlier revision of this description called the unconditional Microsoft.Extensions.Logging.Abstractions pin 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:

  • StackExchange.Redis 3.1.31 declares Microsoft.Extensions.Logging.Abstractions >= 10.0.5 in every dependency group, .NETFramework8.0 included. A net8 floor of 8.0.x cannot restore against it.
  • Logging.Abstractions 10.0.12 ships a net8.0 lib 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: every Microsoft.Extensions.* a src project 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.Resilience and .ServiceDiscovery are 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

Comment thread Directory.Packages.props Outdated
razvalex
razvalex previously approved these changes Sep 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 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.0 is declared before net8.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.

Comment thread tests/UiPath.Caching.Tests/PackageVersionFloorTests.cs
Comment thread Directory.Packages.props Outdated
razvalex
razvalex previously approved these changes Sep 10, 2026
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>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 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

@cosmin-staicu
cosmin-staicu force-pushed the chore/dependabot-floor-property branch from b7b105c to 728b5f5 Compare September 10, 2026 12:20
@sonarqubecloud

Copy link
Copy Markdown

@cosmin-staicu
cosmin-staicu merged commit 72c1a91 into main Sep 10, 2026
10 checks passed
@cosmin-staicu
cosmin-staicu deleted the chore/dependabot-floor-property branch September 10, 2026 12:39
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.

4 participants