Skip to content

[Deps] Upgrade System.CommandLine to 2.0 GA - #50884

Merged
Clint Rutkas (crutkas) merged 5 commits into
mainfrom
crutkas-system-commandline-2-0-ga-dep-3
Oct 13, 2026
Merged

Clint Rutkas (crutkas) merged 5 commits into
mainfrom
crutkas-system-commandline-2-0-ga-dep-3

Conversation

@crutkas

@crutkas Clint Rutkas (crutkas) commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Summary of the Pull Request

Upgrades System.CommandLine from 2.0.0-beta4.22272.1 to 2.0.1 and migrates PowerToys.DSC, Awake, FancyZonesCLI, Image Resizer, and PowerDisplay.Cli (and their tests) to the 2.0 API. Option names, aliases, defaults, and exit codes are unchanged.

PR Checklist

  • Closes: N/A
  • Communication: I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected
  • Tests: Added/updated and all pass
  • Localization: All end-user-facing strings can be localized (no new strings)
  • Dev docs: Added/updated (doc/devdocs/cli-conventions.md)
  • New binaries: Added on the required places (none)
  • Documentation updated: N/A

Detailed Description of the Pull Request / Additional comments

  • 2.0.1 is pinned because it's the newest 2.0.x available in the PowerToys NuGet feed.
  • The Image Resizer and PowerDisplay CLIs remove the --help/--version options that 2.0 adds to every RootCommand, so -h keeps its existing meaning.
  • CA1010 is suppressed where public types derive from Command, which implements only non-generic IEnumerable.
  • User-visible changes:
    • Help lists -?, -h, --help before --version, and Awake no longer prints [default: False].
    • The Image Resizer CLI rejects invalid --unit/--fit values with exit code 1 instead of ignoring them.
    • FancyZonesCLI reports one error instead of two for set-layout <layout> --monitor 0 --all.

Validation Steps Performed

  • CI: PowerToys CI build 390259: x64/arm64 builds, unit tests, and UI tests.
  • Anonymous restore on a clean NuGet cache downloads System.CommandLine 2.0.1 from the feed.
  • Built all seven System.CommandLine consumers locally; DSC, Awake, Image Resizer, PowerDisplay.Cli, and CmdPal Shell unit tests pass (2 new Image Resizer tests).
  • Compared --help and representative invocations of each CLI against main. The DSC manifest output and the Settings search index are byte-identical.

@crutkas
Clint Rutkas (crutkas) requested a review from a team as a code owner September 29, 2026 18:40
@github-actions github-actions Bot added Product-Awake Issues regarding the PowerToys Awake utility Product-FancyZones Refers to the FancyZones PowerToy Product-Image Resizer Things regarding image resizing module Product-PowerDisplay Ready for review labels Sep 29, 2026
@github-actions

Copy link
Copy Markdown

🧭 PR intake

Visual evidence: Not needed — The changed files do not indicate a visible UI change. No visual evidence is expected.

Recommendation

Link the issue this PR fixes using a closing keyword such as Closes #123.

✅ Ready for review

This PR passed the automated intake checks and is ready for maintainer review.

Automated PR intake; PowerToys maintainers make final decisions.

Clint Rutkas (crutkas) added a commit that referenced this pull request Sep 30, 2026
â€Ķ or Screen Ruler UI tests are selected (#50891)

## Summary of the Pull Request

PR CI fails `ImageResizer.ContextMenu.EnabledState` whenever it selects
`ImageResizer.UITests` without also selecting a suite from
`$authenticatedSettingsIpcModules`. The job then doesn't test-sign
`PowerToys.exe` and `PowerToys.Settings.exe`, so the Release Runner
rejects the Settings pipe client as `not-microsoft-signed` and never
applies the Image Resizer toggle.

This PR adds `ImageResizer.UITests` to the exact-stem
`$authenticatedSettingsIpcModules` list in
`.pipelines/v2/templates/job-test-project.yml`. The audit below found
two more auto-selectable suites with the same dependency, so it adds
them too: `FileLocksmith.UITests` and `ScreenRuler.UITests.Next`.
`.pipelines/tests/uiTestSigningSelection.Tests.ps1` mirrors the list and
now has an ImageResizer-only regression test on x64 Win10, x64 Win11,
and ARM64. The PR also updates
`.github/skills/ui-tests-local-vm/references/shell-extensions-and-signing.md`,
which described this signing as PowerRename-only. It now states the
rule: any suite that changes module state through Settings must be in
the list, and the YAML is the source of truth.

This unblocks the UI-test run of #50884 (System.CommandLine 2.0
upgrade).

## PR Checklist

