Skip to content

Modernize build infrastructure, CI and analyzer compliance - #7

Merged
capjan merged 3 commits into
mainfrom
modernize/build-infra
Sep 25, 2026
Merged

capjan merged 3 commits into
mainfrom
modernize/build-infra

Conversation

@capjan

@capjan capjan commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Summary

Phases 0-3 of the modernization plan. The public API is unchanged (verified with package validation against the published Cap.Core 12.0.0).

Build (213c4dd)

  • Targets: net10.0;net8.0;netstandard2.0 (drops the EOL net6.0); tests run on net10.0 and net8.0
  • Directory.Build.props / Directory.Packages.props (central package management), global.json, .editorconfig
  • CoreLib.sln -> CoreLib.slnx
  • mkver replaced by MinVer (tag prefix v); the SourceLink package is dropped (built into the SDK)
  • Test stack updated (xunit 2.9.3, Test.Sdk 18, coverlet)

CI (213c4dd)

  • Build and test on Linux, Windows and macOS; pack on every change
  • Tests that need the internet are marked Category=Network and run non-blocking
  • Release: NuGet trusted publishing with fallback to the NUGET_API_KEY secret, and a check that the package version matches the release tag
  • Dependabot for NuGet and GitHub Actions

Analyzer compliance (a30e4bf)

  • All 131 CA* findings are fixed or explicitly accepted; analyzer findings now fail the build
  • Rules that can only be fixed by breaking the public API are downgraded in Core/.editorconfig for 13.0; MD5/SHA1 are suppressed locally until deprecation
  • Bug fixes found on the way: HttpHeader parsed dates with the current culture (fails e.g. for ar-SA), GeoLocation threw the wrong exception type for a null longitudeDMS, the macOS name mapping ended at macOS 13, and a wrong expectation in LoremIpsumGeneratorTest was swallowed by DefaultTempUtil.UseFile (which also made TestLog flaky)
  • New CultureIndependenceTest

Test plan

  • dotnet build on the whole solution: 0 warnings, 0 errors
  • 253/253 offline tests pass on net10.0 and net8.0 (local, macOS), 25 repeated runs without a failure
  • dotnet pack produces net10.0, net8.0 and netstandard2.0 assets
  • Package validation against Cap.Core 12.0.0: no removed types or members (only ISpanFormattable noise from dropping the net6.0 asset)
  • The Windows and macOS CI jobs have never run; the first run of this PR is their first check
  • The trusted publishing policy on nuget.org still has to be created (owner Capjan, repo capjan/CoreLib, workflow nuget_deploy.yml); until then the release workflow uses the API key secret

Notes

  • PublicIpResolverTest.DefaultServiceUrlTest still fails on hosts that answer with an IPv6 address (it asserts an IPv4 regex). It carries the Network trait, so CI treats it as informational.
  • Not part of this PR: breaking API changes for 13.0 (HttpWebRequest, sync-over-async, MD5/SHA1 deprecation, async overloads).

Build
- target net10.0, net8.0 and netstandard2.0 (drop EOL net6.0)
- add Directory.Build.props and Directory.Packages.props (central package management)
- treat compiler warnings as errors, enable analyzers (CA* stay warnings for now)
- replace mkver with MinVer (tag prefix "v"), drop SourceLink package (built into the SDK)
- migrate CoreLib.sln to CoreLib.slnx, add global.json and .editorconfig
- update test stack (xunit 2.9.3, Test.Sdk 18, coverlet)

CI
- build and test on Linux, Windows and macOS, pack on every change
- tests that need the internet are marked Category=Network and run non-blocking
- publish via NuGet trusted publishing, falling back to the API key secret
- verify that the package version matches the release tag
- add dependabot for NuGet and GitHub Actions

Fixes
- resolve macOS release names for macOS 14, 15 and 26 and fall back to the product name
- fix wrong expectation in LoremIpsumGeneratorTest that DefaultTempUtil.UseFile swallowed,
  which also made TestLog flaky through the process-wide log event
- make TestLog collect only its own events
- fix xunit analyzer findings in MaskedTextFormatterTest and DownloaderTest
Enable CodeAnalysisTreatWarningsAsErrors. All 131 CA findings in Core are either fixed or
explicitly accepted; nothing about the public API changes.

Fixed
- culture: use ordinal comparisons and ToLowerInvariant; format and parse machine-readable
  values (URLs, hex, HTTP headers, OS versions) with the invariant culture
- HttpHeader parsed Date/Last-Modified with the current culture, which fails for e.g. ar-SA
- GeoLocation threw ArgumentException instead of ArgumentNullException for longitudeDMS
- pass parameter names and messages to ArgumentException/ArgumentOutOfRangeException
- seal internal types, call GC.SuppressFinalize in Dispose, use static readonly separator arrays
- AssertionPredicate uses TextWriter.Null instead of an undisposed StreamWriter
- narrow private field and parameter types (CA1859)
- add the Polyfill source generator for netstandard2.0 (no runtime dependency)

Accepted (Core/.editorconfig, Core/Extensions/SecurityRelated/HashAlgorithmExt.cs)
- rules that can only be fixed by breaking the public API are downgraded to suggestions and
  revisited for 13.0: naming (CA1711, CA1716, CA1720, CA1725), public fields (CA1051, CA2211),
  static members (CA1000, CA1822), CA2201
- MD5/SHA1 (CA5350, CA5351) are suppressed locally until they are deprecated in 13.0
- CA1307 and CA1510 are off: the affected overloads are ordinal by default, and
  ArgumentNullException.ThrowIfNull does not exist on netstandard2.0

Tests: add CultureIndependenceTest (de-DE, tr-TR, sv-SE, ar-SA).
DefaultServiceUrlTest asserted that every service returns the same IPv4 address. That fails on
dual-stack hosts (a service answers with IPv6) and behind NAT pools such as GitHub-hosted runners,
where consecutive requests leave via different addresses (seen on macos-latest).

Each service must now answer with a valid IP address (IPv4 or IPv6); Resolve() is still expected
to return an IPv4 address.
@capjan
capjan merged commit f7bc1c8 into main Sep 25, 2026
4 checks passed
@capjan
capjan deleted the modernize/build-infra branch September 26, 2026 00:36
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.

1 participant