NuGet packages, builds, and releases
The repository is configured for the stable version 3.0.0. Package and GitHub release publication are separate steps; these instructions do not imply that the version is already available on either registry. See the 3.0 release notes, 2.x migration guide, and documentation index before upgrading.
Install in a consuming application
After publication to NuGet.org, select the version explicitly:
dotnet add package Consoul --version 3.0.0
dotnet add package Consoul.Cli --version 3.0.0
Optional integration packages use the same --version 3.0.0 argument. This stable version does not require enabling Include prerelease in Visual Studio’s NuGet manager. NuGet.org package restore requires no API key. If a consuming project uses multiple feeds, ensure its configuration can also resolve public integration dependencies from NuGet.org.
Before publication, consume the locally built packages with a configuration in a separate smoke-test application directory. Replace the local path below with the output directory on your machine:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="consoul-local" value="C:\path\to\Consoul\artifacts\packages\3.0.0" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
Then use the same explicit-version install commands in that application. NuGet caches packages by ID and version. If rebuilding a local candidate with the same identity, isolate the consumer’s global package cache (for example, set NUGET_PACKAGES to a temporary directory for that smoke test) so an older locally cached package cannot masquerade as the latest build. Published package versions should be immutable; use a new version for a changed release.
For GitHub Packages, add https://nuget.pkg.github.com/tbm0115/index.json to the consuming application’s feed configuration alongside NuGet.org. Outside GitHub Actions, authentication uses a GitHub personal access token (classic) with read:packages and access to the package. Supply the source credential through a user-scoped configuration or a session environment variable, never a committed file. For a source named github, NuGet recognizes:
# Obtain the token through your local secret manager; do not hard-code it here.
$env:NuGetPackageSourceCredentials_github = "Username=$env:GITHUB_USER;Password=$env:GITHUB_PACKAGES_READ_TOKEN;ValidAuthenticationTypes=Basic"
dotnet add package Consoul --version 3.0.0
The feed’s configured name must match the suffix github. Clear session credentials when the restore session ends. GitHub’s registry documentation describes token scopes and repository/package access rules.
Package and dependency matrix
All five packages share the version in Directory.Build.props. Install only the integrations the application needs.
| Package | Shipped target frameworks | Direct package dependencies |
|---|---|---|
Consoul |
netstandard2.0, netcoreapp3.1, net461 |
No optional infrastructure packages. Framework support dependencies can be supplied by the SDK. |
Consoul.Cli |
netstandard2.0 |
Consoul at the same release version |
Consoul.Extensions.Configuration |
netstandard2.0 |
Consoul at the same release version; Microsoft.Extensions.Configuration.Json 10.0.9 |
Consoul.Extensions.Logging |
netstandard2.0 |
Consoul at the same release version; Microsoft.Extensions.Logging 10.0.9 |
Consoul.Text.Json |
netstandard2.0 |
Consoul at the same release version; System.Text.Json 8.0.5 |
Project references become NuGet dependencies when packing. Their generated minimum versions must match this release; package verification checks that relationship. NuGet also resolves the transitive dependencies of the integration libraries. A package’s target framework does not guarantee that all its dependencies support every historical runtime that implements that framework. Check the restored dependency graph in the consuming application, especially for older .NET Framework applications.
The legacy core targets are preserved for compatibility. They are compilation targets, not a claim that the underlying .NET Core 3.1 or .NET Framework 4.6.1 runtimes are still supported. The current automated tests run on .NET 8; they do not establish runtime coverage for those older targets or every terminal/operating system.
Package contents and version ownership
Directory.Build.props owns package version 3.0.0, assembly/file version 3.0.0.0, repository metadata, release notes, deterministic compilation, portable PDB generation, and XML documentation generation. Assembly and file versions are numeric; the package/informational version has no prerelease suffix for this stable release. The SDK may append the source revision to informational version metadata.
Directory.Build.targets includes each library’s own README.md, the repository LICENSE, and the shared 128 × 128 Ember icon as consoul-icon.png in the package root. All five projects inherit PackageIcon from Directory.Build.props; no remote icon URL is required. See the brand asset guide for other sizes and formats. License metadata points to the existing LGPL v3 license file. Each lib/<TFM>/ directory contains its assembly and matching XML IntelliSense documentation. A separate .snupkg carries the portable PDBs for each target. XML comments are therefore available to consumers without a source checkout. The SDK supplies repository/source revision metadata during builds when available.
Missing public API documentation and malformed/unresolved XML documentation warnings are errors for packable projects: CS1591, CS1570, CS1572, CS1573, CS1574, CS1580, CS1581, CS1584, CS1587, CS1711, and CS1712. scripts/Verify-Documentation.ps1 additionally checks generated documentation and local Markdown links. Warnings are not suppressed to make release validation pass.
Only the five library projects opt into IsPackable. Tests and the sample are not packages. GeneratePackageOnBuild is disabled: an ordinary build compiles the solution, and explicit packing follows successful tests. Update the shared version and release notes together for each release; avoid per-project version overrides that would separate integration dependencies from the core release.
Build prerequisites and restore configuration
Install the .NET SDK selected by global.json: 10.0.300, or a later stable patch in the same 10.0.3xx feature band. rollForward: latestPatch allows servicing patches but does not silently switch feature bands or SDK major versions. Install a .NET 8 runtime as well to execute the existing net8.0 tests and sample; installing the .NET 8 SDK provides that runtime. CI provisions both through actions/setup-dotnet.
The supported release verification path uses Windows and PowerShell 7, matching CI. Building net461 requires .NET Framework reference assemblies; the SDK may restore the reference assembly package when the targeting pack is absent. Building all targets does not require installing the .NET Core 3.1 runtime because no tests execute on that runtime.
NuGet.Config clears inherited package sources and selects only the public NuGet v3 feed, https://api.nuget.org/v3/index.json. Repository restore requires no private feed or credential. This prevents a developer’s unrelated private feed from becoming an undocumented CI prerequisite. Consumers can use a separate configuration for GitHub Packages or local packages; do not put credentials in this repository’s configuration.
Inspect installed tools from the repository root:
dotnet --version
dotnet --list-runtimes
Validate and pack locally without publishing
Run the same orchestration script used by CI:
pwsh -File ./scripts/Verify-Release.ps1
It restores the solution from NuGet.Config, builds Release, runs the complete xUnit project, packs each of the five libraries, checks all package contents and dependency versions, then checks documentation. Every native command exit code is checked. No publishing command is present in this script.
Outputs are five .nupkg and five .snupkg files under artifacts/packages/3.0.0/, plus test results under artifacts/test-results/. The package verifier rejects extra versions or missing packages in its selected directory; use a clean output directory for each candidate. The default directory includes the configured version to keep releases apart.
The equivalent individual commands, useful while diagnosing a specific stage, are:
dotnet restore Consoul.sln --configfile NuGet.Config
dotnet build Consoul.sln --configuration Release --no-restore
dotnet test Consoul.Tests/Consoul.Tests.csproj --configuration Release --no-build --no-restore
$projects = 'Consoul', 'Consoul.Cli', 'Consoul.Extensions.Configuration', 'Consoul.Extensions.Logging', 'Consoul.Text.Json'
foreach ($project in $projects) {
dotnet pack "$project/$project.csproj" --configuration Release --no-build --no-restore --output artifacts/packages/3.0.0
if ($LASTEXITCODE -ne 0) { throw "Packing failed for $project" }
}
pwsh -File ./scripts/Verify-Packages.ps1
pwsh -File ./scripts/Verify-Documentation.ps1 -Configuration Release
--no-build and --no-restore require the corresponding earlier stages to have succeeded for the same configuration and version. Do not reuse old outputs after a source/version change. Package verification checks the package ID/version, README/license/icon/repository metadata, assemblies and XML files for every expected target, matching core dependency versions, and corresponding symbol packages.
CI and publication safeguards
dotnetcore.yml runs validation on pushes, pull requests, manual dispatch, and published GitHub release events. Push, PR, and manual runs only build, test, verify, and upload workflow artifacts. They cannot enter the publication job. The workflow uses explicit action major versions instead of floating @main, disables checkout credential persistence, and gives validation only contents: read permission.
Actual publication is a separate job that requires a successful validation job and a GitHub release: published event. Before validation and again before publishing, Validate-ReleaseTag.ps1 requires the exact tag v3.0.0 to match Directory.Build.props. This stable version requires a non-prerelease GitHub release: leave Set as a pre-release unchecked. For future versions containing a prerelease suffix, the guard instead requires GitHub’s prerelease flag. Publishing either kind of GitHub release is a real registry publication; creating a draft or running this workflow manually is not.
The publication job downloads and verifies the same package artifact that passed validation. It pushes all five main packages and their .snupkg symbols to the NuGet v3 endpoint, then the five main packages to the repository owner’s GitHub Packages feed. Symbols remain available in workflow artifacts and NuGet.org’s symbol service. Pushes check exit codes and use --skip-duplicate so a partially completed release can resume; duplicate skipping does not compare an existing registry package’s contents or replace it. Do not retry a version with different bytes.
Required publisher configuration:
| Setting | Purpose |
|---|---|
| NuGet.org Trusted Publishing policy | For package owner tbm0115, trust repository owner tbm0115, repository Consoul, workflow file dotnetcore.yml, and environment production. Authorize the five package IDs and creation of new IDs where needed. |
GitHub Actions environment production |
The publication job declares this environment to match the NuGet policy. Any environment protection rules must permit the release tag and be satisfied before publishing. |
NuGet account tbm0115 and job permission id-token: write |
NuGet/login@v1 exchanges the publishing job’s GitHub OIDC token for a temporary NuGet API key immediately before the pushes. No repository NUGET_API_KEY secret is required. |
Automatic GITHUB_TOKEN with job permission packages: write |
Publishes packages associated with this repository. Repository/organization policy and existing package access must permit the workflow to write each package. |
| Repository owner | Determines https://nuget.pkg.github.com/<owner>/index.json; the current owner is tbm0115. No GPR_URI or GPR_USERNAME secret is needed. |
The NuGet login step’s user is the NuGet account username, not an email address. Its NUGET_API_KEY output supplies both package and symbol pushes; the workflow no longer reads a stored NuGet API key. Only the publication job can request an OIDC token. The policy’s workflow filename and environment must match the job; creating the policy alone does not update workflow authentication. See NuGet Trusted Publishing and the NuGet login action.
GitHub creates a referenced environment automatically if it does not exist. To require reviewers or restrict release tags, configure production under repository Settings > Environments before the publishing job runs.
For a release that failed before the Trusted Publishing workflow change, use a new package version and matching release tag whose commit includes the updated workflow and release notes. Keep the existing tag unchanged. Re-running an old workflow uses its original commit and ref, so it will still use the old authentication. Manual dispatch remains validation-only.
The GitHub publication step creates a temporary runner configuration containing only a named github source URL. Its NuGetPackageSourceCredentials_github environment variable supplies the actor and GITHUB_TOKEN for Basic authentication when NuGet reads the service index; the same token is passed as the publishing API key. This avoids relying on a push API key alone to authenticate feed discovery. The temporary file contains no token. NuGet documents this environment credential convention.
Credentials are not needed for validation runs and are not included in package metadata, artifacts, or the checked-in NuGet configuration. Registry account ownership and package permissions must be confirmed by a maintainer before a future publication; local validation cannot prove those permissions or registry availability.
No release, tag, push, or registry publication is performed by preparing these files. Before an authorized publication, review the migration/release notes, test the packages in a fresh consumer, commit the intended source snapshot, and obtain green CI for it. Publish the non-prerelease GitHub release for v3.0.0 only when the release is intended to become available to consumers.