Skip to content

Fix #463 and #464: surface progress and stop lying about why init skipped SDK setup#484

Merged
nmetulev merged 3 commits into
mainfrom
fix/issue-463-init-progress
Apr 21, 2026
Merged

Fix #463 and #464: surface progress and stop lying about why init skipped SDK setup#484
nmetulev merged 3 commits into
mainfrom
fix/issue-463-init-progress

Conversation

@nmetulev
Copy link
Copy Markdown
Member

Closes #463 and #464.

#463winapp init can be silent for ~30s on a fresh machine

After answering "No" to the manifest-overwrite prompt, AskSdkInstallModeAsync performed two slow operations with no visible output:

  1. dotNetService.HasPackageReferenceAsync(csproj, "Microsoft.WindowsAppSDK") runs dotnet list package --format json, which triggers an implicit dotnet restore on a cold NuGet cache (30s+ for projects like AI Dev Gallery).
  2. A Task.WhenAll over 6 parallel NuGet feed queries (3 modes × 2 packages) used to label the SDK install prompt.

Both happened before any prompt was rendered, and the early-exit when the project already references WinAppSDK only logged at Debug level — so the user saw nothing at all.

Fixes:

  • DotNetService.HasPackageReferenceAsync: try a fast XDocument scan of the .csproj for an inline <PackageReference Include="…"/> first. Only positive matches short-circuit; absence still falls back to dotnet list package because Directory.Packages.props / SDK-imported packages aren't visible in the raw csproj.
  • WorkspaceSetupService: wrap the slow ops in a Spectre Status spinner ("Detecting project SDK references…" / "Fetching latest SDK versions…"), with a log-line fallback when output is redirected or Information logging is off.
  • Promote the "project already references WinAppSDK; skipping setup" log from Debug to Information.

#464winapp init says "SDK installation skipped by user choice" when it wasn't

WorkspaceSetupService always printed SDK installation skipped by user choice whenever options.SdkInstallMode == None. That fires even when the .NET path auto-sets None because the project already references WinAppSDK — not a user choice.

Fix: delete the trailing "by user choice" line. The actual reason is now logged at the decision site:

  • AskSdkInstallModeAsync logs the auto-skip line ("Project already references Microsoft.WindowsAppSDK; skipping Windows App SDK setup.") in the .NET case.
  • The interactive prompt logs Setup SDKs: Do not setup SDKs when the user picks that option.
  • --setup-sdks=none is the user's own input and needs no echo.

The matching unreachable LogDebug for non-.NET projects was removed for the same reason.

Tests

  • New unit tests for the XML fast path in HasPackageReferenceAsync (inline PackageReference + case-insensitive Include attribute).
  • Full suite: 766/766 passing.
  • scripts/build-cli.ps1 -SkipMsix -SkipNpm -SkipTests clean (an unrelated stale regen of docs/npm-usage.md came along).

nmetulev and others added 2 commits April 20, 2026 15:05
On a fresh machine, `winapp init` could hang silently for ~30s after
answering the manifest-overwrite prompt. The next step (`AskSdkInstallModeAsync`)
performed two slow network/IO operations with no visible output:

  1. `dotNetService.HasPackageReferenceAsync(csproj, "Microsoft.WindowsAppSDK")`,
     which runs `dotnet list package --format json` and triggers an implicit
     `dotnet restore` on a cold NuGet cache.
  2. `Task.WhenAll` over 6 parallel NuGet feed queries (3 modes × 2 packages)
     to label the SDK install prompt.

Both happened before any prompt or status output, and the early-exit when
the project already references WinAppSDK only logged at Debug level, so the
user saw nothing at all.

Changes:

  * `DotNetService.HasPackageReferenceAsync`: try a fast XPath-style XDocument
    scan of the csproj for an inline `<PackageReference Include="..."/>` first.
    Only positive matches short-circuit; absence still falls back to
    `dotnet list package` because Directory.Packages.props / SDK-imported
    packages aren't visible in the raw csproj.
  * `WorkspaceSetupService`: wrap the slow ops in a Spectre `Status` spinner
    (with a graceful log-line fallback when output is redirected or
    Information logging is off).
  * Promote the "project already references WinAppSDK; skipping setup" log
    from Debug to Information so the user knows why we proceeded silently.

Tests: 766/766 passing. Two new unit tests cover the XML fast path
(inline PackageReference + case-insensitive Include attribute).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WorkspaceSetupService printed 'SDK installation skipped by user choice'
whenever options.SdkInstallMode == None at the end of init. That fired
even when the .NET path auto-set it to None because the project already
references Microsoft.WindowsAppSDK, which is not a 'user choice'.

The specific reason is now logged where the decision is made:
  * AskSdkInstallModeAsync logs the auto-skip line for .NET projects
  * The interactive prompt logs 'Setup SDKs: Do not setup SDKs'
  * --setup-sdks=none is the user's own input and needs no echo

so the trailing 'by user choice' line was redundant as well as wrong.
Delete it (and the matching unreachable LogDebug for non-.NET projects).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves winapp init user experience by surfacing progress during slow SDK-detection/version lookups and by correcting misleading messaging when Windows App SDK setup is skipped.

Changes:

  • Add Spectre.Console status spinners (with fallback messaging) around slow SDK reference detection and NuGet version fetches.
  • Add a fast XML scan path for detecting inline <PackageReference /> in .csproj files before falling back to dotnet list package.
  • Remove/adjust “skipped by user choice” messaging so skip reasons aren’t misattributed.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/winapp-CLI/WinApp.Cli/Services/WorkspaceSetupService.cs Adds status spinner wrapper for long-running init steps and refines skip logging to avoid misleading output.
src/winapp-CLI/WinApp.Cli/Services/DotNetService.cs Adds a fast XML-based check for inline PackageReference to avoid slow dotnet list package on cold machines.
src/winapp-CLI/WinApp.Cli.Tests/DotNetServiceTests.cs Adds unit tests covering the new XML fast path behavior.
docs/npm-usage.md Updates npm usage docs to reflect manifest filename support text.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/winapp-CLI/WinApp.Cli/Services/DotNetService.cs
Comment thread src/winapp-CLI/WinApp.Cli/Services/WorkspaceSetupService.cs
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

Build Metrics Report

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 30.53 MB 30.65 MB 📈 +117.0 KB (+0.37%)
CLI (x64) 30.90 MB 31.01 MB 📈 +110.0 KB (+0.35%)
MSIX (ARM64) 12.89 MB 12.93 MB 📈 +33.2 KB (+0.25%)
MSIX (x64) 13.67 MB 13.73 MB 📈 +61.2 KB (+0.44%)
NPM Package 26.80 MB 26.89 MB 📈 +96.5 KB (+0.35%)
NuGet Package 26.88 MB 26.97 MB 📈 +98.0 KB (+0.36%)
VS Code Extension 19.61 MB 19.71 MB 📈 +101.2 KB (+0.50%)

Test Results

766 passed out of 766 tests in 373.0s (+2 tests, -84.8s vs. baseline)

Test Coverage

20.8% line coverage, 35.1% branch coverage · ✅ no change vs. baseline

CLI Startup Time

38ms median (x64, winapp --version) · ✅ no change vs. baseline


Updated 2026-04-20 23:43:54 UTC · commit 151919f · workflow run

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@nmetulev nmetulev merged commit 3e20de9 into main Apr 21, 2026
21 checks passed
@nmetulev nmetulev deleted the fix/issue-463-init-progress branch April 21, 2026 04:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants