Skip to content

Fix dotnet tool run generation - #4246

Open
thomhurst wants to merge 4 commits into
mainfrom
fix/dotnet-tool-run-generation
Open

Fix dotnet tool run generation#4246
thomhurst wants to merge 4 commits into
mainfrom
fix/dotnet-tool-run-generation

Conversation

@thomhurst

@thomhurst thomhurst commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • preserve required and variadic operand metadata from authoritative .NET usage synopses
  • regenerate the .NET SDK 10.0.400 command surface, including strongly typed dotnet tool run
  • strip generation-directory defaults from generated XML documentation
  • add parser and rendered-command regressions

Validation

  • OptionsGenerator tests: 1230 passed
  • DotNet tests: 36 passed, 2 known skips
  • DotNet Release solution build: 0 warnings, 0 errors
  • generated-output path audit: clean

Closes #4245

Summary by CodeRabbit

  • Documentation

    • Added documentation for the ModularPipelines.DotNet package, including installation, usage, supported commands, and configuration options.
  • Bug Fixes

    • Improved generated CLI documentation by removing environment-specific current-directory defaults.
    • Corrected .NET CLI positional argument metadata and option terminator handling, including repeated terminators for separate argument groups.
  • Tests

    • Added coverage for dotnet tool run, dotnet test, command generation, documentation cleanup, and CLI argument metadata.

@greptile-apps

greptile-apps Bot commented Aug 28, 2026

Copy link
Copy Markdown

