Skip to content

Hide MSBuild property JSON from winapp run --aot output - #936

Merged
Zach Teutsch (zateutsch) merged 4 commits into
mainfrom
nmetulev-hide-aot-property-json
Sep 29, 2026
Merged

Zach Teutsch (zateutsch) merged 4 commits into
mainfrom
nmetulev-hide-aot-property-json

Conversation

@nmetulev

@nmetulev Nikola Metulev (nmetulev) commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Description

winapp run --aot printed MSBuild's large --getProperty result in the terminal after publishing. Winapp now passes --getResultOutputFile so MSBuild writes that result to a temporary file, which winapp reads to resolve the executable and package, then deletes. Publish output still streams live, and the JSON no longer appears.

--getResultOutputFile ships in MSBuild 17.10, so --aot now requires .NET SDK 8.0.300 or newer.

Usage Example

winapp run . --aot

Before: the publish status was followed by a large { "Properties": { ... } } block. After: normal dotnet publish progress streams live, followed by Native AOT output: ... and launch status.

Related Issue

N/A

Type of Change

  • 🐛 Bug fix
  • 📝 Documentation
  • 🧪 Test update

Checklist

  • Regression tests cover live streaming, property resolution from the result file, temp-file cleanup on success and failure, and --json/--quiet
  • Tested locally on Windows with a packaged WinUI Native AOT app
  • docs/usage.md and the winapp-setup skill updated

Screenshots / Demo

Observed output from a local packaged WinUI ARM64 run (paths abbreviated):

🔎 Resolving project...
🔎 Native AOT  ·  winui-app.csproj  ·  Debug | win-arm64
🔧 Publishing Native AOT...
  Determining projects to restore...
  All projects are up-to-date for restore.
  winui-app -> C:\…\win-arm64\winui-app.dll
  winui-app -> C:\…\win-arm64\publish\
✅ Native AOT output: C:\…\publish\winui-app.exe
Launching packaged application...
✅ winui-aot-output-demo-20260924_md30f2v49kz6j launched

Additional Notes

  • MsBuildPropertyReader is unchanged from main.
  • Local validation: 631 focused ProjectRunService/MsBuildPropertyReader/RunCommand tests passed; scripts\build-cli.ps1 -SkipTests -SkipMsix -SkipNpm -SkipNuGet succeeded. The WinUI run used a %TEMP% path containing a space, and no result file was left behind.
  • CI: build-and-package, test-samples-result, and all sample and validation jobs passed on this head.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings September 24, 2026 21:28
@nmetulev Nikola Metulev (nmetulev) added the agent-preparing Agent is addressing feedback or completing required validation and CI label Sep 24, 2026

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

The implementation is focused and the build plus 69 targeted tests passed.

Review effort: Balanced
Findings: None

What changed in this PR

Suppresses MSBuild property JSON from winapp run --aot while preserving diagnostics and property-based output resolution.

Changes:

  • Buffers publish stdout and removes only the final property envelope.
  • Preserves live stderr and other publish diagnostics.
  • Adds regression tests and updates usage documentation.
File Description
ProjectRunService.Aot.cs Filters buffered publish output.
MsBuildPropertyReader.cs Locates and removes the final property envelope.
ProjectRunServiceAotTests.cs Tests success, failure, quiet, and JSON output.
MsBuildPropertyReaderTests.cs Tests filtering and diagnostic preservation.
docs/​usage.md Documents revised AOT output behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Build Metrics Report

Validation passed. All required build and validation jobs succeeded.

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 57.29 MB 57.29 MB 📈 +6.0 KB (+0.01%)
CLI (x64) 57.33 MB 57.34 MB 📈 +5.0 KB (+0.01%)
MSIX (ARM64) 23.79 MB 23.79 MB 📈 +0.0 KB (+0.00%)
MSIX (x64) 25.26 MB 25.26 MB 📈 +0.4 KB (+0.00%)
NPM Package 49.63 MB 49.63 MB 📈 +0.6 KB (+0.00%)
NuGet Package 49.74 MB 49.74 MB 📉 -2.2 KB (-0.00%)

.NET Test Results (TRX reports)

Other suites are reflected in the overall validation status above.

✅ 7879 passed, 37 skipped out of 7916 tests in 1114.2s (-81.5s vs. baseline)

Test Coverage

✅ 86.3% line coverage, 80.9% branch coverage · ✅ no change vs. baseline

CLI Startup Time

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

Try This Build

Installs the MSIX for your architecture, replacing any previously installed build. Needs the GitHub CLI — the command offers to install it and sign you in if it is missing.

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) 936
Switching between builds often?

Put the tool on your PATH once:

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) -AddToPath

Then this build is just:

winapp-pr 936

Run winapp-pr with no arguments to pick from a list of open PRs.


Updated 2026-09-28 22:26:15 UTC · commit 34a5b5c · workflow run

@nmetulev Nikola Metulev (nmetulev) added ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge and removed agent-preparing Agent is addressing feedback or completing required validation and CI labels Sep 28, 2026

@zateutsch Zach Teutsch (zateutsch) 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.

