Skip to content

Convert remaining Fallout.Cli commands to IFalloutCommand dispatch (#392)#476

Merged
ChrisonSimtian merged 11 commits into
Fallout-build:mainfrom
ChrisonSimtian:cli-command-dispatch
Jul 18, 2026
Merged

Convert remaining Fallout.Cli commands to IFalloutCommand dispatch (#392)#476
ChrisonSimtian merged 11 commits into
Fallout-build:mainfrom
ChrisonSimtian:cli-command-dispatch

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator

Second step of the Fallout.Cli command-dispatch migration (#392). Builds on the merged foundation (#448); supersedes fork-only PRs #17#26, which were collapsed into one and re-authored against the current (async/internal) contract.

Converts the remaining legacy Program.X handlers into real IFalloutCommand types and reduces Program to a thin entry point.

What

  • complete, get-configuration, add-package, update, secrets, cake-convert, cake-clean, setup, and the navigation cluster → real command types (ExecuteAsync, DI-injected services)
  • New injectable services: ConfigurationReader, PackageManager, BuildScaffolder, CakeConverter, CliConventions
  • Deletes the DelegateCommand shims + every Program.X.cs partial
  • Specs re-homed to Fallout.Cli.Specs (async); existing specs repointed to the new service homes

Not breaking / no regressions

Derived from main's current handlers, so these are preserved: .slnx setup support, net10.0 target, the _FALLOUT_VERSION_ template token, and the nuke→fallout rebrand. Fallout.Cli.Specs 46/46 green; runtime dispatch verified (all 15 commands resolve via DI).

Notes

  • Not per-command commits: the shared Program registration + config services couple the commands (CakeConvert depends on SetupCommand), so it lands as 4 logical commits.
  • Sync commands wrap in Task.FromResult(...) (as the existing DelegateCommand did); only genuinely async work is truly async.

🤖 Generated with Claude Code

@ChrisonSimtian ChrisonSimtian added target/vCurrent Targets the current version enhancement New feature or request labels Jul 11, 2026
Comment thread tests/Fallout.Cli.Specs/Commands/CakeCleanCommandSpecs.cs Outdated
Comment thread src/Fallout.Cli/Commands/AddPackageCommand.cs Outdated
@ChrisonSimtian
ChrisonSimtian marked this pull request as ready for review July 15, 2026 09:21
@ChrisonSimtian
ChrisonSimtian requested a review from a team as a code owner July 15, 2026 09:21

@ITaluone ITaluone left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Comment thread src/Fallout.Cli/Commands/UpdateCommand.cs Outdated
@ITaluone

ITaluone commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Found one little quirck :D

ChrisonSimtian and others added 11 commits July 19, 2026 00:02
Extract Program.Trigger into a real IFalloutCommand (async ExecuteAsync per the merged
foundation contract), register the type directly, and drop the DelegateCommand shim + the
Program.Trigger.cs partial. Test re-homed to Fallout.Cli.Specs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the shared logic the converted commands depend on into injectable services:
ConfigurationReader (build-script config parsing), PackageManager (package add/replace),
BuildScaffolder (build scripts/solution wiring, incl. the .slnx writer), CakeConverter
(Cake script conversion), and CliConventions/ToolBanner (banner + script-name helpers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fallout-build#392)

Convert complete, get-configuration, add-package, update, secrets, cake-convert, cake-clean,
setup, and the navigation cluster into real IFalloutCommand types (async ExecuteAsync, DI-injected
services), register them directly, and delete the DelegateCommand shims + every Program.X.cs
partial. Program is now a thin entry point (DI wiring + root resolution). Commands and new CLI
interfaces are internal, matching the merged foundation. Derived from main's current handlers, so
the .slnx setup support, net10.0 target, and nuke->fallout rebrand are preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add async specs for the converted commands (Fallout.Cli.Specs/Commands, *Specs naming) plus a
FakeConsolePrompts double and ConfigurationReader specs, and repoint the existing CakeConversion /
UpdateSolutionFileContent specs at their new service homes (CakeConverter, PackageManager,
BuildScaffolder).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AddPackage, CakeConvert and Setup did real async work (NuGet version
resolution, nested command invocation) but blocked on it via
.GetAwaiter().GetResult() inside a synchronous Execute wrapped in
Task.FromResult. Fold the private Execute into an async ExecuteAsync
and await the work directly, removing the sync-over-async anti-pattern.

Purely-sync commands keep Task.FromResult(Execute(...)) — they have no
async work to await.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The new command specs used Method_State_Result names; the repo
convention (docs/agents/conventions.md, AV1600) is short present-tense
descriptions of observable behavior. Rename all command spec methods to
match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The last sync-over-async in the command layer sat in ProjectUpdater,
reached from UpdateCommand via the synchronous ConfirmExecution(Action)
prompt boundary. ConfirmExecution is a hand-rolled helper (not a Spectre
primitive), so add a Func<Task> overload alongside the Action one and
flow async through:

- IConsolePrompts.ConfirmExecutionAsync + SpectreConsolePrompts impl
- ProjectUpdater.Update -> async UpdateAsync (out param becomes a return)
- UpdateCommand.UpdateBuildProject -> UpdateBuildProjectAsync, folded
  into a genuine async ExecuteAsync

The genuinely-sync update steps (build scripts, config file, global.json)
stay on the sync ConfirmExecution overload. No .GetAwaiter().GetResult()
remains in the command layer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The migrated commands are all `internal sealed`, but three types were
still `public` with no consumer outside the assembly and no PublicAPI
tracking: RunCommand (the lone public command), ProjectUpdater, and
Program (the tool entry point). None are part of a public surface —
there is no public command SDK yet (that's milestone #7).

Make them internal to match the rest of the command set. Fallout.Cli.Specs
already has InternalsVisibleTo, so the specs are unaffected; DI registration
works unchanged with internal types.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The build-project update logic lived in a separate static ProjectUpdater
helper, splitting the update command's behaviour across two files for no
reason. Move it into UpdateCommand as private methods so the command owns
its own logic, and delete ProjectUpdater.

Also drops the stale "Nuke" name (UpdateNukeCommonPackage ->
UpdateFalloutCommonPackage). No behaviour change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The :update command's build-project step reset TargetFramework to net8.0,
which can't restore Fallout.Common or resolve its namespaces — the framework
targets net10.0. SetupCommand already scaffolds new projects at net10.0
(TARGET_FRAMEWORK), so update now matches.

Centralizing the target-framework literal (SetupCommand + UpdateCommand share
"net10.0") is deferred to a dedicated cleanup PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The net8.0 bug slipped through because the build-project update path had no
spec. Add one: parse a project pinned to an old TargetFramework, run the
retarget, assert it lands on net10.0. Guards the literal from drifting again.

UpdateTargetFramework is now internal (Fallout.Cli.Specs already has IVT) and
Cli.Specs gets the ProjectModel MSBuild-resolver ModuleInit so a test can hold
a Microsoft.Build.Evaluation.Project local.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian
ChrisonSimtian merged commit c99b238 into Fallout-build:main Jul 18, 2026
1 check passed
@ChrisonSimtian
ChrisonSimtian deleted the cli-command-dispatch branch July 18, 2026 12:11
@dennisdoomen dennisdoomen added skip-changelog and removed enhancement New feature or request labels Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog target/vCurrent Targets the current version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants