Skip to content

Stop building and testing twice in bv release - #395

Merged
rdeago merged 2 commits into
Tenacom:mainfrom
rdeago:release-single-pipeline-run
Sep 11, 2026
Merged

rdeago merged 2 commits into
Tenacom:mainfrom
rdeago:release-single-pipeline-run

Conversation

@rdeago

@rdeago rdeago commented Sep 11, 2026

Copy link
Copy Markdown
Member

Checklist of related issues / discussions

  • Closes #
  • Part of #
  • Related discussion(s): #

Proposed changes

bv release ran the build pipeline twice: from clean through test before the release commit, and from restore through pack after it.
The second run built and tested the tree of the release commit, which is the tree the release tags and publishes.
The first run tested a tree that differs from it only by VERSION, the public API files, and CHANGELOG.md.
In the release of 2.1.727-preview, the first run took 1 min 41 s of the command's 3 min 17 s.

The two runs date from the Cake.Frosting port, where ReleaseTask depended on TestTask and kept a pipeline run of its own.

bv release runs the pipeline once, from clean through pack, after the release commit.
The preliminary checks, the draft release, the release commit, and the tag check all come before any build, so a release that cannot succeed is refused before there is anything to roll back.
A build or test failure rolls back the release commit and the draft release, as a pack, push, or publish failure already did.

The draft release is created "so if the token has no permissions we can bail out early".
That check used to come after a full pipeline run.
With one run, it comes before any build.

The tests, the page docs/tool-commands/release.md, and the changelog follow the new order.

Additional changes

  • Release_WithEmptySectionAndNoSubstitute_Fails asserts that no pipeline step ran, where it asserted only that pack did not.
    Its comment claimed the stronger fact already, and the fact holds once the pipeline runs after the changelog check.

Types of changes

This pull request introduces the following types of changes:

  • Bug fix
  • New feature
  • Test addition / update (no changes to non-test code)
  • Refactor (no changes in public API syntax or semantics)
  • Performance improvement (no changes in public API syntax or semantics)
  • Documentation update (not including changelog)
  • Dependency addition / update
  • Changes to toolchain configuration
  • Changes to CI (workflows, bot / app configurations)
  • Changes to repository files (.gitattributes, .gitignore)
  • Other

Breaking changes

This pull request introduces breaking changes:

  • Yes
  • No

Checklist

  • For all types of changes:
  • For code changes only:
    • The project builds on my machine, via the provided build script, with zero warnings
    • I have added tests that prove my feature works / my fix is effective
    • I have added / modified XML documentation according to changes in code
    • I have checked that all the links I added or modified in XML documentation point to their intended destination
  • For documentation changes only:
    • I have checked and proofread documentation locally
    • I have checked that all the links I added or modified point to their intended destination

🤖 Generated with Claude Code

`ReleaseCommand` ran the build pipeline from Clean through Test before the
release commit, and from Restore through Pack after it. The second run built
and tested the tree of the release commit, which is the tree the release tags
and publishes. The first run tested a tree that differs from it only by
`VERSION`, the public API files, and `CHANGELOG.md`. The pair dates from the
Cake.Frosting port, where `ReleaseTask` depended on `TestTask` and kept a
pipeline run of its own. The pipeline runs once, after the release commit,
from Clean through Pack. A build or test failure then rolls back the release
commit and the draft release, like any later failure.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rdeago rdeago added the perf [issue/PR] requests / implements a performance improvement without affecting functionality. label Sep 11, 2026
@github-actions github-actions Bot added area:docs [issue/PR] affects documentation (excluding XML documentation that is part of source code). area:code [issue/PR] affects project code (excluding tests). labels Sep 11, 2026
@rdeago

rdeago commented Sep 11, 2026

Copy link
Copy Markdown
Member Author

@claude please review this PR.

@claude

claude Bot commented Sep 11, 2026

Copy link
Copy Markdown

Claude finished @rdeago's task in 5m 49s —— View job


Review

  • Read the review rules and the diff
  • Read ReleaseCommand.cs in full, around the change
  • Check the tests against the new order
  • Check docs/tool-commands/release.md and the changelog
  • Post findings

No blocking findings.

The single run still covers what the two runs covered. RunThroughAsync(BuildStep.Pack, …) resolves to RunRangeAsync(BuildStep.Clean, BuildStep.Pack, …), which iterates Clean, Restore, Build, Test, Pack. TestAsync and PackAsync pass restore: false, build: false, and Build runs ahead of both in the same range, so neither loses an input.

