Repository navigation
[Tech Debt]: Introduce Central Package Management (CPM) and a deliberate dependency-version policy #328
Description
Summary
Adopt Central Package Management (CPM) — a single Directory.Packages.props
that owns every dependency version — codify a dependency-version policy that
keeps redistributable-library floors low, and exclude the deliberately-floored
packages from the outdated-package CI check so they stop generating recurring
"NuGet Package Issues Detected" issues.
Motivation
Each of the ~22 .csproj files carries its own Version="…" per PackageReference:
-
Duplication / drift risk. The test stack (
NUnit 4.6.1,NUnit3TestAdapter 6.2.0,
NUnit.Console 3.22.0,Microsoft.NET.Test.Sdk 18.6.0,coverlet.* 10.0.1,
Microsoft.Extensions.Logging.Console 10.0.9) is repeated in every test project. -
Library floors are too high. The redistributable libraries multi-target
netstandard2.1;net10.0and pin runtime-era versions that become a minimum
floor for every downstream consumer (the floor bites hardest on the
netstandard2.1target; onnet10.0these are in-box/unified). These abstraction
packages have been API-stable since 6.0 and NuGet unifies to the consuming app's
version anyway, so the high floor only narrows compatibility. -
The outdated-check fights the policy.
.github/workflows/nuget-reference-check.yml
runsdotnet list package --outdateddaily and opens/updates a "NuGet Package
Issues Detected" issue. Once we intentionally floor a package, it is by design
"outdated" forever, so the check would nag continuously unless excluded.
Packages to floor (exhaustive, from current dependencies)
Only stable framework-abstraction packages referenced by redistributable
libraries are floored. Suggested floor: latest LTS (e.g. 8.0.x); final
version at implementer discretion, provided the APIs used still resolve.
| Package | Referenced by (library) | Current | Action |
|---|---|---|---|
Microsoft.Extensions.Logging.Abstractions |
SysML2.NET, SysML2.NET.Serializer.TextualNotation |
10.0.9 | Floor to LTS |
System.Collections.Immutable |
SysML2.NET, SysML2.NET.Serializer.TextualNotation |
10.0.9 | Floor to LTS |
System.IO.Pipelines |
SysML2.NET.Serializer.MessagePack |
10.0.9 | Floor to LTS (note: MessagePack's own transitive floor wins if higher) |
Proposed approach
- Add
Directory.Packages.propsat the repo root (<ManagePackageVersionsCentrally>true</…>, one<PackageVersion>per package). - Strip
Version="…"from every<PackageReference>. - Floor the three packages in the table above to an LTS version.
- Extend
IGNORE_PACKAGESin.github/workflows/nuget-reference-check.ymlwith those three floored packages so they no longer trigger the outdated issue — while remaining covered by the--deprecatedand--vulnerablesteps (which do not use the ignore filter).
Dependency-version policy
- Redistributable libraries (
SysML2.NET,.Serializer.*,.Dal,.REST,
.Kpar,.Extensions,.PIM): reference the lowest version providing the APIs
used. Keep stable framework abstractions (Microsoft.Extensions.*,
System.Collections.Immutable,System.IO.Pipelines, …) at an LTS floor; do
not chase majors. - Applications & test projects (
SysML2.NET.Viewer, all*.Tests): keep current. - Bump a library dependency only when (a) a required new API needs it, or (b) a
CVE affects that specific package. Serialization/crypto packages track current.
CI: exclude floored packages from the outdated check (not from security)
- Add the three floored packages to
IGNORE_PACKAGESinnuget-reference-check.yml
(the regex on line ~33). This suppresses only the outdated signal. - Do NOT exclude them from
--deprecatedor--vulnerable— a floored package
with a CVE must still surface. - Keep the floored/ignored list as a single source of truth: list the floored
packages once (e.g. a comment block inDirectory.Packages.props) and mirror
them in the workflow'sIGNORE_PACKAGES, so the two never drift.
Scope / tasks
- Add
Directory.Packages.propscentralizing all versions. - Remove
Version=from everyPackageReference. - Floor
Microsoft.Extensions.Logging.Abstractions,System.Collections.Immutable, andSystem.IO.Pipelinesto an LTS version (per the table). - Extend
IGNORE_PACKAGESin.github/workflows/nuget-reference-check.ymlwith those three packages (outdated check only). - Document the dependency-version policy + the floored/ignored list (single source of truth) in
README.md,CLAUDE.md, and the project wiki. -
dotnet restore+dotnet build+ fulldotnet testgreen;CodeQuality.ymlunaffected;nuget-reference-check.ymlproduces no recurring outdated issue for floored packages.
Out of scope
- Mass-bumping application/test package versions.
- Changing target frameworks.
- Weakening the deprecated/vulnerable checks (those stay strict on every package).
References
- MS Docs — Central Package Management: https://learn.microsoft.com/nuget/consume-packages/central-package-management
dotnet list package --outdated: https://learn.microsoft.com/dotnet/core/tools/dotnet-list-package
Activity