🤖 AI-generated review (winappcli pr-review skill) — verify before acting.

Summary

The change produces correct output and CI is green, but there's a materially simpler approach that avoids both the stdout-buffering behavior change and the new offset-tracking in the shared property parser. Raising as changes requested so we can weigh it before merge.

Must fix — redirect the property JSON to a file instead of buffering stdout and cutting it out

What the PR does today: to hide MSBuild's final { "Properties": {...} } envelope, it (a) switches publish stdout from live to buffered (onOutputLine: null) and replays it after publish exits, and (b) adds character start/length tracking to the shared ScanJsonObjects / FindLastPropertiesObject so it can stdout.Remove(start, length).

Why reconsider: MSBuild can write the property result straight to a file, so neither piece is needed.

  • dotnet publish --getProperty:TargetPath --getResultOutputFile:props.json on a scratch app → stdout keeps its normal build diagnostics (Determining projects to restore… app -> …\publish\) and the property result lands in props.json, off stdout entirely.
  • With the current approach, that same stdout — including target output/warnings, which the …ShowsEarlierTargetOutput test exercises — is withheld until the publish process exits, so a multi-minute Native AOT publish can look hung.

Why it matters: using the file redirect removes a real behavior change (loss of live stdout during a long publish) and lets us delete the offset math from MsBuildPropertyReader, a helper shared by all property parsing — less surface to get wrong, for the same user-visible result.

Smallest fix: add a per-invocation --getResultOutputFile:<temp> to the AOT publish args, keep stdout+stderr streaming as before, parse properties from that file, and delete it in a finally. Then drop WithoutLastPropertiesObject, the offset parameters on ScanJsonObjects, and revert RunPublishPassAsync to the streaming call. Please confirm --getResultOutputFile is available on the project's supported SDK floor — it's MSBuild-forwarded and present in the dotnet 10 build SDK here.

Locations: src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.Aot.cs (RunPublishPassAsync) and src/winapp-CLI/WinApp.Cli/Helpers/MsBuildPropertyReader.cs.

Non-blocking — shipped setup skill says AOT output "streams live"

plugins/winapp/skills/winapp-setup/SKILL.md (Output bullet) says winapp "streams both commands' output live" in the section covering winapp run . --aot. The buffering approach makes that inaccurate for AOT publish stdout. This becomes moot if you adopt --getResultOutputFile (stdout streams live again) — in which case the reworded docs/usage.md line would also need to drop "shown after publishing completes." If you keep buffering, qualify this bullet for --aot.

What I checked

  • dotnet publish --getProperty:… [--getResultOutputFile:…] on a scratch console app (dotnet 10.0.401) — confirmed the file redirect keeps the property JSON off stdout while restoring live build diagnostics.
  • The UTF-8/UTF-16 offset math in the parser is correct for multibyte/surrogate content, so there's no correctness bug there. Security: nothing found. The one concern is the approach itself.
  • Not exercised: a full winapp binary run against a real Native AOT project (needs the AOT toolchain + a multi-minute build), so the exact magnitude of the buffering delay is inferred from the code path rather than measured.

@nmetulev Nikola Metulev (nmetulev) added agent-preparing Agent is addressing feedback or completing required validation and CI and removed ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge labels Sep 28, 2026
Address review feedback: instead of buffering publish stdout and cutting the
final --getProperty envelope out of it, pass --getResultOutputFile so MSBuild
writes the property result to a temp file. Publish output streams live again,
and the shared MsBuildPropertyReader is unchanged from main.

--getResultOutputFile ships in MSBuild 17.10, so --aot now needs .NET SDK
8.0.300 or newer; docs and the setup skill say so.

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

Copy link
Copy Markdown
Member Author

Zach Teutsch (@zateutsch) thanks, good call. Switched to --getResultOutputFile in 34a5b5c:

  • Publish stdout and stderr stream live again. The --getProperty result goes to a per-run temp file, which is read and then deleted in a finally.
  • MsBuildPropertyReader is back to main (no WithoutLastPropertiesObject, no offset tracking).
  • SDK floor: the switch landed in MSBuild 17.10 (Permit specifying output file dotnet/msbuild#9640), so it needs .NET SDK 8.0.300+, not the 8.0.100 project-mode floor. With 8.x near end of support, --aot now requires 8.0.300+; docs/usage.md and the winapp-setup skill say so.
  • The docs wording is back to "streams as it arrives", so the skill's "streams live" bullet is accurate again.

Verified with a real packaged WinUI ARM64 winapp run . --aot: normal publish progress streamed, no property JSON, app launched, and no temp file left behind (including with a %TEMP% path containing a space).

@nmetulev Nikola Metulev (nmetulev) added ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge and removed agent-preparing Agent is addressing feedback or completing required validation and CI labels Sep 28, 2026
@zateutsch
Zach Teutsch (zateutsch) merged commit bd12e40 into main Sep 29, 2026
41 checks passed
@zateutsch
Zach Teutsch (zateutsch) deleted the nmetulev-hide-aot-property-json branch September 29, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants