Development, testing & publishing¶
How to build the .NET solution, run the tests with coverage, and publish the NuGet packages via trusted publishing (OIDC — no stored API key).
Solution layout¶
src/
FdaObservability.Core net8.0 shared query client (FdaKustoClient, models, auth) → NuGet: FdaObservability.Core
FdaObservability.App net8.0-windows WinForms review app
FdaObservability.Api net8.0 REST API + OpenAPI
FdaObservability.Mcp net8.0 MCP stdio server
FdaObservability.Cli net8.0 fda-obs CLI → NuGet: FdaObservability.Cli
tests/
FdaObservability.Tests net8.0 xUnit tests + coverage
The App targets net8.0-windows, so the full solution builds on Windows. The cross-platform
projects (Core, Api, Mcp, Cli, Tests) build and test on any OS.
Build & test¶
dotnet restore src/FdaObservability.sln
dotnet build src/FdaObservability.sln -c Release
dotnet test src/FdaObservability.sln -c Release --collect:"XPlat Code Coverage"
CI runs the same on windows-latest (.github/workflows/dotnet.yml)
and uploads the Cobertura coverage report as an artifact.
Coverage¶
The suite focuses on the deterministic logic and the surface behaviour:
| Assembly | What's covered |
|---|---|
Core |
KQL builders + literal escaping, time-window resolution, row mapping (via DataTableReader), KPI math, options validation, token-scope derivation, and the client's query methods (through an injected fake executor). The thin network executor is [ExcludeFromCodeCoverage]. |
Api |
Every endpoint via WebApplicationFactory with a fake IFdaKustoClient — routing, query binding, 404, health 200/503, the API-key gate, and the swagger redirect. |
Mcp |
The full request handler (initialize, tools/list, tools/call, ping, errors, notifications) and the stdio read loop, against a fake client. |
Cli |
The argument parser and every command path (JSON + table output, not-found, unknown command, errors). |
The only uncovered lines are the process entry points (Program env/auth wiring and the stdio
loop's host plumbing), which are exercised by manual smoke tests rather than unit tests.
NuGet packages¶
Two projects are packable:
| Package | Project | Install |
|---|---|---|
FdaObservability.Core |
shared library | dotnet add package FdaObservability.Core |
FdaObservability.Cli |
fda-obs global tool |
dotnet tool install -g FdaObservability.Cli |
Pack locally:
dotnet pack src/FdaObservability.Core/FdaObservability.Core.csproj -c Release -o artifacts
dotnet pack src/FdaObservability.Cli/FdaObservability.Cli.csproj -c Release -o artifacts
Trusted publishing (OIDC)¶
Publishing uses NuGet trusted publishing: the publish workflow requests a short-lived OIDC token from GitHub, exchanges it with nuget.org for a temporary API key (valid 1 hour), and pushes. No long-lived API key is stored.
flowchart LR
gha[GitHub Actions job<br/>id-token: write] -->|OIDC token| nuget[nuget.org<br/>token exchange]
nuget -->|temp API key 1h| gha
gha -->|dotnet nuget push| feed[(nuget.org feed)]
One-time setup (repo owner)¶
- nuget.org → your username → Trusted Publishing → Add policy:
- Repository Owner:
PatrickGallucci - Repository:
fda-observability - Workflow File:
nuget-publish.yml(file name only — no path) - Environment: leave empty
- Repository Owner:
- Add a repository secret
NUGET_USER= your nuget.org profile name (not your email). - If the package IDs don't exist yet, the first successful publish reserves them under your account.
Pending activation
For private repos the policy is temporarily active for 7 days until the first publish locks it to the repo/owner IDs. Publish within that window to make it permanent.
Publishing a release¶
The workflow triggers on a published GitHub Release (or manual Run workflow):
- Bump
<Version>inCore/Clicsproj (and the others) + updateCHANGELOG.md. - Commit, tag
vX.Y.Z, and create a GitHub Release for the tag. - The publish workflow packs both projects (versioned from the tag) and pushes them via OIDC.
Manual dispatch accepts an optional version input; otherwise the csproj version is used.