The move also makes one line of docs/tool-commands/release.md true that was not. Preconditions opens with "Before building anything", and item 6 is the GITHUB_OUTPUT check. GitHubServerRelease reads that variable in CreateReleaseAsync, which used to run after the verification pass.


Non-blocking

Reported once, per .claude/rules/reviewing.md.

Nothing pins the range of the run. ReleaseHarness writes Test.slnx as <Solution />, so the harness solution holds no project. CleanAsync then deletes nothing and records no ReleaseEvent. TestSolutionAsync returns at No test projects found, skipping tests. without invoking dotnet, so it records none either. Release_RunsPipelineOnce_ThenPushesAndPublishes (tests/Buildvana.Tool.Tests/ReleaseCommandTests.cs:35) would pass unchanged if ReleaseCommand.cs:229 became RunRangeAsync(BuildStep.Restore, BuildStep.Pack, …). A release would then publish without cleaning and without running the tests, and the suite would stay green.

The gap predates this PR for the test step: the removed RunThroughAsync(BuildStep.Test, …) was equally unobservable. What changes is the weight on it. The doubled restore, build pair used to be evidence of a second pass, and one enum argument now carries the whole fact. A project in the harness solution, plus a FakeProcessRunner answer of true to the -getProperty:IsTestingPlatformApplication probe, would make both steps record events. Fix this →

No test covers a pipeline failure. The PR moves build and test failures inside the rollback scope, and the description states the new outcome: a failing build rolls back the release commit and the draft release. ReleaseHarnessOptions injects a failure at publication (OnPublishing) and ReleaseHarness injects one at the hook (HookBehavior). Neither injects one in a dotnet invocation, so nothing exercises the path. ReleaseCommandFailureTests has the shape ready in Release_WhenHookFails_LeavesTheRepositoryUnchanged. Fix this →


• branch release-single-pipeline-run

@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.84%. Comparing base (7314705) to head (4436eca).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #395   +/-   ##
=======================================
  Coverage   82.83%   82.84%           
=======================================
  Files         278      278           
  Lines        8314     8313    -1     
  Branches     1618     1618           
=======================================
  Hits         6887     6887           
+ Misses       1151     1150    -1     
  Partials      276      276           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

`ReleaseHarness` records a `ReleaseEvent` per child process. `Clean` starts
none, and `Test` starts none either, because `ReleaseHarness` writes
`Test.slnx` without a project. `Release_RunsPipelineOnce_ThenPushesAndPublishes`
therefore passed whether `ReleaseCommand` ran the build pipeline from `Clean`
or from `Restore`. The four tests that assert an empty event list could not
tell a refused release from one that had cleaned. `BuildPipeline` begins a
reporter activity named after each step, so `ReleaseHarness.PipelineSteps`
reads the steps back from `CaptureReporter.ActivityTitles`.
`Release_RunsPipelineOnce_ThenPushesAndPublishes` asserts the five steps, and
the four tests assert none.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rdeago

rdeago commented Sep 11, 2026

Copy link
Copy Markdown
Member Author

Round 1.

Nothing pins the range of the run. Done in 4436eca. BuildPipeline begins a reporter activity named after each step, and the harness reporter is a CaptureReporter, so ReleaseHarness.PipelineSteps reads the steps back from its ActivityTitles. Release_RunsPipelineOnce_ThenPushesAndPublishes asserts Clean through Pack. The four tests that assert an empty event list assert an empty step list as well. A project in Test.slnx would have left Clean unobserved, since CleanAsync invokes no child process.

No test covers a pipeline failure. Left alone. ReleaseCommand runs the pipeline inside the same await using (release) block as every later step, and ServerRelease.DisposeAsync undoes the release commit whatever threw, so a pipeline failure has no rollback code of its own. Four tests exercise that rollback already:

  • before the pipeline: Release_OnExistingTag_UndoesTheReleaseCommit, Release_WithUncommittedVersionFile_Fails;
  • after it: Release_WhenHookFails_LeavesTheRepositoryUnchanged, Release_WhenPublicationFails_ResetsAndForcePushesTheBranch.

A dotnet failure injected in the harness would exercise FakeProcessRunner throwing and two methods not catching, with no product branch between them. The draft-release half is out of the harness's reach: RecordingServerRelease models publication and its undo, and the draft deletion lives in GitHubServerRelease.

@rdeago
rdeago merged commit 2134517 into Tenacom:main Sep 11, 2026
8 checks passed
@rdeago
rdeago deleted the release-single-pipeline-run branch September 11, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:code [issue/PR] affects project code (excluding tests). area:docs [issue/PR] affects documentation (excluding XML documentation that is part of source code). perf [issue/PR] requests / implements a performance improvement without affecting functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant