Propagate scaffolding failures to CLI exit codes - #3860
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The required-step failure path skips the established post-execution callback.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
This PR propagates required scaffolding failures through interactive execution and the CLI so failed operations return nonzero exit codes.
Changes:
- Returns execution results from scaffolder and runner APIs.
- Propagates built-in and external command failures.
- Adds failure diagnostics and regression coverage.
Review findings:
- Moderate (2 votes):
Scaffolder.cs:73returns beforeRunPostExecute, changing the callback contract. Defer the failure return until after the post-execution callback. - Nit (1 vote):
ScaffolderTests.cs:58codifies that regression; keeppost2unconditional and gate only step-3 events on success.
| File | Description |
|---|---|
test/dotnet-scaffolding/dotnet-scaffold.Tests/Interactive/Flow/CommandExecuteFlowStepTests.cs |
Tests interactive failure propagation. |
test/dotnet-scaffolding/dotnet-scaffold.Tests/CommandLine/ScaffoldExitCodeTests.cs |
Tests process exit codes and diagnostics. |
test/dotnet-scaffolding/dotnet-scaffold.Tests/CommandLine/ScaffolderTests.cs |
Tests step ordering and callback behavior. |
test/dotnet-scaffolding/dotnet-scaffold.Tests/CommandLine/FullHelpPrinterTests.cs |
Updates the test scaffolder contract. |
test/dotnet-scaffolding/dotnet-scaffold.Tests/Aspire/ScaffoldSteps/WrappedAddPackagesStepTests.cs |
Updates the test scaffolder contract. |
test/dotnet-scaffolding/dotnet-scaffold.Tests/Aspire/ScaffoldSteps/ValidateOptionsStepTests.cs |
Updates the test scaffolder contract. |
test/dotnet-scaffolding/dotnet-scaffold.Tests/Aspire/ScaffoldSteps/AddAspireConnectionStringStepTests.cs |
Updates the test scaffolder contract. |
test/dotnet-scaffolding/dotnet-scaffold.Tests/Aspire/ScaffoldSteps/AddAspireCodeChangeStepTests.cs |
Updates the test scaffolder contract. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/Scaffolders/Scaffolder.cs |
Returns required-step results and logs failures. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/Scaffolders/IScaffolder.cs |
Exposes Boolean execution results. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/CommandLine/CommandLineExtensions.cs |
Maps scaffold failures to exit code 1. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/Builder/ScaffoldRunnerBuilder.cs |
Adds exit-code-returning root handlers. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/Builder/ScaffoldRunner.cs |
Returns command invocation exit codes. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/Builder/ScaffoldBuilder.cs |
Supplies failure logging. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/Builder/IScaffoldRunnerBuilder.cs |
Declares result-returning handlers. |
src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/Builder/IScaffoldRunner.cs |
Declares exit-code-returning execution. |
src/dotnet-scaffolding/dotnet-scaffold/Program.cs |
Returns the runner’s process exit code. |
src/dotnet-scaffolding/dotnet-scaffold/Interactive/Flow/Steps/CommandExecuteFlowStep.cs |
Propagates interactive command failures. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
A critical issue still allows built-in failures to return exit code 0 in the normal interactive path.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Resolved since last review (1)
Return required-step failures through the command handler, runner, process entry point, and interactive flow. Preserve skipped and optional steps, report partial-change diagnostics, and add regression coverage. Fixes #3845 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71b25d6d-c063-4036-bebc-b34f1487819e
Remove duplicate runner and direct-flow cases, low-value construction and empty-step checks, and redundant logging assertions. Retain process exit-code coverage, step ordering semantics, and built-in and external interactive failure propagation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71b25d6d-c063-4036-bebc-b34f1487819e
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71b25d6d-c063-4036-bebc-b34f1487819e
Cache the command execution result and reuse it when the interactive flow invokes RunAsync after validation failure. Exercise production interactive mode with an isolated Windows console buffer and assert the fallback failure and exactly one execution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71b25d6d-c063-4036-bebc-b34f1487819e
Port the framework guard from #3836 using the existing target-framework helper. The passkey script is not available for .NET 8 or 9, so skip its step instead of failing scaffolding now that required-step failures propagate to the process exit code. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71b25d6d-c063-4036-bebc-b34f1487819e
4800813 to
25b6e26
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Critical exit-code handling and moderate passkey rerun behavior remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (1)
Resolved since last review (1)
Report unexpected interactive flow errors and return 1 instead of int.MinValue, which becomes success on Unix. Cover successful, nonzero, and exception results. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71b25d6d-c063-4036-bebc-b34f1487819e
Stop on failed package additions, distinguish matching existing static files from conflicts, propagate tool manager failures, and normalize negative interactive flow results at the common runner boundary. Add focused end-to-end and unit regressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71b25d6d-c063-4036-bebc-b34f1487819e


Summary
Fixes #3845.
Required scaffold-step failures currently stop execution but are discarded by the scaffolder, command handler, runner, and process entry point. This can leave partial changes while reporting exit code 0.
IScaffolder.ExecuteAsyncand propagate failure as exit code 1 through the CLI.ContinueOnError, and pre/post-execution callback behavior.dotnet add packagefailures instead of always returning success; package-installation steps are required, so stop before subsequent code-generation steps on failure.Compatibility and coordination
IScaffolder.ExecuteAsyncnow returnsTask<bool>andIScaffoldRunner.RunAsyncreturnsTask<int>. Custom interface implementations need to update their signatures; existing callers can still await and ignore the result. ExistingTaskroot-handler overloads remain available.The runner/process changes overlap with the still-open #3806. This PR additionally fixes the earlier loss of required-step failures and interactive result propagation; coordinate those overlapping changes when merging.
This shared fix also addresses the false-success report for missing client-project references in the Blazor Identity updates in #3836 (for #3797):
ValidateIdentityStepalready returns false, but its result was discarded. The exact combined Identity-branch repro has not been run.Missing tool-internal code-modification recipes can still cause some preparers to skip required work. That broader packaging/layout failure path is deferred to a focused follow-up; it is not the same as missing application configuration.
Validation
dotnet add packagenow propagates through a scaffolder to exit code 1; identical existing static files succeed without a write and modified files fail without being overwritten.nonInteractive: false), verify the fallback returns the actual command failure, and assert exactly one execution. A private Windows console buffer avoids unrelated headless-console errors; the original handles are restored afterward.-1andint.MinValue) normalize to 1 at the runner boundary; positive action codes continue to pass through.dotnet-scaffoldfor .NET 8, 9, 10, and 11 with no warnings or errors.razorview-emptyusing the .NET 11 tool; verified exit code 0 and the generatedViews/ExitCodeSuccess.cshtmlfile, then removed the temporary project.No tenant-backed provisioning was performed. Failure reporting does not introduce rollback of earlier changes.