Repository navigation
Modernize NullFX.CRC targeting, versioning, packaging, and CI - #32
Merged
Merged
Conversation
add snk file
Keeps the existing net40, net6.0 and net7.0 targets and adds the requested modern targets (netstandard2.0, netcoreapp3.1, net45-net48 were already present). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
…VERSION
- Add Directory.Build.props holding RELEASE_MAJOR=1, RELEASE_MINOR=1,
RELEASE_REVISION=10 as the checked-in version source of truth.
- RELEASE_VERSION is computed as MAJOR.MINOR.REVISION unless passed
explicitly (e.g. -p:RELEASE_VERSION=0.0.0 for CI/PR builds).
- Version, PackageVersion, AssemblyVersion, FileVersion and
InformationalVersion all derive from RELEASE_VERSION.
- Remove the #{RELEASE_VERSION}# replace-tokens placeholders from the
library csproj; no hard-coded version remains in the project file.
- Turn off GeneratePackageOnBuild: packing is now an explicit
'dotnet pack' step so builds and test runs no longer emit packages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
- Retarget NullFX.CRC.Tests from net7.0 (EOL) to net10.0, the common test/benchmark runtime. - Pin previously floating (*) package versions so CI is reproducible. FluentAssertions is held on 7.2.0 (Apache-2.0); 8.x is commercially licensed. - Drop the redundant xunit.assert reference (included by the xunit metapackage), the replace-tokens ReleaseVersion property and the SonarQubeExclude marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
- Retarget NullFX.CRC.Benchmarks from netstandard2.0/net47/net48/ netcoreapp3.1/net6.0/net7.0 to the common net10.0 runtime. The netstandard2.0 Exe target could never run, and BenchmarkDotNet is started from a single host runtime anyway. - Update BenchmarkDotNet 0.13.5 -> 0.15.8 (0.13.x predates .NET 10). - Forward args to BenchmarkRunner so CI can choose a short job and JSON/GitHub-markdown exporters. No-arg behaviour is unchanged. - Drop the replace-tokens ReleaseVersion property and SonarQubeExclude. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
Replaces .github/workflows/cicd-actions.yml with .github/workflows/ci.yml: - Runs on windows-latest (required for the net40-net48 targets). - Installs the .NET 8 and .NET 10 SDKs. The .NET 10 SDK builds every target, including netcoreapp3.1/net6.0/net7.0 and the .NET Framework targets via reference packs, so no .NET Core 3.1 SDK is needed. - Separate jobs: build (all TFMs + 0.0.0 inspection pack), unit tests (net10.0, TRX) and benchmarks (net10.0, BenchmarkDotNet ShortRun). - Test and benchmark results are written to the job summary and uploaded as artifacts; the package and binlog are uploaded too. - Never changes the version and never publishes (release.yml does). - Removes the SonarCloud scanner, cache steps, SONAR_TOKEN usage, the JDK setup that only existed for SonarCloud, the replace-tokens step and the publish steps that ran on every push to main. - Adds .github/scripts/verify-package.ps1, which checks the packed version, README, license, per-TFM assemblies and for leftover tokens or bin/obj content. - Library csproj: drop the SonarQubeTestProject marker and set ContinuousIntegrationBuild under GitHub Actions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
Adds .github/workflows/codeql.yml as the replacement for SonarCloud: - Runs on pull requests to main, pushes to main, weekly and on demand. - windows-latest with the .NET 8 and .NET 10 SDKs, manual build mode, building the library for every target framework. - security-and-quality query suite, category /language:csharp. - Least-privilege permissions (security-events: write for upload). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
Adds .github/workflows/release.yml and .github/scripts/bump-version.ps1. On every push to main (i.e. a merged PR) or manual dispatch: 1. Read RELEASE_MAJOR/MINOR/REVISION from Directory.Build.props. 2. Increment just before the release build: patch by default, or major/minor/patch via workflow_dispatch input. Idempotent: if the stored version has no v<version>/<version> tag yet, it is released as-is instead of being incremented again. 3. Commit the bump locally, build all TFMs, pack and verify the package with that version, then run tests and short benchmarks. 4. Push the bump to main with [skip ci]; abort before publishing if the push is rejected. 5. Publish to GitHub Packages (GITHUB_TOKEN), to nuget.org only when NUGET_ORG_API_KEY is set, and create the v<version> GitHub release with the .nupkg/.snupkg attached. 6. Optionally mirror RELEASE_MAJOR/MINOR/REVISION to repository variables when RELEASE_VARIABLES_TOKEN is provided (GITHUB_TOKEN cannot write repository variables). Secrets are scoped to the steps that use them. Also lists the new workflow files and Directory.Build.props under Solution Items. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
- Install with 'dotnet add package NullFX.CRC' (no PROJECT placeholder and no hard-coded --version that goes stale every release). - Remove the broken SonarCloud quality-gate badge. - Replace the old cicd-actions build badge with CI and CodeQL workflow badges for nullfx/NullFX.CRC, and add a NuGet version badge. - List the supported target frameworks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
nuget.org now supports Trusted Publishing, so the release workflow no longer needs a long-lived NUGET_ORG_API_KEY secret. - Grant id-token: write (job-scoped; workflow default is contents: read). - Exchange the job's GitHub OIDC token for a short-lived API key with NuGet/login@v1 immediately before 'dotnet nuget push'. - Gate nuget.org publishing on the NUGET_USER secret (nuget.org profile name, not email); skip with a warning when it is absent. - The temporary key is passed via env, not inlined into the script. Requires a Trusted Publishing policy on nuget.org for owner nullfx, repository NullFX.CRC, workflow file release.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
The library referenced Microsoft.SourceLink.GitHub with Version="*". That now floats to 10.0.x, which pulls in System.IO.Hashing and emits 'doesn't support netcoreapp3.1/net6.0/net7.0' build warnings, and it made release builds non-reproducible. SourceLink for GitHub ships in the .NET 8+ SDK (required for the net8.0 and net10.0 targets), so the package reference is removed. Verified the packed nuspec still carries the repository commit and that the package has no dependencies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU
Owner
Author
|
🥳 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Modernize NullFX.CRC targeting, versioning, packaging, and CI
Summary
This PR modernizes the NullFX.CRC target frameworks, versioning, NuGet packaging, README and CI/CD pipeline. It does not change the library's public API, and it does not publish a package.
Target frameworks
The library now targets:
netstandard2.0;netcoreapp3.1;net40;net45;net46;net47;net48;net6.0;net7.0;net8.0;net10.0net8.0,net10.0netstandard2.0,netcoreapp3.1,net45,net46,net47,net48net40,net6.0,net7.0. I kept them because the instructions said not to remove valid targets.net6.0andnet7.0are out of support (they still build cleanly with the .NET 10 SDK). Dropping them could be a follow-up.net7.0→net10.0netstandard2.0;net47;net48;netcoreapp3.1;net6.0;net7.0→net10.0. Thenetstandard2.0Exe target could never run.Versioning
Directory.Build.propsis the single, checked-in source of truth:RELEASE_MAJOR=1,RELEASE_MINOR=1,RELEASE_REVISION=10.RELEASE_VERSIONis computed as$(RELEASE_MAJOR).$(RELEASE_MINOR).$(RELEASE_REVISION)unless it is passed explicitly, for example-p:RELEASE_VERSION=0.0.0.Version,PackageVersion,AssemblyVersion(x.y.z.0),FileVersion(x.y.z.0) andInformationalVersionare all derived from it. No version is hard-coded in any.csproj.vars.RELEASE_VERSIONis no longer used anywhere. After merge you can delete that repository variable.GITHUB_TOKENcannot write Actions repository variables, so a workflow cannot safely increment them on its own. If aRELEASE_VARIABLES_TOKENsecret is set (a fine-grained PAT with "Variables: read and write"), the release workflow mirrorsRELEASE_MAJOR/MINOR/REVISIONinto repository variables after each release so they stay visible. The file remains the source of truth.Packaging / nuspec
.csproj.dotnet packhandles every TFM, the README, the license expression, SourceLink and the.snupkgnatively. A standalone.nuspecwould duplicate metadata.#{RELEASE_VERSION}#placeholders and thecschleiden/replace-tokensstep are removed. The version comes only from the MSBuild property.0.0.0placeholder or release-time replacement.GeneratePackageOnBuildis nowfalse. Packing is an explicitdotnet packstep, so builds and test runs no longer emit packages as a side effect.ContinuousIntegrationBuild=trueis set under GitHub Actions for deterministic, SourceLink-friendly builds.Microsoft.SourceLink.GitHubVersion="*"reference. It had started resolving to 10.0.x, which pulls inSystem.IO.Hashingand caused unsupported-TFM warnings fornetcoreapp3.1,net6.0andnet7.0. SourceLink is built into the .NET 8+ SDK, and the packed nuspec still records the repository commit..github/scripts/verify-package.ps1checks every packed.nupkg:README.mdis packed and referencedlib/<tfm>/NullFX.CRC.dllfor every TFM, read from the project#{…}#tokens.snkfilesREADME
dotnet add PROJECT package NullFX.CRC --version 1.1.10→dotnet add package NullFX.CRCcicd-actions.ymlbadge with CI (ci.yml) and CodeQL (codeql.yml) badges fornullfx/NullFX.CRC, and added a NuGet version badge.CI/CD
ci.yml(replacescicd-actions.yml)main, pushes tomainand manual dispatch.windows-latest, which is required fornet40–net48.netcoreapp3.1,net6.0,net7.0and .NET Framework, so a .NET Core 3.1 SDK is not needed.0.0.0inspection package, and uploads the package and binlog.test-resultsartifact.benchmark-resultsartifact. ShortRun keeps PR feedback quick, and shared runners can't give stable absolute timings anyway.0.0.0. They never change version state and never publish.SONAR_TOKEN, the JDK setup that only existed for it, and the csprojSonarQube*markers. The old workflow also published to NuGet on every push tomain; that now happens only inrelease.yml.codeql.yml(new)main, pushes tomain, weekly (Monday 06:30 UTC) and manual dispatch.windows-latest,github/codeql-action@v4,languages: csharp,build-mode: manual,security-and-qualityqueries,category: /language:csharp.release.yml(new)Runs on push to
main(a merged PR) or onworkflow_dispatch, which takes abumpinput ofpatch,minorormajor.v<ver>or<ver>tag yet (because an earlier run failed after bumping), it releases that version instead of incrementing again. It refuses to bump onto a version that is already tagged.mainasrelease: vX.Y.Z [skip ci]. If the push is rejected, the run stops before anything is published.vX.Y.Ztag and GitHub release with the.nupkg/.snupkgattached.Secrets are scoped only to the steps that use them. The PR validation workflow never increments the version.
nuget.org Trusted Publishing
No long-lived nuget.org API key is stored. The release job has
id-token: write. Right before the push,NuGet/login@v1exchanges the job's GitHub OIDC token for a short-lived (about 1 hour) API key, which is passed todotnet nuget pushthrough an environment variable. If theNUGET_USERsecret is missing, the nuget.org step is skipped with a warning; GitHub Packages and the GitHub release still happen.Setup needed before the first release:
nullfx, repositoryNullFX.CRC, workflow filerelease.yml(no environment).NUGET_USERwith the nuget.org profile name (not the email address).NUGET_ORG_API_KEYsecret and revoke that key on nuget.org. Nothing uses it anymore.Optional secrets:
NUGET_USERRELEASE_PUSH_TOKENmainblocksGITHUB_TOKENfrom pushing the version commit.RELEASE_VARIABLES_TOKENRELEASE_MAJOR/MINOR/REVISIONinto repository variables.Validation
Run locally on Linux x64 with .NET SDK 10.0.401 and 8.0.425 and PowerShell 7.4. The Windows runners in CI are the final check, especially for the .NET Framework targets.
dotnet build -c Release(library, all 11 TFMs)SYSLIB0051on net8.0/net10.0 from the existing serialization constructor onUnknownAlgorithmException(public API, left unchanged).dotnet test -c Release -f net10.0--job short --exporters json github)dotnet packwith0.0.0NullFX.CRC.0.0.0.nupkg+.snupkg.verify-package.ps1passes: 11 TFMs, README, MIT, no dependencies, no tokens, no stray files.RELEASE_VERSION=1.1.11,GITHUB_ACTIONS=true)NullFX.CRC.1.1.11.nupkgverifies. The nuspec carries the SourceLink repository commit. The assemblies areNullFX.CRC, Version=1.1.11.0, PublicKeyToken=090786b319d4654b. Nothing was published.ci.ymlwere run against the real outputs above.git diff --checkis clean. Nosonar,#{RELEASE_VERSION}#,PROJECT package,vars.RELEASEorNUGET_ORG_API_KEYreferences remain.1.1.10appears nowhere; it lives only as 1/1/10 inDirectory.Build.props. No bin/obj, nupkg or trx files are tracked.Notes and follow-ups
release.yml. Because1.1.10is already tagged, the first run will bump to 1.1.11, push that commit tomain, publish to GitHub Packages (and to nuget.org if Trusted Publishing is set up), and create thev1.1.11release. If you don't want a release on merge, disable the Release workflow first or add a path filter.vX.Y.Z. Historical tags (1.1.10, …) have nov; the bump script recognises both.NullFX.CRC.snkandSignAssembly. The first release built here will be the first strong-named NullFX.CRC. That changes the assembly identity, which can affect .NET Framework consumers that bind to the unsigned assembly, so please consider it before releasing. Committing the.snkfollows Microsoft's guidance for OSS strong naming.x.y.z.0), as it did before. For a strong-named library, a common alternative is to pinAssemblyVersiontox.0.0.0to avoid binding redirects.*before. FluentAssertions is held on 7.2.0 because 8.x is commercially licensed. BenchmarkDotNet moved from 0.13.5 to 0.15.8 for .NET 10 support.Microsoft.NETFramework.ReferenceAssemblies. The SDK references it automatically when targeting packs are missing, and Windows runners have them installed anyway.🤖 Generated with Claude Code
https://claude.ai/code/session_012C6aJYkYBV2GSnSZwsd9GU