Too many files changed for review (129 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 98f11de1-eeff-492a-9fde-0f315ef9a97b

📥 Commits

Reviewing files that changed from the base of the PR and between 5e1404d and 3653bb9.

⛔ Files ignored due to path filters (2)
  • src/ModularPipelines.DotNet/Options/DotNetTestOptions.Generated.cs is excluded by !**/*.generated.*
  • src/ModularPipelines.DotNet/Options/DotNetToolRunOptions.Generated.cs is excluded by !**/*.generated.*
📒 Files selected for processing (12)
  • src/ModularPipelines.SourceGenerator/CommandOptionsGenerator.cs
  • src/ModularPipelines/Attributes/CliArgumentAttribute.cs
  • src/ModularPipelines/Helpers/Internal/CommandArgumentBuilder.cs
  • test/ModularPipelines.DotNet.UnitTests/DotNetCommandParserTests.cs
  • test/ModularPipelines.UnitTests/Attributes/GeneratedRuntimeMetadataTests.cs
  • test/ModularPipelines.UnitTests/Context/CommandLineBuilderTests.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator.Tests/Generators/GeneratorHardeningTests.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator.Tests/Scrapers/DotNetCliScraperTests.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/GeneratedApiCompatibilityPreserver.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/OptionsClassGenerator.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Models/CliPositionalArgument.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Scrapers/Cli/DotNetCliScraper.cs

Included review availability: Your plan provides up to 4 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds repeated option terminator support, improves DotNet CLI positional metadata and compatibility preservation, removes current-directory defaults from generated comments, adds validation tests, and documents the ModularPipelines.DotNet package.

Changes

DotNet CLI generation and documentation

Layer / File(s) Summary
Repeated option terminator contract and rendering
src/ModularPipelines/Attributes/CliArgumentAttribute.cs, src/ModularPipelines/Helpers/Internal/CommandArgumentBuilder.cs, src/ModularPipelines.SourceGenerator/CommandOptionsGenerator.cs, tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Models/CliPositionalArgument.cs, tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/OptionsClassGenerator.cs
CLI argument metadata now supports repeated -- terminators. Command rendering emits a later requested terminator.
DotNet scraping and compatibility preservation
tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Scrapers/Cli/DotNetCliScraper.cs, tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/GeneratedApiCompatibilityPreserver.cs
DotNet tool and test arguments receive passthrough and terminator metadata. Usage synopsis data now preserves argument types, requiredness, and variadic status. Generated API compatibility logic carries the new metadata.
Metadata and command validation
tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator.Tests/Scrapers/DotNetCliScraperTests.cs, tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator.Tests/Generators/GeneratorHardeningTests.cs, test/ModularPipelines.UnitTests/Attributes/GeneratedRuntimeMetadataTests.cs, test/ModularPipelines.UnitTests/Context/CommandLineBuilderTests.cs, test/ModularPipelines.DotNet.UnitTests/DotNetCommandParserTests.cs
Tests validate DotNet positional metadata, repeated terminators, generated runtime metadata, rendering-phase migration, and tool command generation.
Generated comment normalization
tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/GeneratorUtils.cs
Generated XML comments remove current-directory default annotations and reuse path-separator variant handling.
DotNet package reference
docs/docs/mp-packages/cli/dotnet.md
The generated page documents package installation, service resolution, command execution, and supported DotNet CLI commands.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to 3653b

The PR corrects generated .NET command metadata and argument rendering, with regression tests, a clean release build, and generated-output validation reported successful. No actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant DotNetOptions
  participant CommandArgumentBuilder
  participant DotNetCLI
  DotNetOptions->>CommandArgumentBuilder: provide platform and extension arguments
  CommandArgumentBuilder->>DotNetCLI: emit first -- and platform options
  CommandArgumentBuilder->>DotNetCLI: emit repeated -- and extension options
  DotNetCLI-->>CommandArgumentBuilder: execute rendered command
Loading

Poem

A rabbit marks each -- with care,

Tool arguments travel through the air.
Paths lose their local trace,
Metadata stays in place.
DotNet commands fill the guide,
Tests check every stride.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 35 functions across 13 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The parser and command-builder changes address the required tool-run argument handling. However, the generated DotNetToolRunOptions.Generated.cs file is excluded from review, so the final generated To… Provide the generated DotNetToolRunOptions.Generated.cs file or equivalent generated-output evidence confirming that DotNetToolOptions.Tool is emitted into the command as dotnet tool run . Confirm empty or missing tool han…
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: fixing .NET tool run command generation.
Out of Scope Changes check ✅ Passed The changes support the stated objectives. Documentation, generator hardening, metadata preservation, option-terminator handling, and regression tests are related to the .NET command-generation fix. N…
Full details: Linked Issues check

Explanation

The parser and command-builder changes address the required tool-run argument handling. However, the generated DotNetToolRunOptions.Generated.cs file is excluded from review, so the final generated Tool operand and execution path cannot be fully verified.

Resolution

Provide the generated DotNetToolRunOptions.Generated.cs file or equivalent generated-output evidence confirming that DotNetToolOptions.Tool is emitted into the command as dotnet tool run <tool> <arguments>. Confirm empty or missing tool handling if that behavior is required.

Full details: Out of Scope Changes check

Explanation

The changes support the stated objectives. Documentation, generator hardening, metadata preservation, option-terminator handling, and regression tests are related to the .NET command-generation fix. No clearly unrelated code changes are shown.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dotnet-tool-run-generation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3eaaf8aba7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ModularPipelines.DotNet/Options/DotNetToolRunOptions.Generated.cs Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review of #4246 — Fix dotnet tool run generation

Verified the diff directly (121 auto-regenerated files + 5 hand-written source/test/generator files) against a fresh clone of the PR head. Summary of what changed:

  • DotNetCliScraper.ApplyUsageCardinality now merges CSharpType, IsRequired, and IsVariadic from the usage-synopsis parser into any name-matched positional argument, instead of only merging IsVariadic/CSharpType when the usage-derived argument was variadic. This is what fixes dotnet tool run's CommandName losing its IsRequired = true (previously the merge only ever looked at variadic args, so a required-but-non-variadic operand's required-ness from the usage line was silently dropped).
  • New GeneratorUtils.RemoveCurrentDirectoryDefault strips [default: <cwd>] suffixes (in both slash orientations) from generated doc comments so they don't bake in the machine's build-time working directory.
  • The other 121 files are the expected regenerated *.Generated.cs output; spot-checked several against sibling files and found nothing that looks hand-edited or coincidentally altered — no other command's Required/CSharpType metadata changed in this regen.

Finding: ApplyUsageCardinality's broadened trust isn't scoped, and only tool run is regression-tested

ParsePositionalArguments (help-text Arguments: section parser) hardcodes IsRequired = false for every operand it emits — it has no way to know an operand is actually required. Previously ApplyUsageCardinality never trusted the usage-line parser's IsRequired for non-variadic matches either, so this hardcoded false was effectively unconditional for non-variadic operands. The fix now trusts the usage-line parser's IsRequired/CSharpType for any name-matched operand, for every dotnet subcommand that has both a help-text Arguments: section and a usage synopsis (i.e. most of them, not just tool run — see the call site at DotNetCliScraper.cs around the ApplyUsageCardinality(positionalArgs, usagePositionalArgs) call, which isn't conditioned on the command).

That's the right fix for tool run, and I confirmed empirically that no other command's generated Required/CSharpType flipped in this particular regen (the two parsers happen to agree today). But nothing in the code scopes the broadened trust to the case it was written for, and only tool run's CommandName/ToolArguments got new assertions in DotNetCliScraperTests.cs. If a future SDK version's usage synopsis and help text ever disagree on optionality for some other command (say dotnet build's PROJECT | SOLUTION | FILE operand), this merge would silently flip that command's generated property from optional to required on the next scrape/regen, which is a breaking API change for consumers with no test catching it.

Suggested improvement: add a regression test asserting a non-tool-run command (e.g. dotnet build's ProjectSolution) keeps its expected IsRequired/CSharpType through ApplyUsageCardinality, so future scrapes that hit a genuine parser disagreement fail loudly in CI instead of silently reshaping a public options class. That turns "we verified this by hand once" into a durable guardrail, which matters more here than in typical code because this generator's output is a public API surface.

Minor: duplicated path-variant logic in GeneratorUtils.cs

NormalizeRunnerHomePaths and the new RemoveCurrentDirectoryDefault both independently build an identical forward/backslash variants array (.Replace('\\','/') / .Replace('/','\\') + .Distinct(StringComparer.OrdinalIgnoreCase)) from a trimmed path, and the two already use different trimming calls (.TrimEnd('/', '\\') vs Path.TrimEndingDirectorySeparator) for the same intent. Factoring this into a shared GetPathSeparatorVariants(string path) helper would remove the duplication and the risk of the two implementations drifting further apart on edge cases (UNC paths, trailing dots, etc.).

Everything else — the generated-file regen, the tool run fix itself, and the new tests for it — looks correct and consistent with the project's documented generator workflow.

Preserve authoritative usage cardinality when rich .NET help descriptions are merged. Strip generation-directory defaults from XML documentation.

Closes #4245
@thomhurst
thomhurst force-pushed the fix/dotnet-tool-run-generation branch from 3eaaf8a to 5e1404d Compare August 28, 2026 11:20
@thomhurst

Copy link
Copy Markdown
Owner Author

Addressed review findings in 5e1404d:

  • Added a non-tool run regression fixture proving dotnet build keeps its optional, non-variadic ProjectSolution metadata when usage cardinality is merged.
  • Consolidated slash/backslash path variants behind GetPathSeparatorVariants.
  • Also fixed the inline forwarded-argument finding by generating PrependOptionTerminator = true for ToolArguments and covering a dash-prefixed value.
  • Rebased onto current main.

Validation: 1,231 generator tests passed; 36 DotNet tests passed with 2 pre-disabled; deterministic second generation produced no diff; touched-file format verification and docs build passed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e1404d8dd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ModularPipelines.DotNet/Options/DotNetToolRunOptions.Generated.cs Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review of #4246 — Fix dotnet tool run generation

Re-reviewed at head 5e1404d8dd2905f12df9a181c4210494f31476fe. The two findings from the prior review (scoping/regression-test gap in ApplyUsageCardinality, and duplicated path-variant logic in GeneratorUtils) have both been addressed:

  • Build_Preserves_Optional_Project_Operand_Metadata now locks in that dotnet build's ProjectSolution stays optional/non-variadic through ApplyUsageCardinality, guarding against the broadened merge silently flipping some other command's operand to required on a future regen.
  • NormalizeRunnerHomePaths and RemoveCurrentDirectoryDefault now share GetPathSeparatorVariants, removing the duplicated slash/backslash variant logic.

Finding: dotnet tool run's ToolArguments uses the wrong Phase, so combining it with any Normal-phase option throws at runtime

ApplyPositionalArgumentFixes (tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Scrapers/Cli/DotNetCliScraper.cs, the "tool run" branch) only sets PrependOptionTerminator = true on ToolArguments; it leaves Phase at the default CommandLinePhase.EarlyOperand inherited from ParsePositionalArguments. The generated DotNetToolRunOptions.Generated.cs reflects this:

[CliArgument(1, Phase = CommandLinePhase.EarlyOperand, PrependOptionTerminator = true)]
public IEnumerable<string>? ToolArguments { get; set; }

CommandArgumentBuilder.GetRenderOrder renders EarlyOperand (order 0) before Normal (order 1, the phase every plain [CliFlag]/[CliOption] defaults to — including AllowRollForward here). ValidateOptionTerminatorOrdering in src/ModularPipelines/Helpers/Internal/CommandArgumentBuilder.cs explicitly guards against an operand emitting its -- terminator before a later-phase option renders, and throws InvalidOperationException when it detects that. Concretely:

new DotNetToolRunOptions("csharpier")
{
    AllowRollForward = true,
    ToolArguments = ["check", "--help"]
}

throws "CLI argument 'ToolArguments' emits an end-of-options marker before a later flag or option. Move the argument to a later phase or remove its option-terminator setting." at command-build time, instead of producing the valid dotnet tool run csharpier --allow-roll-forward -- check --help. This isn't a hypothetical edge case — --allow-roll-forward is DotNetToolRunOptions's only other property, so it's the first thing a consumer would reach for alongside forwarded tool arguments, and it fails every time.

The one test added for this command, Tool_Run_Prepends_Option_Terminator, only exercises ToolArguments alone, so this doesn't surface in CI. The scraper test Preserves_Current_Option_And_Operand_Arity also only asserts toolArguments.PrependOptionTerminator is true, never checking Phase.

Why this is the right fix, not just a smaller one: the codebase already has an established, tested pattern for pass-through operands that need an option terminator — BrewCliScraper's RequiredArgument/VariadicArgument helpers and the Go/Gradle/Jq scrapers all pair PrependOptionTerminator/variadic pass-through args with Phase = CommandLinePhase.Passthrough (order 3, i.e. after Normal-phase options), specifically so real options can still render before the -- marker. The "tool run" fix should follow that same pairing instead of leaving Phase at its EarlyOperand default:

if (commandKey.Equals("tool run", StringComparison.OrdinalIgnoreCase))
{
    return args.Select(argument =>
        argument.PropertyName.Equals("ToolArguments", StringComparison.OrdinalIgnoreCase)
            ? argument with { Phase = CommandLinePhase.Passthrough, PrependOptionTerminator = true }
            : argument).ToList();
}

More durably: since ValidateOptionTerminatorOrdering already encodes the invariant "an option-terminating argument must render in a phase at or after every option it could conflict with," it would be worth adding a GeneratorHardeningTests (or CliArgumentAttribute-level analyzer) check that flags PrependOptionTerminator = true combined with a Phase earlier than Passthrough/Terminal at generation time — this exact mistake (right terminator flag, wrong phase) is easy to repeat in the next scraper fix and currently fails silently until someone hits the runtime exception.

I'd also suggest extending Tool_Run_Prepends_Option_Terminator (or adding a sibling test) to cover AllowRollForward + ToolArguments together, asserting dotnet tool run csharpier --allow-roll-forward -- check --help, so this is caught the moment the Phase fix lands.

Everything else — the regenerated 121 files, the GeneratorUtils doc-cleanup fix, and the ApplyUsageCardinality change itself — looks correct and matches the stated intent.

Render dotnet tool run options before the option terminator and forwarded tool arguments. Allow explicitly opted-in phase migrations to adopt their phase-scoped position.\n\nRefs #4245

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c4b6246b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ModularPipelines.DotNet/Options/DotNetTestOptions.Generated.cs Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review of #4246 — Fix dotnet tool run generation

Re-reviewed at head 3c4b6246b98121959c1d6b571fb55cb9d30a467c. This commit addresses the one remaining finding from the prior review: dotnet tool run's ToolArguments was rendering in CommandLinePhase.EarlyOperand (order 0) while carrying PrependOptionTerminator = true, so any Normal-phase option (AllowRollForward, order 1) rendered after the -- terminator and tripped ValidateOptionTerminatorOrdering's runtime guard.

Verified the fix directly:

  • DotNetCliScraper.cs's "tool run" branch now sets Phase = CommandLinePhase.Passthrough (order 3, after Normal) alongside PrependOptionTerminator = true and AllowRenderingPhaseMigrationFromBaseline = true — matching the pattern already used elsewhere (Brew/Go/Gradle/Jq scrapers) for pass-through operands paired with an option terminator.
  • The compatibility guard change in GeneratedApiCompatibilityPreserver.cs (AllowsRenderingPhaseMigration) drops the ArgumentPosition equality requirement only when the specific property has AllowRenderingPhaseMigrationFromBaseline set — it's scoped per-property via command.PositionalArguments.Any(...), so this doesn't loosen the guard for any other generated property.
  • DotNetToolRunOptions.Generated.cs now emits [CliArgument(0, Phase = CommandLinePhase.Passthrough, PrependOptionTerminator = true)] for ToolArguments, as expected.
  • The new test in DotNetCommandParserTests.cs reproduces exactly the scenario I flagged (AllowRollForward = true combined with ToolArguments) and asserts the correct rendered command dotnet tool run csharpier --allow-roll-forward -- check --help. I built and ran it locally against this head (ModularPipelines.DotNet.UnitTests, Tool_Run_Prepends_Option_Terminator) — passes.
  • I also ran the full GeneratorHardeningTests/DotNetCliScraperTests suites locally (183 tests) — all pass, including the updated hardening test that now separately asserts Phase and PositionIndex rather than conflating them.

Both findings from the earlier rounds (the unscoped ApplyUsageCardinality trust/regression-test gap, and this Phase ordering bug) are now resolved with matching regression coverage. Nothing further to flag.

Preserve distinct platform and extension boundaries.
@thomhurst
thomhurst deployed to Pull Requests August 28, 2026 12:52 — with GitHub Actions Active

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review of #4246 — Fix dotnet tool run generation

Re-reviewed at head 3653bb9b1c18d3bc94d86e16716598776a3cdf96. This is a follow-up commit ("fix(dotnet): delimit test argument groups") on top of the previously-cleared head (3c4b6246b9); the earlier findings (unscoped ApplyUsageCardinality, and the tool run Phase/terminator-ordering bug) remain fixed and unaffected by this change.

What changed: dotnet test's PlatformOptions (position 0) and ExtensionOptions (position 1) are both Passthrough-phase arguments with PrependOptionTerminator = true. Previously, CommandArgumentBuilder.AddArguments only ever emitted one -- per render (!emittedOptionTerminator guard), so once PlatformOptions emitted its terminator, ExtensionOptions's own request was silently swallowed — collapsing dotnet test -- <platform> -- <extension> into a single --, merging two argument groups the CLI treats as distinct. This commit adds a new RepeatOptionTerminator flag on CliArgumentAttribute/CliPositionalArgument that, when set, forces a fresh -- even if one was already emitted, and applies it to ExtensionOptions via the same ApplyPositionalArgumentFixes special-case pattern already used for tool run.

Verified directly:

  • Traced AddArguments: for PlatformOptions then ExtensionOptions in the same phase, the second argument now re-emits -- because RepeatOptionTerminator is true, while optionTerminatorIndex ??= args.Count correctly keeps pointing at the first terminator (used downstream by CommandLineBuilder.InsertManualOptions to splice manual/global options before the first --, which is still the right insertion point — options can never legally appear after any terminator per ValidateOptionTerminatorOrdering).
  • GeneratedApiCompatibilityPreserver's equality/migration checks (AllowsRenderingPhaseMigration, IsCompatible) were extended to include RepeatOptionTerminator symmetrically with the existing PrependOptionTerminator handling, so compatibility auditing stays accurate.
  • The new/updated tests reproduce exactly this scenario and I ran them locally against this head:
    • ModularPipelines.UnitTests: CommandLineBuilderTests.Build_Repeats_Explicit_Option_Terminator_For_Later_Argument_Group (1 passed), GeneratedRuntimeMetadataTests.* (32 passed)
    • ModularPipelines.DotNet.UnitTests: DotNetCommandParserTests.* (5 passed), including the new Test_Preserves_Platform_And_Extension_Option_Terminators asserting dotnet test --no-build -- --filter Category=Unit -- --report-trx
    • ModularPipelines.OptionsGenerator.Tests: DotNetCliScraperTests.Test_Preserves_Both_Option_Terminators (1 passed)
  • DotNetTestOptions.Generated.cs's new attribute arguments (RepeatOptionTerminator = true on ExtensionOptions) match what OptionsClassGenerator/CommandOptionsGenerator would emit from the scraper's ApplyPositionalArgumentFixes("test", ...) special case — consistent field ordering through PropertyMetadata and CliPositionalArgument.

No regressions or gaps found. Nothing further to flag.

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.

Dotnet Tool Execute Ignores the Tool

1 participant