- [ ] Closes: N/A (no tracking issue; unblocks the UI-test run of
#50884)
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass.
`uiTestSigningSelection.Tests.ps1` passes 45/45. The 7 failures
elsewhere in `.pipelines\tests` already fail the same way on `main` (see
Validation).
- [ ] **Localization:** All end-user-facing strings can be localized
(N/A, no strings)
- [x] **Dev docs:** Added/updated. `shell-extensions-and-signing.md` now
states the Settings-IPC opt-in rule and points to the YAML as the source
of truth.
- [ ] **New binaries:** Added on the required places (N/A)
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** N/A

## Detailed Description of the Pull Request / Additional comments

### Root cause

- Since #49527, a Release Runner only dispatches Settings IPC from a
`PowerToys.Settings.exe` with a valid Microsoft Authenticode signature
(`src/runner/settings_window.cpp`,
`src/common/interop/pipe_caller_auth.cpp`). PR builds are unsigned.
- `job-test-project.yml` handles this by test-signing both companions
(`signSparsePackages.ps1 -RequiredAuthenticodeFile PowerToys.exe,
PowerToys.Settings.exe`). It only does so when a selected suite is in
`$authenticatedSettingsIpcModules` (or when all modules run).
`ImageResizer.UITests` wasn't in that list.
- The Image Resizer switch only sends the general-settings IPC message
(`ImageResizerViewModel.IsEnabled` calls `SendConfigMSG`). The Runner is
what disables the module and persists `enabled`
(`src/runner/general_settings.cpp`). The shell extension reads
`enabled["Image Resizer"]` from that Runner-written `settings.json`
(`ImageResizerLib/Settings.cpp`). When the message is rejected, the
switch changes visually but the context-menu entry stays.

### Evidence

- **Build 389804 (#50884):** #50884 touches `awake`, `fancyzones`,
`imageresizer`, and `powerdisplay`. Running `resolveUiTestModules.ps1`
on its changed files selects `FancyZones.UITests.Next`,
`FancyZonesEditor.UITests.Next`, and `ImageResizer.UITests`, none of
which is in the list. `ImageResizer.ContextMenu.EnabledState` failed the
same way on ARM64, x64 Win10, and x64 Win11, with 15/16 passing on each.
The Runner log in the test attachments shows `Rejected unauthenticated
Settings pipe client ... PowerToys.Settings.exe
reason=not-microsoft-signed`.
- **Build 389369 (#50218), last pass:** NewPlus and PowerRename UI tests
ran in the same job. They are in the list, so they turned on companion
signing for the whole job, ImageResizer included. #50534's CI likewise
ran Image Resizer (16/16) and File Locksmith (9/9) only alongside listed
suites (New+, PowerRename, Registry Preview), which hid the gap.

### Audit of suites that change module state through Settings

"Auto-selectable" means the project references `UITestAutomation.Next`,
which `resolveUiTestModules.ps1` needs to pick it for a PR that touches
that module.

| Suite | Settings-driven change + Runner reaction? | Action |
|---|---|---|
| `ImageResizer.UITests` | Yes. `ImageResizer.ContextMenu.EnabledState`
turns the module off and on in Settings, then asserts the context-menu
command disappears and comes back (and the sparse package re-registers).
| **Added** |
| `FileLocksmith.UITests` | Yes.
`FileLocksmith.ContextMenu.EnabledState` follows the same pattern.
`FileLocksmithViewModel` only sends IPC, and the extension reads
`enabled["File Locksmith"]` from the Runner-written general settings
(`FileLocksmithLib/Settings.cpp`). | **Added.** It was a negative
example in the Pester test; that case is now the near-miss
`FileLocksmith.UITests.Extra`. |
| `ScreenRuler.UITests.Next` | Yes. `TestScreenRulerShortcutActivation`
disables Screen Ruler in Settings, asserts the activation shortcut no
longer opens it, then re-enables it and expects it to open.
`MeasureToolViewModel.IsEnabled` only sends IPC. | **Added** |
| `KeyboardManager.UITests` | No. Settings starts the editor itself
(`Process.Start`); the test only asserts the switch is on. | None |
| `EnvironmentVariables.UITests` | No. Launch uses a named event, and
Settings saves the admin option itself. | None |
| `AlwaysOnTop.UITests`, `Peek.UITests.Next`, `PreviewPane.UITests`,
`FancyZones.UITests.Next`, `FancyZonesEditor.UITests.Next` | No. They
use seeded settings files, named events, or the module's file watcher. |
None |
| `Settings.UITests` | No. Navigation smoke tests, plus PowerDisplay
profile reordering that Settings saves itself. | None |
| `Workspaces.Editor.UITests` | No. The Runner-dependent cases are
`[Ignore]`d. | Stays a negative example |

The already-listed suites (AdvancedPaste, ColorPicker, CropAndLock,
Hosts, LightSwitch.Next, MouseUtils, New+, PowerAccent, PowerRename,
RegistryPreview, Workspaces.Next, ZoomIt) are unchanged. Adding a suite
doesn't change which sparse packages get signed:
`signSparsePackages.ps1` signs every one it finds either way. It stops
PowerToys first, test-signs the two companions, and makes signing
failures fatal instead of warnings.

### Follow-ups (not in this PR)

- Legacy WinAppDriver suites `ScreenRuler.UITests` and
`PowerOCR.UITests` have the same disable-then-shortcut pattern. PR CI
doesn't auto-select them, and they are `OutputType=Library`, so the
MTP-based "Run UI Tests" step can't run them when selected by name. Opt
them in if they are migrated or revived.
- `runUiTestAsUser.Tests.ps1` ‹ "scopes Workspaces authenticated
Settings IPC signing without changing other families" fails on `main` (7
cases). Its single-line regex can't parse the multi-line
`$requiresAuthenticatedSettingsIpc = $allModules -or @(` statement from
#50534. `uiTestSigningSelection.Tests.ps1` now covers the same behavior,
so it can be fixed or removed separately.

### After merge

PR CI builds `refs/pull/N/merge`, so #50884 picks up this fix from a
**new** PR build (for example `/azp run`). "Rerun failed jobs" on build
389804 reuses its original source version and will still fail.

## Validation Steps Performed

All runs used PowerShell 7.6 with the in-box Pester 3.4.0, matching the
tests' Pester 3 `Should Be` syntax. Nothing was installed:

```powershell
pwsh -NoProfile -Command "Import-Module 'C:\Program Files\WindowsPowerShell\Modules\Pester\3.4.0\Pester.psd1'; Invoke-Pester -Script .\.pipelines\tests\uiTestSigningSelection.Tests.ps1"
```

- `uiTestSigningSelection.Tests.ps1`: **45/45 passed**, up from 37/37 on
`main`. The new cases are the 3 added stems, 3 near-miss negatives
(replacing the old `FileLocksmith.UITests` negative), and
ImageResizer-only on `x64Win10`, `x64Win11`, and `ARM64`.
- Red check: I ran the updated test file against `main`'s
`job-test-project.yml` in a scratch copy. Exactly the 6 new expectations
failed: the 3 added stems and ImageResizer-only on all three platforms.
- All of `.pipelines\tests`: **170 passed, 7 failed** with this change,
versus 162 passed, 7 failed on `main`. All 7 failures are the
pre-existing `runUiTestAsUser.Tests.ps1` parse error described above.
- YAML: `job-test-project.yml` parses with PyYAML 6.0.3, and the signing
step contains the new stems. A `previewRun=true` of the internal **UI
Test Automation** pipeline on this branch with
`uiTestModules=[ImageResizer.UITests]` expanded successfully
(`Build_x64`, `Test_x64Win10_FullBuild`, `Test_x64Win11_FullBuild`) and
created no build.
- CI proof: internal **UI Test Automation** run, build `159036467`. It
uses `buildNowSlim` (the same unsigned-installer path as PR CI) on arm64
and x64 (Win10 and Win11), with `uiTestModules=[ImageResizer.UITests]`
only, at `a34f7e59`. That commit is the complete pipeline change; the
only later commit is the docs update. Its preview showed all three test
jobs' signing steps with `$modulesRaw = 'ImageResizer.UITests'` and the
new list entries. **Result: in progress; I'll update this section when
it finishes.**
- No local product build was needed for this pipeline and docs change.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@crutkas

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@crutkas

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Clint Rutkas (crutkas) added a commit that referenced this pull request Sep 30, 2026
â€ĶSamplePagesExtension (#50917)

## Summary of the Pull Request

Fixes an intermittent PowerToys CI failure. The main build sometimes
fails while MSIX packaging trims the Command Palette sample extension
(`SamplePagesExtension`):

```
Microsoft.NET.ILLink.targets(150,5): error MSB6006: "dotnet.exe" exited with code 57005.
Microsoft.NET.ILLink.targets(103,5): error NETSDK1144: Optimizing assemblies for size failed.
```

The fix is one Release-only property in `SamplePagesExtension.csproj`:
`TrimmerRemoveSymbols=true`. With it, ILLink doesn't rewrite debug
symbols for this trim, so it never loads the native Windows PDB writer
that crashes. The trimmed code doesn't change. The only difference is
that the trimmed output has no PDBs.

This is backlog item **BUILD-8** of the PowerToys speed & quality
backlog.

## PR Checklist

- [ ] Closes: N/A (backlog item BUILD-8, no GitHub issue)
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
(part of the speed & quality backlog)
- [ ] **Tests:** Added/updated and all pass (N/A: build-configuration
change only, no product code. Validated with a local trimmed publish,
repeated ILLink runs before and after the fix, and PR CI; see below)
- [ ] **Localization:** All end-user-facing strings can be localized
(N/A: no strings)
- [ ] **Dev docs:** Added/updated (N/A)
- [ ] **New binaries:** Added on the required places (N/A: no new
binaries)
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: N/A

## Detailed Description of the Pull Request / Additional comments

### Root cause

In the failing jobs, ILLink (`dotnet.exe`, Microsoft.NET.ILLink.Tasks
10.0.11) dies in its output step while it writes symbols:

```
Fatal error.
0xC0000005
   at Mono.Cecil.Pdb.ISymUnmanagedWriter2.Close()
   at Mono.Cecil.Pdb.SymWriter.Close()
   at Mono.Cecil.Pdb.NativePdbWriter.Write()
   at Mono.Linker.CustomSymbolWriter.Write()
   ...
   at Mono.Linker.Steps.OutputStep.WriteAssembly(Mono.Cecil.AssemblyDefinition, System.String)
```

- **ILLink runs in every Release CI build.**
`SamplePagesExtension.csproj` sets `GenerateAppxPackageOnBuild=true`,
and in Release it also sets `PublishTrimmed=true`. MSIX packaging during
the solution build publishes the app with `win-$(Platform).pubxml`, so
`_RunILLink` trims it. It's the only ILLink invocation in PR CI.
- **ILLink rewrites the symbols.** `TrimmerRemoveSymbols` defaults to
`false` unless `DebuggerSupport=false`, so ILLink gets `-b` and rewrites
the PDB of every assembly it trims.
- **Those symbols are Windows PDBs.** `src\Common.Dotnet.props` sets
Release `DebugType=pdbonly`. That covers the sample and also
`Microsoft.CommandPalette.Extensions.Toolkit`, a `ProjectReference`
that's trimmed in the same ILLink run. Mono.Cecil can only write Windows
PDBs through the native COM `ISymUnmanagedWriter` (the .NET Framework's
DiaSymReader). The access violation happens inside that native
`Close()`, so we can't fix it in this repo. We can only stop using that
writer.

### Affected builds and frequency

I used the public Azure DevOps REST API to scan every build still
retained for the **PowerToys CI** pipeline (shine-oss/PowerToys,
2026-08-31 to 2026-09-30), including earlier attempts of retried jobs.
Each failure below has the same stack, in the SamplePagesExtension
`_RunILLink` step:

| Build | Trigger | Queued (UTC) | Failed job |
| --- | --- | --- | --- |
|
[388605](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=388605)
| `main` (batched CI) | 2026-09-11 | Build Release_x64 |
|
[389658](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=389658)
| PR #50843 | 2026-09-28 | Build Release_arm64 |
|
[389667](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=389667)
| PR #50186 | 2026-09-28 | Build Release_arm64 |
|
[389871](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=389871)
| PR #50507 | 2026-09-30 | Build Release_x64 |
|
[389888](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=389888)
| PR #50884 | 2026-09-30 | Build Release_x64 |

- **Rate:** 5 of 255 builds (~2%) and 5 of 486 x64/arm64 build jobs
(~1%). In the last ~2 weeks (2026-09-14 to 2026-09-30) it was 4 of 196
builds (390 build jobs). PR builds only show up in this project from
2026-09-22, and 4 of those 125 PR builds (~3%) failed this way, all in
the last three days. It hits both x64 and arm64 jobs. All five failures
used ILLink 10.0.11, and every build I sampled from 2026-09-15 on used
.NET SDK 10.0.303, so this isn't a new-toolset regression. The 30
scheduled "PowerToys CI (Caching)" builds had no hits.
- **Cost:** A hit fails the whole build job after ~30–34 minutes, and
the job has to be re-run. A green build job takes ~53 minutes (median),
and the test jobs wait for it. In 4 of the 5 builds, this crash was the
job's only error. 389888 also had two unrelated unit-test failures in
the same task.

### Fix and why

| Option | Result |
| --- | --- |
| (a) `DebugType=portable` for the sample (preferred, because it would
keep symbols) | **Not enough.** The sample's PDB becomes portable, but
the same ILLink run still rewrites
`Microsoft.CommandPalette.Extensions.Toolkit.pdb` as a Windows PDB
(verified locally, see Validation), so the native writer is still used.
Switching the Toolkit to portable PDBs would change the symbol format of
a shipping CmdPal/SDK binary, which is out of scope here. |
| (b) `TrimmerRemoveSymbols=true` (**chosen**) | ILLink runs without
`-b`, so it doesn't read or write any symbols and never loads the native
writer. The trimmed assemblies are otherwise identical. |
| (c) Don't package or trim the sample in CI | Not needed. It would also
drop CI coverage of the trimmed, AOT-compatible sample that extension
authors copy. |

Effects of (b):
- The sample's trimmed publish output, and so its MSIX, has no PDBs
(locally, the publish folder had none). The WinAppSDK MSIX targets skip
`_GenerateAppxSymbolPackage` when the payload has no PDBs, so the sample
no longer gets an `.appxsym` (confirmed in PR CI). The sample isn't
shipped to users (it's not in the installer).
- The untrimmed build output keeps its PDB
(`<Platform>\Release\WinUI3Apps\CmdPalExtensions\SamplePagesExtension\SamplePagesExtension.pdb`).
That's the PDB CI's "Stage Unique Symbols" step already picks up.
- Debug builds don't trim, so the extension-author inner loop is
unchanged. The property sits in the existing Release property group, and
the repo-wide `DebugType` isn't touched.

### Other projects checked

- **ILLink in PR CI:** I grepped every build task log of a green PR
build
([389905](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=389905))
for ILLink and ILC invocations. That covered x64 and arm64 (main build,
BugReportTool, StylesReportTool, the seven "Publish â€Ķ for Packaging"
steps, DSC, and the installer) plus the "Build SDK" job. The only
`illink.dll` invocation is SamplePagesExtension, once per platform, and
nothing runs ILC.
- **Other trimmed or AOT projects:** `Microsoft.CmdPal.Ext.PowerToys`,
`Microsoft.CommandPalette.Extensions.Toolkit`, `UITestAutomation`,
PowerOCR, PowerDisplay (+CLI), and PowerAccent.UI set `PublishAot` or
`PublishTrimmed`. PR CI only builds them and never publishes them, so
neither ILLink nor ILC runs. CmdPal UI uses Native AOT only in the
release pipeline (`EnableCmdPalAOT=true`). Native AOT trims with ILC,
not ILLink/Cecil, so it doesn't use this writer. The release pipeline
builds the same solution, so its SamplePagesExtension trim gets this fix
too. No follow-ups needed.
- **`src\modules\cmdpal\ExtensionTemplate`:** Not built in CI (it's not
in `PowerToys.slnx`, and `verifyCommonProps.ps1` skips it). It doesn't
import `Common.Dotnet.props` or set `DebugType`, so it uses the SDK
default portable PDBs. The Toolkit it gets from NuGet ships without a
PDB, so a trimmed template publish only uses Cecil's managed
portable-PDB writer. No template change needed.

## Validation Steps Performed

**Local environment limits:** The dev box is ARM64 with VS 18 and has no
C++ toolset or Windows SDK, so there's no `MakeAppx` and MSIX packaging
can't run locally. I exercised ILLink with a Release|x64 publish that
skips packaging:

```powershell
tools\build\build.ps1 -Platform x64 -Configuration Release /restore /t:Publish /p:GenerateAppxPackageOnBuild=false `
  /p:CsWinRTWindowsMetadata=<Microsoft.Windows.SDK.NET.Ref>\winmd `
  /p:CustomAfterMicrosoftCommonTargets=<local hook that swaps .vcxproj references for prebuilt winmd/dll>
```

The hook is local only and isn't part of this PR. Restores were
anonymous (`NUGET_PLUGIN_PATHS`, `NUGET_NETFX_PLUGIN_PATHS`, and
`NUGET_NETCORE_PLUGIN_PATHS` pointed at an empty folder), and no new
packages were needed. Local ILLink is 10.0.12 (SDK 10.0.401); CI uses
10.0.11. To tell PDB formats apart, I checked the file header: a Windows
PDB starts with `Microsoft C/C++ MSF 7.00` and a portable PDB starts
with `BSJB`.

1. **Before (`main`):** Publish exits 0. ILLink runs with `-b` and
writes `SamplePagesExtension.pdb` and
`Microsoft.CommandPalette.Extensions.Toolkit.pdb` as Windows PDBs, which
means the native writer is used.
2. **Option (a), not committed:** `SamplePagesExtension.pdb` becomes
portable (`BSJB`), but ILLink still writes
`Microsoft.CommandPalette.Extensions.Toolkit.pdb` as a Windows PDB.
3. **After (this PR):** Publish exits 0 with the same two `IL2104`
warnings as `main` (both already in `WarningsNotAsErrors`). The ILLink
task gets `RemoveSymbols=True`, so there's no `-b`, and it returns
`_ILLinkExitCode=0` without writing any PDBs. Compared with the "before"
output, the trimmed `SamplePagesExtension.dll` (171 types, 743 methods,
251 fields) and `Microsoft.CommandPalette.Extensions.Toolkit.dll` (399
types, 1850 methods, 530 fields) have the same metadata counts and code
size. The only change is the missing CodeView debug-directory entry (the
pointer to the PDB).
4. **Property evaluation:** `dotnet msbuild -getProperty` gives
`TrimmerRemoveSymbols=true` for Release|x64 and Release|ARM64 and leaves
it empty for Debug, where `PublishTrimmed=false`.
5. **Repeated trims:** I replayed the exact ILLink command from the
MSBuild log 20 times with the native arm64 `dotnet` and 20 times with
the emulated x64 `dotnet` (closer to the x64 CI agents), before and
after the fix.
- Before: 40/40 passed, plus 10 more runs with
`DOTNET_GCgen0size=0x20000`. Every run wrote two Windows PDBs through
the native writer.
   - After: 40/40 passed, and no PDBs were written.
- The crash didn't reproduce locally. That's consistent with a ~1%
per-job rate, so PR CI is the real gate.
6. **PR CI
([389926](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=389926)):
green on x64 and arm64.** All jobs passed: Build Release_x64 (build +
tests), Build Release_arm64, Build SDK, and both "Resolve affected UI
test projects" jobs. In both main-build logs:
- SamplePagesExtension's ILLink ran once (`illink.dll -a
"obj\x64\Release\SamplePagesExtension.dll"` and `obj\ARM64\...`, ILLink
10.0.11) without `-b`. It has 253 arguments versus 254 in build 389905,
which doesn't have this change, and the only one missing is `-b`.
- There were no `Fatal error`, `0xC0000005`, `57005`, or `NETSDK1144`
markers. The task had 0 errors and the same two `IL2104` warnings as
389905.
- MSIX packaging still produced `SamplePagesExtension_1.0.0.0_x64.msix`
and `SamplePagesExtension_1.0.0.0_arm64.msix`, and it skipped the
sample's `.appxsym` as expected.
- "Stage Unique Symbols" still links 202 PDBs per platform, the same as
389905, and that includes the untrimmed `SamplePagesExtension.pdb`.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Clint Rutkas (crutkas) and others added 2 commits October 6, 2026 14:14
Bump System.CommandLine from 2.0.0-beta4.22272.1 to 2.0.1 and migrate the
CLIs that use its API (PowerToys.DSC, Awake, FancyZonesCLI, Image Resizer
CLI, PowerDisplay.Cli) and their tests to the 2.0 API: SetHandler and
InvocationContext become SetAction and ParseResult; AddOption, AddArgument
and AddCommand become Options, Arguments and Subcommands; IsRequired becomes
Required; AddValidator and ErrorMessage become Validators and AddError;
GetValueFor* becomes GetValue; Parser(command).Parse becomes command.Parse.

Microsoft.CmdPal.Ext.Shell and Settings.UI.XamlIndexBuilder reference the
package without using its API and only pick up the new version.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Shorten the --help/--version option comments to one line each and drop
a comment that restated the code. No behavior change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@crutkas
Clint Rutkas (crutkas) force-pushed the crutkas-system-commandline-2-0-ga-dep-3 branch from c143af3 to 6e39e97 Compare October 6, 2026 21:14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Automated review generated with .github/prompts/review-pr.prompt.md (Copilot CLI).

Reviewed head 6e39e97 (full review, iteration 1). Found no blocking issues. Severity counts: high 0 · medium 0 · low 1 · info 2. No inline comments, because the only actionable finding is on a line outside the diff hunks.
Checked against the System.CommandLine GA sources and the beta4 sources for all 5 migrated CLIs (DSC, Awake, FancyZonesCLI, Image Resizer, PowerDisplay.Cli): option names, aliases and defaults, Required, exit codes from SetAction, help/version built-ins (Options.Clear() keeps -h as --height or as a value, and HasHelpToken still ignores TokenType.Argument), parse-error reporting, validator ordering, greedy tokenization, response files, AOT (PowerDisplay.Cli) and the CPM pin. CI is green.

Unanchored finding

  • [low] code-comments — src/modules/fancyzones/FancyZonesCLI/CommandLine/FancyZonesCliUsage.cs:49: // Find first alias (Aliases includes Name) is now wrong. In 2.0, Command.Aliases excludes Name, which is why this PR adds the c.Name check and Aliases.Prepend(Name). Update the comment (e.g. // Aliases excludes Name in System.CommandLine 2.0), and optionally simplify to command.Aliases.FirstOrDefault().

Info (no action required for this PR)

  • Pre-existing and unchanged from beta4: validators that call GetValue/GetValueOrDefault throw InvalidOperationException out of Parse() for non-numeric input. Examples are SetLayoutCommand.cs:54 (set-layout x --monitor abc) and the Image Resizer QualityOption/SizeOption validators (--quality abc).
  • doc/devdocs/cli-conventions.md:36 hard-codes 2.0.1, so it will drift on the next bump.

Disable default directives in the Image Resizer and PowerDisplay roots,
which parse input before manually executing commands. This prevents
[suggest] from clearing errors and allowing invalid commands to proceed.

Add regression coverage for conversion, validator, required argument,
unknown option, and response file errors with both completion forms.

Validation: x64 Debug builds and 166 targeted tests passed.

@moooyo Yu Leng (moooyo) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

â€Ķdline-2-0-ga-dep-3

# Conflicts:
#	Directory.Packages.props
Light Switch CLI (#50459) and Settings CLI (#50507) merged to main using System.CommandLine beta APIs, breaking the 2.0 GA upgrade build. Port them to the GA API while preserving command names, options, output, and exit codes. Light Switch clears the default RootCommand help/version/directives, ignores implicit option results, and reports leading [directive] tokens as unrecognized to keep the previous parsing behavior.
@crutkas

Copy link
Copy Markdown
Member Author

Yu Leng (@moooyo) had to do another push.

@moooyo

Copy link
Copy Markdown
Contributor

Boliang Zhang (@LegendaryBlair) Could you please help to review it? OOF today. I think it should in 0.102

@crutkas

Copy link
Copy Markdown
Member Author

Boliang Zhang (@LegendaryBlair) possible for another review? Yu Leng (@moooyo) did approve prior

@crutkas
Clint Rutkas (crutkas) merged commit d162b92 into main Oct 13, 2026
13 checks passed
@crutkas
Clint Rutkas (crutkas) deleted the crutkas-system-commandline-2-0-ga-dep-3 branch October 13, 2026 06:36
Boliang Zhang (LegendaryBlair) added a commit that referenced this pull request Oct 13, 2026
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Migrate AdvancedPaste.CLI from the System.CommandLine beta4 API to the
centrally pinned 2.0.1 API. This fixes the main-branch compilation
failure after #50884, which upgraded the dependency after #50834
introduced this CLI.

Preserve the existing commands, parameter names and aliases, help text,
JSON output, clipboard defaults, and exit codes. Add regression coverage
for aliases and help-like option values.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: N/A (build regression involving #50834 and #50884)
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: N/A

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

### Cause and scope

[Main CI
390858](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=390858)
and
[390863](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=390863)
fail on both architectures with missing `System.CommandLine.IO`,
`IConsole`, and `IStandardStreamWriter`. AdvancedPaste.CLI also still
used beta4 option constructors, command registration, parsing, and
value/result lookup APIs.

- `src/modules/AdvancedPaste/AdvancedPaste.CLI/Program.cs`: use
`Options`/`Subcommands`, `RootCommand.Parse`,
`ParseResult.GetValue`/`GetResult`, and
`InvocationConfiguration.Output`/`Error`. Define option names/aliases
separately from `Description` and remove the obsolete console adapter.
- Keep recognizing help-like values belonging to an option, rather than
interpreting a prompt or path such as `-h` as a help request.
-
`src/modules/AdvancedPaste/AdvancedPaste.Cli.UnitTests/ProgramTests.cs`:
cover both action aliases, long/short file options, all existing help
aliases, and help-like prompt values. Existing JSON, error,
cancellation, policy, and clipboard-adapter tests remain intact.
- `doc/devdocs/modules/advancedpaste.md`: document the parser API and
the help-token invariant.

No dependency downgrade, new binaries, installer changes, policy
changes, test suppression, or pipeline changes. User-facing text is
unchanged; the localization checkbox denotes preservation of existing
behavior. New-binary and external user-documentation checklist items are
N/A.

This PR targets **main only**. It does not cherry-pick to stable, queue
a signed release, or publish a release.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

### Build scope and environment limitation

The ordinary documented build command was attempted:

```powershell
Set-Location 'D:\PT102-CommandLineFix\src\modules\AdvancedPaste\AdvancedPaste.Cli.UnitTests'
& 'D:\PT102-CommandLineFix\tools\build\build.ps1' -Platform x64 -Configuration Release -Path . -ExtraArgs '/p:CIBuild=false'
```

**Blocked before source compilation, exit 1:** the local Visual Studio
installation cannot resolve `Microsoft.NET.Sdk`. Explicitly selecting
the installed SDK then fails in `ProcessFrameworkReferences` with
MSB4018 loading `Microsoft.Deployment.DotNet.Releases, Version=2.0.0.0`.
A task-local .NET 10.0.303 SDK can restore the real project graph, but
its Core MSBuild host cannot execute the native VC tasks. No tracked
build settings or system installation were changed to bypass these
failures.

To validate the changed code despite that host issue, rebuilt the
**actual CLI and unit-test `.csproj` files**, with their repository
analyzers and warnings-as-errors, using unchanged dependency binaries
from successful [CI
390854](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=390854),
source `26b99a0a01af48b87a6aacd341e2c355ea3c6d1e`. The source of the
reused managed dependency projects is unchanged from that build to this
PR's base `863ff53e9b87790cf2885d5ef527587534e1fecf`.

An **uncommitted, local-only** `ReuseCiDependencies.targets` replaces
project references with those dependency assemblies. The CLI itself and
all CLI test sources were compiled from this worktree against
System.CommandLine **2.0.1**; neither the parser nor the CLI
implementation was stubbed. This is dependency-reuse validation, **not**
a successful clean build of the full dependency graph.

```powershell
$repo = 'D:\PT102-CommandLineFix'
$validation = "$repo\artifacts\commandline-fix"
$dotnet = "$validation\dotnet\dotnet.exe"
$env:DOTNET_ROOT = "$validation\dotnet"
$env:MSBuildEnableWorkloadResolver = 'false'
$buildArgs = @(
    '/t:Build', '/p:Platform=x64', '/p:Configuration=Release',
    "/p:SolutionDir=$repo\", '/p:CIBuild=false', '/p:SkipLongPathsCheck=true',
    '/p:BuildProjectReferences=false', '/p:DisableTransitiveProjectReferences=true',
    "/p:CustomAfterMicrosoftCommonTargets=$validation\ReuseCiDependencies.targets",
    '/v:minimal', '/nologo'
)
& $dotnet msbuild "$repo\src\modules\AdvancedPaste\AdvancedPaste.CLI\AdvancedPaste.CLI.csproj" @buildArgs
& $dotnet msbuild "$repo\src\modules\AdvancedPaste\AdvancedPaste.Cli.UnitTests\AdvancedPaste.Cli.UnitTests.csproj" @buildArgs
```

**Both passed, exit 0.** `SkipLongPathsCheck` is the existing developer
option; the machine-wide long-path registry setting was not modified.

### Tests and executable smoke checks

```powershell
Set-Location "$repo\x64\Release\tests\AdvancedPaste.Cli.UnitTests"
& $dotnet '.\AdvancedPaste.Cli.UnitTests.dll' --filter 'FullyQualifiedName~ProgramTests' --report-trx
```

**Passed, exit 0: 91/91, zero skipped.**

```powershell
& $dotnet '.\AdvancedPaste.Cli.UnitTests.dll' --report-trx
```

**Passed, exit 0: 151/151, zero skipped**, including the nine additional
regression cases.

```powershell
& "$repo\src\modules\AdvancedPaste\AdvancedPaste.CLI\SmokeTest.ps1" `
    -Executable "$repo\x64\Release\WinUI3Apps\PowerToys.AdvancedPaste.Cli.exe"
```

**Passed, exit 0:** existing executable smoke checks for help,
stdin/stdout, file conversion, JSON output, conflicting input modes, and
unsupported actions. Unchanged runtime dependencies and
`PowerToys.AdvancedPaste.pri` were supplied from the same successful CI
build. No real clipboard writes or AI-provider calls were performed.

```powershell
git -C D:\PT102-CommandLineFix diff --check
```

**Passed.**

ARM64 compilation, UI automation, a clean native dependency build, and
an official signed release build were **not completed locally**. Public
PR CI remains the full integration gate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@zadjii-msft

Copy link
Copy Markdown
Member

Clint Rutkas (@crutkas) Yu Leng (@moooyo)

How the fuck did this merge and then immediately break CI? What happened that caused the PR CI checks on this to pass, and then fail for future PRs? How can we avoid this in the future?

Boliang Zhang (LegendaryBlair) pushed a commit that referenced this pull request Oct 14, 2026
## Summary of the Pull Request

Upgrades System.CommandLine from `2.0.0-beta4.22272.1` to `2.0.1` and
migrates PowerToys.DSC, Awake, FancyZonesCLI, Image Resizer, and
PowerDisplay.Cli (and their tests) to the 2.0 API. Option names,
aliases, defaults, and exit codes are unchanged.

## PR Checklist

- [ ] Closes: N/A
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized (no
new strings)
- [x] **Dev docs:** Added/updated (`doc/devdocs/cli-conventions.md`)
- [ ] **New binaries:** Added on the required places (none)
- [ ] **Documentation updated:** N/A

## Detailed Description of the Pull Request / Additional comments

- `2.0.1` is pinned because it's the newest 2.0.x available in the
PowerToys NuGet feed.
- The Image Resizer and PowerDisplay CLIs remove the
`--help`/`--version` options that 2.0 adds to every `RootCommand`, so
`-h` keeps its existing meaning.
- `CA1010` is suppressed where public types derive from `Command`, which
implements only non-generic `IEnumerable`.
- User-visible changes:
- Help lists `-?, -h, --help` before `--version`, and Awake no longer
prints `[default: False]`.
- The Image Resizer CLI rejects invalid `--unit`/`--fit` values with
exit code 1 instead of ignoring them.
- FancyZonesCLI reports one error instead of two for `set-layout
<layout> --monitor 0 --all`.

## Validation Steps Performed

- CI: [PowerToys CI build
390259](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=390259):
x64/arm64 builds, unit tests, and UI tests.
- Anonymous restore on a clean NuGet cache downloads `System.CommandLine
2.0.1` from the feed.
- Built all seven System.CommandLine consumers locally; DSC, Awake,
Image Resizer, PowerDisplay.Cli, and CmdPal Shell unit tests pass (2 new
Image Resizer tests).
- Compared `--help` and representative invocations of each CLI against
main. The DSC `manifest` output and the Settings search index are
byte-identical.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Yu Leng <42196638+moooyo@users.noreply.github.com>
(cherry picked from commit d162b92)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Boliang Zhang (LegendaryBlair) added a commit that referenced this pull request Oct 14, 2026
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Migrate AdvancedPaste.CLI from the System.CommandLine beta4 API to the
centrally pinned 2.0.1 API. This fixes the main-branch compilation
failure after #50884, which upgraded the dependency after #50834
introduced this CLI.

Preserve the existing commands, parameter names and aliases, help text,
JSON output, clipboard defaults, and exit codes. Add regression coverage
for aliases and help-like option values.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: N/A (build regression involving #50834 and #50884)
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: N/A

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

### Cause and scope

[Main CI
390858](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=390858)
and
[390863](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=390863)
fail on both architectures with missing `System.CommandLine.IO`,
`IConsole`, and `IStandardStreamWriter`. AdvancedPaste.CLI also still
used beta4 option constructors, command registration, parsing, and
value/result lookup APIs.

- `src/modules/AdvancedPaste/AdvancedPaste.CLI/Program.cs`: use
`Options`/`Subcommands`, `RootCommand.Parse`,
`ParseResult.GetValue`/`GetResult`, and
`InvocationConfiguration.Output`/`Error`. Define option names/aliases
separately from `Description` and remove the obsolete console adapter.
- Keep recognizing help-like values belonging to an option, rather than
interpreting a prompt or path such as `-h` as a help request.
-
`src/modules/AdvancedPaste/AdvancedPaste.Cli.UnitTests/ProgramTests.cs`:
cover both action aliases, long/short file options, all existing help
aliases, and help-like prompt values. Existing JSON, error,
cancellation, policy, and clipboard-adapter tests remain intact.
- `doc/devdocs/modules/advancedpaste.md`: document the parser API and
the help-token invariant.

No dependency downgrade, new binaries, installer changes, policy
changes, test suppression, or pipeline changes. User-facing text is
unchanged; the localization checkbox denotes preservation of existing
behavior. New-binary and external user-documentation checklist items are
N/A.

This PR targets **main only**. It does not cherry-pick to stable, queue
a signed release, or publish a release.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

### Build scope and environment limitation

The ordinary documented build command was attempted:

```powershell
Set-Location 'D:\PT102-CommandLineFix\src\modules\AdvancedPaste\AdvancedPaste.Cli.UnitTests'
& 'D:\PT102-CommandLineFix\tools\build\build.ps1' -Platform x64 -Configuration Release -Path . -ExtraArgs '/p:CIBuild=false'
```

**Blocked before source compilation, exit 1:** the local Visual Studio
installation cannot resolve `Microsoft.NET.Sdk`. Explicitly selecting
the installed SDK then fails in `ProcessFrameworkReferences` with
MSB4018 loading `Microsoft.Deployment.DotNet.Releases, Version=2.0.0.0`.
A task-local .NET 10.0.303 SDK can restore the real project graph, but
its Core MSBuild host cannot execute the native VC tasks. No tracked
build settings or system installation were changed to bypass these
failures.

To validate the changed code despite that host issue, rebuilt the
**actual CLI and unit-test `.csproj` files**, with their repository
analyzers and warnings-as-errors, using unchanged dependency binaries
from successful [CI
390854](https://dev.azure.com/shine-oss/PowerToys/_build/results?buildId=390854),
source `26b99a0a01af48b87a6aacd341e2c355ea3c6d1e`. The source of the
reused managed dependency projects is unchanged from that build to this
PR's base `863ff53e9b87790cf2885d5ef527587534e1fecf`.

An **uncommitted, local-only** `ReuseCiDependencies.targets` replaces
project references with those dependency assemblies. The CLI itself and
all CLI test sources were compiled from this worktree against
System.CommandLine **2.0.1**; neither the parser nor the CLI
implementation was stubbed. This is dependency-reuse validation, **not**
a successful clean build of the full dependency graph.

```powershell
$repo = 'D:\PT102-CommandLineFix'
$validation = "$repo\artifacts\commandline-fix"
$dotnet = "$validation\dotnet\dotnet.exe"
$env:DOTNET_ROOT = "$validation\dotnet"
$env:MSBuildEnableWorkloadResolver = 'false'
$buildArgs = @(
    '/t:Build', '/p:Platform=x64', '/p:Configuration=Release',
    "/p:SolutionDir=$repo\", '/p:CIBuild=false', '/p:SkipLongPathsCheck=true',
    '/p:BuildProjectReferences=false', '/p:DisableTransitiveProjectReferences=true',
    "/p:CustomAfterMicrosoftCommonTargets=$validation\ReuseCiDependencies.targets",
    '/v:minimal', '/nologo'
)
& $dotnet msbuild "$repo\src\modules\AdvancedPaste\AdvancedPaste.CLI\AdvancedPaste.CLI.csproj" @buildArgs
& $dotnet msbuild "$repo\src\modules\AdvancedPaste\AdvancedPaste.Cli.UnitTests\AdvancedPaste.Cli.UnitTests.csproj" @buildArgs
```

**Both passed, exit 0.** `SkipLongPathsCheck` is the existing developer
option; the machine-wide long-path registry setting was not modified.

### Tests and executable smoke checks

```powershell
Set-Location "$repo\x64\Release\tests\AdvancedPaste.Cli.UnitTests"
& $dotnet '.\AdvancedPaste.Cli.UnitTests.dll' --filter 'FullyQualifiedName~ProgramTests' --report-trx
```

**Passed, exit 0: 91/91, zero skipped.**

```powershell
& $dotnet '.\AdvancedPaste.Cli.UnitTests.dll' --report-trx
```

**Passed, exit 0: 151/151, zero skipped**, including the nine additional
regression cases.

```powershell
& "$repo\src\modules\AdvancedPaste\AdvancedPaste.CLI\SmokeTest.ps1" `
    -Executable "$repo\x64\Release\WinUI3Apps\PowerToys.AdvancedPaste.Cli.exe"
```

**Passed, exit 0:** existing executable smoke checks for help,
stdin/stdout, file conversion, JSON output, conflicting input modes, and
unsupported actions. Unchanged runtime dependencies and
`PowerToys.AdvancedPaste.pri` were supplied from the same successful CI
build. No real clipboard writes or AI-provider calls were performed.

```powershell
git -C D:\PT102-CommandLineFix diff --check
```

**Passed.**

ARM64 compilation, UI automation, a clean native dependency build, and
an official signed release build were **not completed locally**. Public
PR CI remains the full integration gate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit 31de368)
@moooyo

Yu Leng (moooyo) commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Clint Rutkas (Clint Rutkas (@crutkas)) Yu Leng (Yu Leng (@moooyo))

How the fuck did this merge and then immediately break CI? What happened that caused the PR CI checks on this to pass, and then fail for future PRs? How can we avoid this in the future?

I did some investigation. Mike Griese (@zadjii-msft)

Yesterday, we have 2 PRs need to merge.
First one is #50834 . In this PR they introduced a new project (which used the System.commandLine)

Second one is this one.

This PR has triggered the CI check early and everything is green.
Then we merge the #50834, everything works well at this time.

But there's no conflict(at least github doesn't detect) bettwen both PR. so this PR's CI check is still green.

We merged this PR. then boom...

Clint Rutkas (crutkas) added a commit that referenced this pull request Oct 27, 2026
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Finishes DEP-3 by moving the central System.CommandLine pin from `2.0.1`
to `2.0.12`, the latest 2.0.x servicing release. No code changes are
needed. CLI help, errors, and exit codes stay the same.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: N/A (DEP-3 roadmap item; follows #50884)
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass (existing tests; version
bump only)
- [ ] **Localization:** All end-user-facing strings can be localized (no
new strings)
- [x] **Dev docs:** Added/updated (`doc/devdocs/cli-conventions.md`)
- [ ] **New binaries:** Added on the required places (none)
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** N/A

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

- **Library source is unchanged.** The 2.0.12 commit (dotnet/dotnet
`95017c7`) descends from the 2.0.1 commit (`fad253f`). The last commit
that touches `src/command-line-api/src/System.CommandLine` is `4ad7638`
(2025-11-14) in both, so 2.0.2–2.0.12 are .NET 10 servicing rebuilds.
- **The package layout matches 2.0.1:** the same `net8.0` and
`netstandard2.0` targets, 13 satellite cultures, and no `net8.0`
dependencies. `generateAllFileComponents.ps1` harvests satellites at
build time, so the installer needs no change.
- **AssemblyVersion is now `2.0.12.0`** with the same public key token.
.NET doesn't need binding redirects.
- **Restored anonymously** from `PowerToysPublicDependencies`, where
2.0.12 was already saved. Nothing new was pulled from nuget.org.
NOTICE.md doesn't list this package.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- `msbuild <proj> -t:Restore -p:RestorePackagesConfig=true
-p:SolutionDir=<repo>\`, run with `NUGET_PLUGIN_PATHS` pointing at an
empty folder, for all 10 consumers and their test projects: all exit 0.
- `tools\build\build.ps1 -Platform x64 -Configuration Debug -Path <dir>`
for 11 consumer and test projects: all exit 0, with no new warnings.
- `vstest.console.exe <dll> /Platform:x64`: LightSwitch.Cli 221/221,
AdvancedPaste.Cli 154/154, PowerDisplay.Cli 130/130, DSC 115/115,
ImageResizer 213/213, Awake 7/7, CmdPal Shell 128 passed and 1 skipped.
- Settings.UI.UnitTests: 426/448 pass, including all 19
`SettingsCliTests`. The 22 failures are `ImageResizer`/`KeyboardManager`
view-model tests where `ResourceLoaderInstance` throws
`FileNotFoundException`. The same 22 tests fail on a 2.0.1 baseline.
- A/B test: 31 calls across 7 CLIs (`--help`, unknown command or option,
invalid values) built against 2.0.1 and 2.0.12. stdout, stderr, and exit
codes are byte-identical.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-Awake Issues regarding the PowerToys Awake utility Product-FancyZones Refers to the FancyZones PowerToy Product-Image Resizer Things regarding image resizing module Product-LightSwitch Product-PowerDisplay Ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants