Visitar URL original
Fix multiline central package version updates by onuracar-dev · Pull Request #783 · dotnet-outdated/dotnet-outdated · GitHub
Skip to content

Fix multiline central package version updates - #783

Merged
slang25 merged 8 commits into
dotnet-outdated:masterfrom
onuracar-dev:fix/683-multiline-package-version
Nov 8, 2026
Merged

slang25 merged 8 commits into
dotnet-outdated:masterfrom
onuracar-dev:fix/683-multiline-package-version

Conversation

@onuracar-dev

@onuracar-dev onuracar-dev commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • update central PackageVersion and GlobalPackageReference values without requiring the closing element to be on the same line
  • add a regression test for a multiline Directory.Packages.props entry when --no-restore is used

Validation

  • .NET 9 test suite: 211 passed, 1 skipped
  • .NET 8 test suite: 211 passed, 1 skipped
  • Release solution build
  • dotnet format --verify-no-changes for both changed files

AI disclosure: I used OpenAI Codex while implementing this change. I reviewed the complete diff and ran the validation listed above locally.

Maintainer follow-up commits

  • Tests for the child-element shape (<PackageVersion …> / <GlobalPackageReference …> with <PrivateAssets> children, as in Directory.Packages.props with more complex PackageReference does not execute regex replace #602), and the tests now compare the whole file.
  • --no-restore no longer reports "upgraded successfully" when Directory.Packages.props mentions the package but no entry could be updated: the upgrade now fails with a message naming the package and the file, and does not fall back to dotnet add package --no-restore (which would write the version into the project file). An entry already at the requested version still counts as success (multi-targeted projects call this once per framework).
  • The package id is matched case-insensitively, consistent with the existing guard.
  • Merged master. Full suite: 221 passed, 1 skipped on net8.0 and net9.0.

#602 is only partly addressed: the --no-restore path now handles a GlobalPackageReference with child elements, but without --no-restore, dotnet add package still fails on a GlobalPackageReference, so #602 stays open.

Closes #683

🤖 Generated with Claude Code

onuracar-dev and others added 5 commits August 31, 2026 00:47
Cover the shape from dotnet-outdated#602 (an element with child metadata and a separate
closing tag) for both PackageVersion and GlobalPackageReference, and compare
the whole Directory.Packages.props instead of checking substrings, so any
collateral change to the file fails the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TryUpdateCentralPackageVersion returned true as soon as Directory.Packages.props
mentioned the package in quotes, even when the regex matched no element. With
--no-restore the tool then printed "upgraded successfully" and left the file
unchanged (the symptom in dotnet-outdated#683).

Return a tri-state instead: NotFound keeps falling back to `dotnet add
package`; Updated means an entry matched (including one already at the
requested version, e.g. the second framework of a multi-targeted project);
NoMatchingEntry now yields a failed RunStatus naming the package and file, so
the upgrade is reported as an error instead of a silent no-op. It does not fall
back to `dotnet add package --no-restore`, which would write the version into
the project file (NuGet/Home#12552).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guard before the regex already uses OrdinalIgnoreCase, but the regex
matched the id case-sensitively. NuGet ids are case-insensitive, so an entry
written as Include="newtonsoft.json" was skipped, and with the previous commit
that would now be reported as an error. Wrap the escaped id in (?i:...) so only
the id is case-insensitive; the entry keeps its original casing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ackage-version

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

Package-ID matching remains culture-dependent, causing valid entries to be reported as NoMatchingEntry under locales such as tr-TR; the regex needs RegexOptions.CultureInvariant.

1 open issue
What changed in this PR

Fixes central package version updates with --no-restore for multiline entries and entries with child elements, addressing #683 and part of #602.

Changes:

  • Updates version attributes without requiring a same-line closing tag and matches package IDs case-insensitively.
  • Reports unmatched central entries as failures without falling back to project-file updates, while preserving success for already-current versions.
  • Adds regression tests that verify complete file contents and runner behavior.
File Description
test/​DotNetOutdated.Tests/​DotNetPackageServiceTests.cs Adds coverage for multiline entries, child elements, casing, and update outcomes.
src/​DotNetOutdated.Core/​Services/​DotNetPackageService.cs Revises central version matching and distinguishes successful, missing, and unmatched entries.

Review effort: Balanced

slang25 and others added 3 commits November 8, 2026 12:10
Copilot review: the inline (?i:...) match used the current culture, so under
tr-TR a request for Microsoft.IdentityModel.Tokens did not match an entry
written as microsoft.identitymodel.tokens ('I' does not fold to 'i'), and the
upgrade was reported as NoMatchingEntry. Pass RegexOptions.CultureInvariant,
matching the OrdinalIgnoreCase guard above it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ackage-version

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ackage-version

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@slang25 slang25 left a comment

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.

Reviewed and tested; changes applied on top. Thanks!

@slang25
slang25 merged commit f4cf703 into dotnet-outdated:master Nov 8, 2026
9 checks passed
slang25 added a commit to GREsau/dotnet-outdated that referenced this pull request Nov 8, 2026
Brings in dotnet-outdated#783 (multiline central package version updates). Keeps dotnet-outdated#783's
CentralPackageVersionUpdate result and regex, writing the version range
(VersionRange.ToVersionString) instead of a single version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
slang25 added a commit to symbiogenesis/dotnet-outdated that referenced this pull request Nov 8, 2026
…tespace

Resolve the conflict in DotNetPackageService.TryUpdateCentralPackageVersion:
keep dotnet-outdated#783's NotFound/Updated/NoMatchingEntry outcomes, its regex and its
loud failure instead of the dotnet add --no-restore fallback, on top of
this branch's FindCentralPackagesFiles walk and EncodedText write (BOM
kept).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
slang25 added a commit to symbiogenesis/dotnet-outdated that referenced this pull request Nov 8, 2026
The --no-restore path still matched only Include="…" immediately
followed by Version="…", so Version-before-Include, an attribute
between them, single quotes or spaces around = were reported as
NoMatchingEntry, and a commented-out PackageVersion was rewritten. Use
PackageVersionMarkup.ReplaceVersion here too, now with a matched flag
(match, not change, decides Updated) and CultureInvariant for the
case-insensitive id. dotnet-outdated#783's NotFound/Updated/NoMatchingEntry outcomes are
unchanged; a package mentioned only in single quotes now counts as found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
slang25 added a commit that referenced this pull request Nov 8, 2026
* fix: preserve central package props formatting during upgrades

* test: cover whitespace preservation across repeated upgrades

* fix: preserve inactive XML during formatting restoration

* fix: keep encoding and BOM when updating props with --no-restore

The --no-restore path read Directory.Packages.props with ReadAllText and
wrote it back with WriteAllText, which dropped a UTF-8 byte order mark and
re-encoded UTF-16 files as UTF-8. Reuse the decoding used by the formatting
replay so the original encoding and preamble are written back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: say when Directory.Packages.props formatting is not preserved

Per-target-framework PackageVersion entries for the same package still
fall back to the dotnet add package output, so narrow the README claim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor: replay the exact version text passed to dotnet add

Write back the same string that is given to `dotnet add package -v`
instead of formatting a NuGetVersion a second time. A caller that passes
a version range only has to change that one string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: restore variable references in any attribute layout

The formatting replay brings back the original attribute layout (single
quotes, spaces around =, Version before Include, multi-line elements),
but the variable restorer only matched Include="..." Version="...".
On those layouts the property was upgraded while the package kept a
literal version. Share the replay's version-attribute regex with the
variable restorer.

Addresses Copilot review on #803 (variable restoration).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep props encoding when restoring variable references

UpdatePackageVariable read and wrote the property and package files with
ReadAllText/WriteAllText, so a variable-backed upgrade turned a UTF-8 BOM
or UTF-16 file into BOM-less UTF-8 right after the formatting replay had
restored it. Move the encoding round-trip into EncodedText and use it for
both the --no-restore update and the variable restorer.

Addresses Copilot review on #803 (variable updates overwrite encoding).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: use the shared version regex for --no-restore updates

The --no-restore path still matched only Include="…" immediately
followed by Version="…", so Version-before-Include, an attribute
between them, single quotes or spaces around = were reported as
NoMatchingEntry, and a commented-out PackageVersion was rewritten. Use
PackageVersionMarkup.ReplaceVersion here too, now with a matched flag
(match, not change, decides Updated) and CultureInvariant for the
case-insensitive id. #783's NotFound/Updated/NoMatchingEntry outcomes are
unchanged; a package mentioned only in single quotes now counts as found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: match only the real Version attribute of a package entry

PackageVersionMarkup scanned the start tag with [^>]* and a lookahead, so
text inside another attribute's value could be taken for Include= or
Version= (e.g. Notes="Version='legacy'" was rewritten instead of the
version), a '>' inside a quoted condition stopped the match, and a
version expression containing quotes was not matched. Tokenize the start
tag into complete quoted attributes and replace only the Version value,
up to its matching quote. Comments, CDATA and processing instructions are
still skipped.

Addresses Copilot review on #803 (match the complete quoted Version attribute).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Stuart Lang <stuart.b.lang@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@slang25 slang25 mentioned this pull request Nov 8, 2026
ptr727-codegen Bot pushed a commit to ptr727/LanguageTags that referenced this pull request Nov 10, 2026
Updated
[dotnet-outdated-tool](https://github.com/dotnet-outdated/dotnet-outdated)
from 4.8.1 to 4.9.0.

<details>
<summary>Release notes</summary>

_Sourced from [dotnet-outdated-tool's
releases](https://github.com/dotnet-outdated/dotnet-outdated/releases)._

## 4.9.0

## What's Changed
* Adopt MCP 2026-07-28 spec with legacy version negotiation by @​slang25
in dotnet-outdated/dotnet-outdated#772
* Fix concurrent cache corruption during recursive file-based app
upgrades by @​DamianEdwards in
dotnet-outdated/dotnet-outdated#788
* Fix: Parameter --maximum-version ignores exact version references by
@​chefarbeiter in
dotnet-outdated/dotnet-outdated#671
* Show a friendly message instead of crashing when a solution has no
projects by @​DanielC000 in
dotnet-outdated/dotnet-outdated#771
* Surface package-upgrade stdout so failures are diagnosable by
@​timabell in
dotnet-outdated/dotnet-outdated#790
* Fix multiline central package version updates by @​onuracar-dev in
dotnet-outdated/dotnet-outdated#783
* Support versioned MSBuild project SDKs in project files by @​thomhurst
in dotnet-outdated/dotnet-outdated#793
* Preserve whitespace in Directory.Packages.props during upgrades by
@​symbiogenesis in
dotnet-outdated/dotnet-outdated#803
* Treat package references injected by custom SDKs as auto-referenced by
@​thomhurst in
dotnet-outdated/dotnet-outdated#795
* Preserve version ranges when upgrading packages by @​GREsau in
dotnet-outdated/dotnet-outdated#702
* Preserve MSBuild version variables across project and props files by
@​symbiogenesis in
dotnet-outdated/dotnet-outdated#805
* Replace McMaster command-line parsing with System.CommandLine by
@​slang25 in dotnet-outdated/dotnet-outdated#808
* Bump version to 4.9.0 by @​slang25 in
dotnet-outdated/dotnet-outdated#806

## New Contributors
* @​chefarbeiter made their first contribution in
dotnet-outdated/dotnet-outdated#671
* @​DanielC000 made their first contribution in
dotnet-outdated/dotnet-outdated#771
* @​timabell made their first contribution in
dotnet-outdated/dotnet-outdated#790
* @​onuracar-dev made their first contribution in
dotnet-outdated/dotnet-outdated#783
* @​thomhurst made their first contribution in
dotnet-outdated/dotnet-outdated#793
* @​GREsau made their first contribution in
dotnet-outdated/dotnet-outdated#702

**Full Changelog**:
dotnet-outdated/dotnet-outdated@v4.8.1...v4.9.0


Commits viewable in [compare
view](dotnet-outdated/dotnet-outdated@v4.8.1...v4.9.0).
</details>

Updated [ptr727.Utilities](https://github.com/ptr727/Utilities) from
4.1.105 to 4.1.109.

<details>
<summary>Release notes</summary>

_Sourced from [ptr727.Utilities's
releases](https://github.com/ptr727/Utilities/releases)._

## 4.1.109

## What's Changed
* Bump the actions-deps group with 4 updates by @​dependabot[bot] in
ptr727/Utilities#574
* Bump the nuget-deps group with 2 updates by @​dependabot[bot] in
ptr727/Utilities#576
* Resync the Instruction Set With the Hub by @​ptr727 in
ptr727/Utilities#581
* Resync the Skills Tree and Markdownlint Config With the Hub by
@​ptr727 in ptr727/Utilities#578
* Bring the Publisher Concurrency and Aggregator Name to the Workflow
Contract by @​ptr727 in ptr727/Utilities#579
* Reconcile the Intent-Fidelity Carried Files With the Hub by @​ptr727
in ptr727/Utilities#580
* Promote the Hub Resync to Main by @​ptr727 in
ptr727/Utilities#582


**Full Changelog**:
ptr727/Utilities@4.1.108...4.1.109

## 4.1.108

## What's Changed
* Bump the actions-deps group with 4 updates by @​dependabot[bot] in
ptr727/Utilities#575
* Bump the nuget-deps group with 2 updates by @​dependabot[bot] in
ptr727/Utilities#577


**Full Changelog**:
ptr727/Utilities@4.1.105...4.1.108

Commits viewable in [compare
view](ptr727/Utilities@4.1.105...4.1.109).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ptr727 added a commit to ptr727/NxWitness that referenced this pull request Nov 11, 2026
Updated [csharpier](https://github.com/belav/csharpier) from 1.3.0 to
1.4.0.

<details>
<summary>Release notes</summary>

_Sourced from [csharpier's
releases](https://github.com/belav/csharpier/releases)._

## 1.4.0

## Breaking Changes
### Drop support for net8.0 and net9.0
[#​1888](belav/csharpier#1888)
CSharpier and CSharpier.MsBuild now target `net10.0` and `net11.0`.
CSharpier.Core targets `net10.0`, `net11.0` and `netstandard2.0`.

## What's Changed
### Feature: Support for .NET 11 and C# 15
[#​1888](belav/csharpier#1888)
CSharpier now supports the new syntax in C# 15.
```c#
public union Pet(Cat, Dog, Bird);

public closed record GateState;

HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"];

outer:
for (int row = 0; row < grid.Height; row++)
{
    for (int column = 0; column < grid.Width; column++)
    {
        if (grid[row, column].IsBlocked)
        {
            continue outer;
        }

        if (grid[row, column].IsGoal)
        {
            break outer;
        }
    }
}
```

### Feature: Avoid chopping single trailing lambda
[#​1865](belav/csharpier#1865)
When the last argument is a lambda with a block body, and the arguments
up to and including the `=>` fit on one line, CSharpier now keeps them
on the same line as the method name.
```c#
// input & expected output
logging.AddFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "server{0}.log"), o =>
{
    o.MaxRollingFiles = 1;
});

// 1.3.0
logging.AddFile(
    Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "server{0}.log"),
    o =>
    {
        o.MaxRollingFiles = 1;
    }
);
```
 ... (truncated)

## 1.3.11-beta1



## 1.3.6

# 1.3.6
## What's Changed
#### Fix bug where 2nd instance of VSCode was not able to format code
[#​784](belav/csharpier#784)

Thanks to @​BenasB for reporting the issue

Commits viewable in [compare
view](belav/csharpier@1.3.0...1.4.0).
</details>

Updated
[dotnet-outdated-tool](https://github.com/dotnet-outdated/dotnet-outdated)
from 4.8.1 to 4.9.0.

<details>
<summary>Release notes</summary>

_Sourced from [dotnet-outdated-tool's
releases](https://github.com/dotnet-outdated/dotnet-outdated/releases)._

## 4.9.0

## What's Changed
* Adopt MCP 2026-07-28 spec with legacy version negotiation by @​slang25
in dotnet-outdated/dotnet-outdated#772
* Fix concurrent cache corruption during recursive file-based app
upgrades by @​DamianEdwards in
dotnet-outdated/dotnet-outdated#788
* Fix: Parameter --maximum-version ignores exact version references by
@​chefarbeiter in
dotnet-outdated/dotnet-outdated#671
* Show a friendly message instead of crashing when a solution has no
projects by @​DanielC000 in
dotnet-outdated/dotnet-outdated#771
* Surface package-upgrade stdout so failures are diagnosable by
@​timabell in
dotnet-outdated/dotnet-outdated#790
* Fix multiline central package version updates by @​onuracar-dev in
dotnet-outdated/dotnet-outdated#783
* Support versioned MSBuild project SDKs in project files by @​thomhurst
in dotnet-outdated/dotnet-outdated#793
* Preserve whitespace in Directory.Packages.props during upgrades by
@​symbiogenesis in
dotnet-outdated/dotnet-outdated#803
* Treat package references injected by custom SDKs as auto-referenced by
@​thomhurst in
dotnet-outdated/dotnet-outdated#795
* Preserve version ranges when upgrading packages by @​GREsau in
dotnet-outdated/dotnet-outdated#702
* Preserve MSBuild version variables across project and props files by
@​symbiogenesis in
dotnet-outdated/dotnet-outdated#805
* Replace McMaster command-line parsing with System.CommandLine by
@​slang25 in dotnet-outdated/dotnet-outdated#808
* Bump version to 4.9.0 by @​slang25 in
dotnet-outdated/dotnet-outdated#806

## New Contributors
* @​chefarbeiter made their first contribution in
dotnet-outdated/dotnet-outdated#671
* @​DanielC000 made their first contribution in
dotnet-outdated/dotnet-outdated#771
* @​timabell made their first contribution in
dotnet-outdated/dotnet-outdated#790
* @​onuracar-dev made their first contribution in
dotnet-outdated/dotnet-outdated#783
* @​thomhurst made their first contribution in
dotnet-outdated/dotnet-outdated#793
* @​GREsau made their first contribution in
dotnet-outdated/dotnet-outdated#702

**Full Changelog**:
dotnet-outdated/dotnet-outdated@v4.8.1...v4.9.0


Commits viewable in [compare
view](dotnet-outdated/dotnet-outdated@v4.8.1...v4.9.0).
</details>

Updated
[Microsoft.Extensions.Http.Resilience](https://github.com/dotnet/extensions)
from 10.11.0 to 11.0.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Http.Resilience's
releases](https://github.com/dotnet/extensions/releases)._

## 11.0.0

<!-- DRAFT: not published. Public baseline
f8ee27151b21e33793164b39de5bcebfdced81a4 (includes #​7923). Official
build source/tag target c60d72e7973a90cd4e4300d9153e97b93315e4b7 =
baseline + 9 internal release-prep commits (infrastructure, .NET
8/9/10/11 dependency updates, test pins, feeds, SDK 11.0.100 pin); no
additional PRs. Official build 3132207, BAR 340823, final published
manifest SHA256
A694CB054BBD836E73E2EF9EFA26FAD025EC6F709273D4CF217E08F5E1DE5CE6.
c60d72e is publicly reachable. -->
<!-- AVAILABILITY STATUS (2026-11-10): Public SDK 11.0.100 GA/download
and servicing 8.0.34/9.0.23/10.0.15 are confirmed available. Three
successful dotnet-public reads at 16:50:57Z, 17:05:36Z, and 17:20:30Z
found neither Microsoft.WindowsDesktop.App.Runtime.win-x64 8.0.34 nor
9.0.23 listed. The index samples do not establish restore, official CI,
or dependency closure. -->
<!-- VALIDATION STATUS (NOT PASSED): All 55 published package listings,
provenance/content and signatures were verified, as were 900
library/analyzer consumer graphs. The user's BAR readback confirms build
340823 in .NET 11 channel 8297. Published-source commit
c60d72e7973a90cd4e4300d9153e97b93315e4b7 is publicly reachable. All 272
selected library PDBs on msdl matched the original identities and bytes.
Website follow-up is user-deferred. -->

Version 11.0.0 ships alongside .NET 11 and with net11 targets added to
packages. Highlights of this release include new experimental Documents
and Document Extraction abstractions, metric instrument descriptions,
and a sliding-window retry budget for HTTP resilience.

## Experimental API Changes

### Now Stable
* HTTP server latency telemetry (`AddHttpServerLatencyTelemetry`) APIs
are now stable (previously `EXTEXP0013`) #​7898

### New Experimental APIs
* New experimental API: Documents abstractions in the new
`Microsoft.Extensions.Documents.Abstractions` package (`EXTEXP0019`)
#​7835
* New experimental API: Document Extraction in the new
`Microsoft.Extensions.DocumentExtraction` and
`Microsoft.Extensions.DocumentExtraction.Abstractions` packages
(`MEDE0001`) #​7588
* New experimental API: HTTP resilience retry budget
(`HttpRetryBudgetOptions`,
`HttpRetryResiliencePipelineBuilderExtensions`,
`OnRetryBudgetExhaustedArguments`) (`EXTEXP0001`) #​7867
* New experimental API: `Description` on metric attributes
(`EXTEXP0003`) #​7837

### Obsoleted APIs
* `HybridCacheOptions.DisableCompression` is now obsolete (`EXTOBS0003`)
#​7885

## What's Changed

### Telemetry and Logging

* Add Description to metric attributes and describe all instruments
#​7837 by @​evgenyfedorov2 (co-authored by @​Copilot)
* Capture trace context, thread ID and message template in buffered logs
#​7818 by @​evgenyfedorov2 (co-authored by @​Copilot)
* Allow bool and numeric types for strongly-typed metric tags #​7877 by
@​evgenyfedorov2 (co-authored by @​Copilot)
* Fix route parameter redaction when a parameter value contains a
delimiter used later in the same path segment #​7828 by @​evgenyfedorov2
(co-authored by @​Copilot)
* Fix lost log records when logging reentrantly on the same thread
#​7847 by @​evgenyfedorov2 (co-authored by @​Copilot)
* Fix logging generator stack overflow on type cycles #​7861 by
@​evgenyfedorov2 (co-authored by @​Copilot)
* Honor `[LogPropertyIgnore]` during transitive logging and
`[LogProperties(Transitive = true)]` on properties #​7868 by
@​evgenyfedorov2 (co-authored by @​Copilot)
* Make DataClassificationSet static to decrease allocations #​7874 by
@​evgenyfedorov2 (co-authored by @​Copilot)

### Caching

* Add HybridCache.GetOrCreateAsync overloads for dynamic setting of
options #​7568 by @​svick (co-authored by @​Copilot)
* Mark HybridCacheOptions.DisableCompression as obsolete #​7885 by
@​slang25
* Fix HybridCache stampede state removal race #​7814 by @​svick
(co-authored by @​Copilot)
* Fix HybridCache reservation over-release on DisableUnderlyingData miss
#​7879 by @​Eng3bbas

### AI

* AI: Restore neutral tool approval rejection message #​7913 by @​jozkee
(co-authored by @​Copilot)
* Fix ImageGenerationOptions.Clone dropping StreamingCount #​7829 by
@​Empiree
* Fix evaluation context serialization without reflection fallback
#​7869 by @​valkiara
* Pin MessagePack 2.5.307 in AI template AppHost project #​7853 by
@​evgenyfedorov2 (co-authored by @​Copilot)

### Packaging and Target Frameworks

* Condition framework-provided package references for .NET 11 #​7915 by
@​jeffhandley (co-authored by @​Copilot)
 ... (truncated)

Commits viewable in [compare
view](dotnet/extensions@v10.11.0...v11.0.0).
</details>

Updated [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest)
from 18.11.0 to 18.12.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.NET.Test.Sdk's
releases](https://github.com/microsoft/vstest/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/microsoft/vstest/commits).
</details>

Updated [System.CommandLine](https://github.com/dotnet/dotnet) from
2.0.14 to 3.0.0.

<details>
<summary>Release notes</summary>

_Sourced from [System.CommandLine's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [xunit.analyzers](https://github.com/xunit/xunit.analyzers) from
2.2.0 to 2.3.0.

<details>
<summary>Release notes</summary>

_Sourced from [xunit.analyzers's
releases](https://github.com/xunit/xunit.analyzers/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/xunit/xunit.analyzers/commits).
</details>

Updated [xunit.v3](https://github.com/xunit/xunit) from 4.0.2 to 4.0.3.

<details>
<summary>Release notes</summary>

_Sourced from [xunit.v3's
releases](https://github.com/xunit/xunit/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/xunit/xunit/commits).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pieter Viljoen <ptr727@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
timabell added a commit to timabell/dotnet-outdated that referenced this pull request Nov 12, 2026
PackageVersionMarkup.ReplaceVersion located PackageVersion,
GlobalPackageReference and PackageReference elements with regular
expressions. dotnet-outdated#783 made those expressions handle multi-line elements,
but regex still isn't an XML parser, and it gets valid MSBuild wrong:

- A version written as a <Version> child element, which MSBuild
  accepts like any item metadata, was never found. With --no-restore
  a central package upgrade failed, and an imported
  Directory.Build.props entry couldn't be upgraded at all.
- A package id containing an entity reference (Include="A&dotnet-outdated#46;B")
  didn't match, because the regex compared the raw text.

Locate the elements with XmlReader instead, which decodes entities and
never mistakes comments, CDATA or escaped text for markup, and use its
line information to replace only the version text in the original
string, so the file's layout is kept byte-for-byte (an XDocument save
would reserialize the whole document). Content that isn't well-formed
XML is left unchanged and reported as unmatched.

This covers every caller of ReplaceVersion: central package updates
with --no-restore, the Directory.Packages.props formatting replay after
dotnet add package, GlobalPackageReference updates and imported
PackageReference updates. Restoring variable references
(ReplacePackageVersion) and property edits still use regex.

Refs: dotnet-outdated#561
Refs: dotnet-outdated#301
Refs: dotnet-outdated#602
Refs: dotnet-outdated#316

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
timabell added a commit to timabell/dotnet-outdated that referenced this pull request Nov 12, 2026
dotnet-outdated finds the version to change in Directory.Packages.props,
and the other files it edits directly, with regular expressions. Regex
can't parse XML, so some valid files are silently not updated, or the
upgrade fails with a confusing error. dotnet-outdated#602 was one case: entries spread
over several lines weren't updated. dotnet-outdated#783 fixed that by making the regex
cleverer, but valid MSBuild still defeats it:

- A version written as a <Version> child element, which MSBuild accepts
  like any other item metadata, is never found. Upgrading a central
  package with --no-restore fails, and a Directory.Build.props entry
  can't be upgraded at all.
- A package id containing an XML entity reference (Include="A&dotnet-outdated#46;B")
  doesn't match, because the regex compares the raw text.

Each such case would need another regex special case, and there will
always be another:
https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454

Instead, find the elements with an XML parser (XmlReader), which
understands the file the way MSBuild does, and use its line and column
information to replace only the version text, so the rest of the file
stays byte-for-byte identical. (Loading and saving with XDocument would
reformat the whole file.) A file that isn't well-formed XML is left
unchanged and reported as not updated.

This covers every place that changes a version this way: central
package updates with --no-restore, putting back the
Directory.Packages.props layout after `dotnet add package`,
GlobalPackageReference updates, and the Directory.Build.props updates
from the previous commit. Restoring $(Variable) references
(ReplacePackageVersion) and editing properties still use regex; they're
the next candidates.

One upstream test asserted the old limitation: it used a <Version> child
element as its example of an entry that can't be updated. It now uses
an entry with no version at all.

Refs: dotnet-outdated#561
Refs: dotnet-outdated#301
Refs: dotnet-outdated#602
Refs: dotnet-outdated#316

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
timabell added a commit to timabell/dotnet-outdated that referenced this pull request Nov 12, 2026
Some upgrades write the new version into a file directly rather than
through `dotnet add package`: central package versions in
Directory.Packages.props, `GlobalPackageReference` items, and, since the
dotnet-outdated#301 fix, versions in Directory.Build.props. dotnet-outdated finds the
version to change in those files with regular expressions.

Regex can't reliably parse XML. dotnet-outdated#602 was one case: entries spread over
several lines weren't updated. dotnet-outdated#783 fixed that by making the regex
cleverer, but valid MSBuild still defeats it:

- A version written as a `<Version>` child element, which MSBuild
  accepts like any other item metadata, is never found. Upgrading a
  central package with `--no-restore` fails, and a Directory.Build.props
  entry can't be upgraded at all.
- A package id containing an XML entity reference (`Include="A&dotnet-outdated#46;B"`)
  doesn't match, because the regex compares the raw text.

Each such case would need another regex special case, and there will
always be another:
https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454

Instead, find the elements with an XML parser (`XmlReader`), which can
correctly parse the `.props` xml files, and use its line and column
information to replace only the version text, so the rest of the file
stays byte-for-byte identical. (Loading and saving with `XDocument`
would reformat the whole file.) A file that isn't well-formed XML is
left unchanged and reported as not updated.

No existing library fits for editing .csproj and .props files:

- Microsoft.Build, the MSBuild API, is the "correct" editor and resolves
  import precedence, but needs Microsoft.Build.Locator plus a bound SDK
  toolset: a heavy, fragile dependency for a global tool and a departure
  from this project, which otherwise shells out to `dotnet` and reads
  NuGet libraries.
  https://www.nuget.org/packages/Microsoft.Build
  https://www.nuget.org/packages/Microsoft.Build.Locator
- FubuCsProjFile: dead since 2015, .NET Framework only.
  https://www.nuget.org/packages/FubuCsProjFile
- PackageReferenceEditor: unmaintained since 2021, and pulls in the
  ReactiveUI UI framework.
  https://www.nuget.org/packages/PackageReferenceEditor
  https://www.nuget.org/packages/ReactiveUI
- MvsSln: healthy, but depends on Microsoft.Build and is
  solution-oriented.
  https://www.nuget.org/packages/MvsSln
- SunamoCsproj: missing license text, unclear if it does what we need
  https://www.nuget.org/packages/SunamoCsproj

This covers every place that changes a version this way: central package
updates with `--no-restore`, putting back the Directory.Packages.props
layout after `dotnet add package`, `GlobalPackageReference` updates, and
the Directory.Build.props updates from the dotnet-outdated#301 fix. Restoring
`$(Variable)` references (`ReplacePackageVersion`) and editing
properties still use regex; the next two commits move them onto the XML
reader too.

The characterization tests from the previous commit now expect these
versions to be found and updated.

One upstream test asserted the old limitation: it used a `<Version>`
child element as its example of an entry that can't be updated. It now
uses an entry with no version at all.

Refs: dotnet-outdated#561
Refs: dotnet-outdated#301
Refs: dotnet-outdated#602
Refs: dotnet-outdated#316

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
timabell added a commit to timabell/dotnet-outdated that referenced this pull request Nov 13, 2026
Some upgrades write the new version into a file directly rather than
through `dotnet add package`: central package versions in
Directory.Packages.props, `GlobalPackageReference` items, and, since the
dotnet-outdated#301 fix, versions in Directory.Build.props. dotnet-outdated finds the
version to change in those files with regular expressions.

Regex can't reliably parse XML. dotnet-outdated#602 was one case: entries spread over
several lines weren't updated. dotnet-outdated#783 fixed that by making the regex
cleverer, but valid MSBuild still defeats it:

- A version written as a `<Version>` child element, which MSBuild
  accepts like any other item metadata, is never found. Upgrading a
  central package with `--no-restore` fails, and a Directory.Build.props
  entry can't be upgraded at all.
- A package id containing an XML entity reference (`Include="A&dotnet-outdated#46;B"`)
  doesn't match, because the regex compares the raw text.

Each such case would need another regex special case, and there will
always be another:
https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454

Instead, find the elements with an XML parser (`XmlReader`), which can
correctly parse the `.props` xml files, and use its line and column
information to replace only the version text, so the rest of the file
stays byte-for-byte identical. (Loading and saving with `XDocument`
would reformat the whole file.) A file that isn't well-formed XML is
left unchanged and reported as not updated.

No existing library fits for editing .csproj and .props files:

- Microsoft.Build, the MSBuild API, is the "correct" editor and resolves
  import precedence, but needs Microsoft.Build.Locator plus a bound SDK
  toolset: a heavy, fragile dependency for a global tool and a departure
  from this project, which otherwise shells out to `dotnet` and reads
  NuGet libraries.
  https://www.nuget.org/packages/Microsoft.Build
  https://www.nuget.org/packages/Microsoft.Build.Locator
- FubuCsProjFile: dead since 2015, .NET Framework only.
  https://www.nuget.org/packages/FubuCsProjFile
- PackageReferenceEditor: unmaintained since 2021, and pulls in the
  ReactiveUI UI framework.
  https://www.nuget.org/packages/PackageReferenceEditor
  https://www.nuget.org/packages/ReactiveUI
- MvsSln: healthy, but depends on Microsoft.Build and is
  solution-oriented.
  https://www.nuget.org/packages/MvsSln
- SunamoCsproj: missing license text, unclear if it does what we need
  https://www.nuget.org/packages/SunamoCsproj

This covers every place that changes a version this way: central package
updates with `--no-restore`, putting back the Directory.Packages.props
layout after `dotnet add package`, `GlobalPackageReference` updates, and
the Directory.Build.props updates from the dotnet-outdated#301 fix. Restoring
`$(Variable)` references (`ReplacePackageVersion`) and editing
properties still use regex; the next two commits move them onto the XML
reader too.

The characterization tests from the previous commit now expect these
versions to be found and updated.

One upstream test asserted the old limitation: it used a `<Version>`
child element as its example of an entry that can't be updated. It now
uses an entry with no version at all.

Refs: dotnet-outdated#561
Refs: dotnet-outdated#301
Refs: dotnet-outdated#602
Refs: dotnet-outdated#316

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Can't update multi-line <PackageVersion>

3 participants