Plan: NuGet Publishing & CI/CD Pipeline for BenefitManager.Agent.Client#
Context#
BenefitManager.Agent.Client was already extracted as a separate project with full NuGet metadata, but had placeholder URLs, a hardcoded version, and no build pipeline. BenefitManager.Contracts (its dependency) lacked NuGet metadata entirely. No CI/CD workflow existed for building, versioning, or publishing. The goal: make both packages publishable to GitHub Packages with automatic semver from git tags, and produce releases with zipped executables.
Step 1: Add MinVer for automatic versioning#
File: Directory.Build.props
MinVer reads git tags (e.g. v1.0.0) and auto-generates version numbers:
- On tag v1.2.0 → version 1.2.0
- 3 commits after tag → 1.2.1-alpha.0.3
- No tags → 0.0.0-alpha.0.N
<PropertyGroup>
<MinVerTagPrefix>v</MinVerTagPrefix>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MinVer" Version="6.0.0" PrivateAssets="All" />
</ItemGroup>
- [x] MinVer added to Directory.Build.props
- [x] Verified:
dotnet packproduces0.0.0-alpha.0.3(no tags yet)
Step 2: Make BenefitManager.Contracts NuGet-packable#
File: src/BenefitManager.Contracts/BenefitManager.Contracts.csproj
Added NuGet metadata (PackageId, Authors, Description, License, Tags) and Microsoft.SourceLink.GitHub for debugger symbol resolution. Keeps net10.0 TFM override (cross-platform library).
- [x] NuGet metadata added
- [x] SourceLink + snupkg symbols configured
Step 3: Clean up Agent.Client.csproj#
File: src/BenefitManager.Agent.Client/BenefitManager.Agent.Client.csproj
- [x] Removed
<Version>1.0.0</Version>— MinVer handles versioning - [x] Removed
<LangVersion>,<Nullable>,<ImplicitUsings>— inherited fromDirectory.Build.props - [x] Removed placeholder
yourusernameURLs and<PackageReleaseNotes>— SourceLink provides repo URL at pack time; release notes come from the GitHub Release body
Step 4: Add nuget.config#
New file: nuget.config (repo root)
Explicitly declares nuget.org as the package source for local development. CI adds the GitHub Packages source dynamically via dotnet nuget add source with GITHUB_TOKEN.
- [x] nuget.config created
Step 5: Create CI/CD workflow#
New file: .github/workflows/build-and-release.yml
Two trigger paths — both run through the build job:
Push to main: build → test → pack NuGet (prerelease) → push to GitHub Packages
Tag v*: same as above, plus the release job:
- dotnet publish Orchestrator + Agent as self-contained win-x64 single-file EXEs
- Compress-Archive each publish output into a versioned zip
- softprops/action-gh-release@v2 creates GitHub Release with auto-generated notes, zips, and .nupkg files attached
- [x] Workflow created with
build+releasejobs - [x]
fetch-depth: 0on checkout so MinVer can read full tag history - [x]
--skip-duplicateon NuGet push (safe re-runs on main) - [x]
IsPackable=falseon Orchestrator + Agent EXEs as safety guard
Step 6: Set IsPackable=false on non-library projects#
- [x]
src/BenefitManager.Orchestrator/BenefitManager.Orchestrator.csproj - [x]
src/BenefitManager.Agent/BenefitManager.Agent.csproj - (Test projects already had
IsPackable=false)
Files Changed#
| Action | File |
|---|---|
| Modify | Directory.Build.props |
| Modify | src/BenefitManager.Contracts/BenefitManager.Contracts.csproj |
| Modify | src/BenefitManager.Agent.Client/BenefitManager.Agent.Client.csproj |
| Modify | src/BenefitManager.Orchestrator/BenefitManager.Orchestrator.csproj |
| Modify | src/BenefitManager.Agent/BenefitManager.Agent.csproj |
| New | .github/workflows/build-and-release.yml |
| New | nuget.config |
Releasing a version#
git remote add origin https://github.com/ORG/benefits-mgmt.git
git tag v1.0.0
git push origin main --tags
This triggers: build → test → pack NuGet (1.0.0) → push to GitHub Packages → publish single-file EXEs → zip → create GitHub Release with all artifacts.