Reference version
2.1.70-preview (latest published version); analysis done at commit bcb836c, where the merged line coverage of ReleaseCommand is 0/154.
Background and motivation
Issue #320 extracted the extractable logic from ReleaseCommand (hook-args assembly into PostReleaseHookArgsFactory, working-tree change tracking into GitService.TrackChangesAsync), but what remains is exactly what cannot move out: sequencing and policy. The release commit must exist before the artifact pass; the tag check must precede pack; the post-release commit assembles hook changes and dogfood rewrites; push precedes NuGet push. A regression in that ordering surfaces only during an actual release — still the worst possible moment, since releases are not rehearsable locally. And every PR that touches ReleaseCommand accrues a few uncovered patch lines that Codecov rightly flags, with no way to do better until the orchestrator is executable under test.
Proposed enhancement
ReleaseCommand.ExecuteAsync runs end-to-end in a test harness, with only the process and platform boundaries faked, so the sequencing itself is covered by tests.
Implementation proposals
- Drive the real services over a
TempGitRepo with a VERSION file and a buildvana.json: real GitService, VersionService, ChangelogService, HookRunner. The composition stays honest — no mock-and-assert-the-mock.
- Fake only the boundaries that already have seams:
IProcessRunner (FakeProcessRunner exists in Buildvana.Core.Testing) for dotnet invocations, IFileBasedAppRunner for hooks, and a test ServerAdapter (the class is already abstract with a factory) whose release object records UpdateRepository / AddPostReleaseCommit / AddAsset / PushUpdates / PublishAsync calls in order.
- Assert observable sequences: happy-path prerelease release; changelog policy variants (
none | stable | all, empty-section substitute); hook-modified files joining the post-release commit; version-spec change application; tag-collision failure.
- The test
ServerAdapter must not deepen the current adapter shape: the platform/git-host split is planned, so the fake should be designed against the seams that split will keep.
Usage examples
Not user-facing; example of the kind of test this enables:
[Test]
public async Task Release_AssemblesPostReleaseCommit_FromHookChangesAndDogfoodRewrites() { /* ... */ }
Risks
The harness may reveal that some services need construction seams (e.g. BuildPipeline); prefer constructor-level composition over new interfaces. Test-only change; no changelog entry unless behavior fixes fall out.
Additional information
Follow-up to #320, which deliberately stopped at extraction; the residue this issue covers is the part extraction cannot reach.
Reference version
2.1.70-preview (latest published version); analysis done at commit bcb836c, where the merged line coverage of
ReleaseCommandis 0/154.Background and motivation
Issue #320 extracted the extractable logic from
ReleaseCommand(hook-args assembly intoPostReleaseHookArgsFactory, working-tree change tracking intoGitService.TrackChangesAsync), but what remains is exactly what cannot move out: sequencing and policy. The release commit must exist before the artifact pass; the tag check must precede pack; the post-release commit assembles hook changes and dogfood rewrites; push precedes NuGet push. A regression in that ordering surfaces only during an actual release — still the worst possible moment, since releases are not rehearsable locally. And every PR that touchesReleaseCommandaccrues a few uncovered patch lines that Codecov rightly flags, with no way to do better until the orchestrator is executable under test.Proposed enhancement
ReleaseCommand.ExecuteAsyncruns end-to-end in a test harness, with only the process and platform boundaries faked, so the sequencing itself is covered by tests.Implementation proposals
TempGitRepowith aVERSIONfile and abuildvana.json: realGitService,VersionService,ChangelogService,HookRunner. The composition stays honest — no mock-and-assert-the-mock.IProcessRunner(FakeProcessRunnerexists inBuildvana.Core.Testing) fordotnetinvocations,IFileBasedAppRunnerfor hooks, and a testServerAdapter(the class is already abstract with a factory) whose release object recordsUpdateRepository/AddPostReleaseCommit/AddAsset/PushUpdates/PublishAsynccalls in order.none|stable|all, empty-section substitute); hook-modified files joining the post-release commit; version-spec change application; tag-collision failure.ServerAdaptermust not deepen the current adapter shape: the platform/git-host split is planned, so the fake should be designed against the seams that split will keep.Usage examples
Not user-facing; example of the kind of test this enables:
Risks
The harness may reveal that some services need construction seams (e.g.
BuildPipeline); prefer constructor-level composition over new interfaces. Test-only change; no changelog entry unless behavior fixes fall out.Additional information
Follow-up to #320, which deliberately stopped at extraction; the residue this issue covers is the part extraction cannot reach.