Skip to content

feat(globaltool): add in-tool build runner (PR-A of bootstrapper deprecation)#200

Closed
ChrisonSimtian wants to merge 2 commits into
mainfrom
feat/global-tool-in-tool-runner
Closed

feat(globaltool): add in-tool build runner (PR-A of bootstrapper deprecation)#200
ChrisonSimtian wants to merge 2 commits into
mainfrom
feat/global-tool-in-tool-runner

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator

Summary

First of three PRs that deprecate the per-repo `build.cmd`/`build.sh`/`build.ps1` bootstrappers in favour of `Fallout.GlobalTool` (`fallout`) as the canonical entry point for running builds. This one is purely additive — no behaviour change for any repo with existing bootstrappers committed.

Plan & rationale: `/Users/csimon/.claude/plans/linked-frolicking-pine.md` (local). Three-PR sequence:

  • PR-A (this one) — Add in-tool build runner. `fallout ` runs `dotnet build` + `dotnet run --no-build` directly instead of spawning `./build.sh`.
  • PR-B — Switch this repo to thin shims, delete `build.cmd`, update the `[GitHubActions]` generator + workflows, update `:setup` scaffolder.
  • PR-C — Docs cleanup (already tracked under Docs CLI cleanup: replace stale nuke references with fallout across docs/ #198).

What's in this PR

New files:

  • `src/Fallout.GlobalTool/BuildProjectResolver.cs` — resolves the build project (`.csproj`) from optional `BuildProjectFile` field in `.fallout/parameters.json`, falling back to convention `build/_build.csproj`. Six unit tests cover convention default, explicit override, missing files (both cases), and empty override values.
  • `src/Fallout.GlobalTool/Program.Run.cs` — new in-tool runner. Resolves `dotnet` (PATH first; shim-provisioned `.fallout/temp/dotnet-{unix,win}` as fallback), seeds the same env vars the shim sets, then runs `dotnet build` + `dotnet run --project --no-build -- ` as subprocesses with inherited stdio (colours/progress pass through).
  • `tests/Fallout.GlobalTool.Tests/BuildProjectResolverTests.cs` — 6 new tests, all green.

Modified:

  • `src/Fallout.GlobalTool/Program.cs` — `Handle`'s no-`:` fallback now calls `Run(args, rootDirectory, BuildProjectResolver.Resolve(rootDirectory))` instead of `Build(buildScript, ...)`. The `buildScript == null` branch of the "Could not find" prompt is removed — we can run without a shim now — but the `rootDirectory == null` branch stays for empty repos.

What this PR does NOT do (so PR-B has something to do)

  • Doesn't delete `Build()` — still called from `Program.Complete.cs` as a bootstrap path for the first-time completion request. Removed in PR-B alongside the shim deletion.
  • Doesn't touch the shim scripts (`build.sh`/`build.ps1`/`build.cmd`) — they continue to work directly via their own `dotnet build` + `dotnet run --project` invocations, independent of the global tool.
  • Doesn't touch the `[GitHubActions]` generator — it still emits `run: ./{BuildCmdPath} {targets}`, which still works because the shims are still in place. The generator and the four `.github/workflows/*.yml` files get the three-step `setup-dotnet` + `tool restore` + `dotnet fallout` shape in PR-B.
  • Doesn't add `BuildProjectFile` to `build.schema.json` — the schema is regenerated by `HandleShellCompletionAttribute` on every build run, so manual edits don't stick. The schema-generation update belongs to PR-B. The resolver works without schema support because `parameters.json` accepts arbitrary fields (JSON Schema default allows additional properties).

Backwards compatibility

Scenario Behaviour
Existing repo, old fat bootstrapper, run `./build.sh Compile` Unchanged — bootstrapper does its own `dotnet build` + `dotnet run --project`, doesn't touch the global tool.
Existing repo, old fat bootstrapper, run `fallout Compile` Now uses the new in-tool runner. Same end result (`dotnet build` + `dotnet run --no-build`), one fewer subprocess hop. The shim's env-var exports are bypassed; the new runner sets them itself to compensate.
Existing repo, no `_build.csproj` (somehow) Resolver throws with a helpful message pointing at `fallout :setup` or `BuildProjectFile` in `parameters.json`.
Empty directory, no `.fallout/` Prompt for `:setup` as before.

Verification

  • `dotnet build src/Fallout.GlobalTool/Fallout.GlobalTool.csproj` — green (0 errors; only pre-existing warnings unrelated to this PR).
  • `dotnet test tests/Fallout.GlobalTool.Tests/` — 17/17 passed (11 existing + 6 new).
  • Dogfood: `dotnet run --project src/Fallout.GlobalTool -- --help` — exercises full new path; outputs build help identical to `./build.sh --help`.
  • CI: existing workflows still call `./build.cmd`, which still works because the shims are unchanged. So this PR's CI signal verifies the legacy path stays intact; the new path is verified by the unit tests + dogfooding above.

Test plan

  • CI green on `ubuntu-latest` (the only PR gate).
  • `Fallout.GlobalTool.Tests` green on all three release runners post-merge (`ubuntu-latest`, `macos-latest`, `windows-latest`).

Refs

ChrisonSimtian and others added 2 commits May 26, 2026 22:40
…ecation)

First of three PRs that deprecate the per-repo bootstrappers in favour of
`Fallout.GlobalTool` as the entry point for running builds.

Today the global tool's no-`:` fallback in Program.Handle spawned
`bash ./build.sh` (or `powershell ./build.ps1`), letting the shim do
`dotnet build` + `dotnet run --project --no-build -- $@`. This PR moves
that work into the tool itself.

New files:

- BuildProjectResolver.cs — resolves the build project (.csproj) from
  the optional `BuildProjectFile` field in `.fallout/parameters.json`,
  falling back to the convention `build/_build.csproj`. The schema
  itself is regenerated by HandleShellCompletionAttribute on every
  build run; teaching that generator about the new field belongs in
  PR-B. The resolver works without schema support because
  parameters.json accepts arbitrary fields.

- Program.Run.cs — new in-tool runner. Resolves dotnet (PATH first,
  shim-provisioned .fallout/temp/dotnet-{unix,win} as fallback), seeds
  the same env vars the shim sets (DOTNET_CLI_TELEMETRY_OPTOUT,
  DOTNET_NOLOGO, DOTNET_ROLL_FORWARD, FALLOUT_TELEMETRY_OPTOUT, plus
  the existing FALLOUT_GLOBAL_TOOL_* markers), then runs the same two
  subprocesses the shim runs — `dotnet build` then
  `dotnet run --project --no-build -- <args>` — with inherited stdio so
  colours and progress pass through. Argument forwarding uses
  ProcessStartInfo.ArgumentList so cross-platform quoting is handled
  by the framework.

Program.cs change:

- Handle's no-`:` fallback now calls `Run(args, rootDirectory,
  BuildProjectResolver.Resolve(rootDirectory))` instead of
  `Build(buildScript, ...)`. The `buildScript == null` branch of the
  "Could not find" prompt is removed — we can run without a shim now —
  but the `rootDirectory == null` branch stays for empty repos.

What this PR does NOT do:

- Delete `Build()` — still called from Program.Complete.cs as a
  bootstrap path for the first-time completion request. Removed in
  PR-B alongside the bootstrapper deletion.
- Touch the shim scripts (`build.sh`/`build.ps1`/`build.cmd`) — they
  continue to work directly via their own `dotnet build` +
  `dotnet run --project` invocations, independent of the global tool.
- Touch the `[GitHubActions]` generator or CI workflows — they still
  call `./build.cmd Test Pack`, which still works. The generator and
  workflow shape change in PR-B.

Backwards compatibility: existing repos with fat bootstrappers are
unaffected — `./build.sh Compile` runs unchanged. The only behavioural
delta is that `fallout Compile` no longer hops through `bash ./build.sh`
before running `dotnet build` + `dotnet run`; it does that directly.
Same end result, one fewer subprocess.

Tests: BuildProjectResolverTests covers convention default, explicit
override, missing files (both convention and configured), and empty
override values — 6 new tests, all green alongside the existing 11
in Fallout.GlobalTool.Tests.

Dogfooded locally via `dotnet run --project src/Fallout.GlobalTool --
--help`, which exercises the full new path: tool → Resolver →
dotnet build → dotnet run --no-build -- --help. Output matches
`./build.sh --help`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ChrisonSimtian

Copy link
Copy Markdown
Collaborator Author

Closing — re-opening under a fresh branch feat/globaltool-runner since GitHub Actions wouldn't trigger workflows on this branch despite multiple pushes and a close/reopen cycle. Same code, just a different branch name to nudge GH into picking it up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant