Skip to content

Add winapp-pr, a helper for installing CLI MSIX builds from PRs - #697

Merged
Nikola Metulev (nmetulev) merged 5 commits into
mainfrom
nmetulev-winapp-pr-install-tool
Jul 29, 2026
Merged

Nikola Metulev (nmetulev) merged 5 commits into
mainfrom
nmetulev-winapp-pr-install-tool

Conversation

@nmetulev

Copy link
Copy Markdown
Member

Adds scripts/winapp-pr.ps1, a dev-only helper for installing winapp CLI MSIX builds produced by CI. It replaces the manual loop of finding a PR's run, downloading the artifact, unzipping, trusting a certificate, and uninstalling the previous package.

Not a shipping feature — no docs, samples, or skills were touched.

Usage

winapp-pr                                  # pick from a list of open PRs
winapp-pr 690                              # a PR
winapp-pr main                             # a branch
winapp-pr 42 -Repo contoso/winappCli-fork  # another repo (or $env:WINAPP_PR_REPO)
winapp-pr -Run 30492086396                 # an exact run
winapp-pr -List / -Status / -PruneCerts    # inspect and clean up
winapp-pr -AddToPath / -Update             # install and refresh the tool itself

Install on any machine, no clone required:

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

Behavior worth reviewing

Uninstalls before installing. All builds share the winapp-dev identity and the winapp execution alias, and version ordering across branches is arbitrary — PR 690 is 0.5.1.26 while PR 686 is 0.5.1.34. Switching PRs is therefore often a downgrade, which Add-AppxPackage rejects. Removing first sidesteps it.

Only the certificate import elevates. devcert.pfx is gitignored, so package-msix.ps1 mints a fresh self-signed CN=runneradmin certificate on every CI run, and each build needs a new TrustedPeople entry. The download stays unelevated so gh credentials in the user context still apply; elevating the whole script would lose a GH_TOKEN-based login. -PruneCerts clears the accumulation (25 had piled up on my machine), keeping the one the installed build used — tracked in a state file because WindowsApps is ACL-locked and the installed package's own certificate can't be read back.

Falls back to an earlier commit. Runs are resolved by head_sha first, then by branch, so a PR whose newest run is still in progress degrades to the previous good build rather than failing. It reports when it does. Artifacts are also uploaded on !cancelled(), so a build from a failing run is installable, with a warning.

Picker degrades gracefully. Arrow-key selection needs a real console; it falls back to a numbered prompt when stdin/stdout are redirected or cursor control throws, and fails with actionable text when there is no console input at all.

404s explain themselves. Pointing at a private repo the active gh account can't see returns a bare HTTP 404. The tool now reports which GitHub user the lookup ran as, lists other configured accounts, and suggests gh auth switch and SSO authorization.

Incidental

A leading #!/usr/bin/env pwsh suppresses PowerShell comment-based help discovery, so Get-Help returns only a syntax line. A blank line between the shebang and the help block restores it. Fixed here; other scripts in scripts/ have the same pattern and the same problem, left alone as out of scope.

Validation

Exercised end to end on ARM64 against real PR builds: PR / branch / run resolution, artifact download and per-run caching, certificate trust with elevation, uninstall and install, cross-PR downgrade, -PruneCerts, the .cmd shim, the numbered-menu fallback and its error paths, and a from-scratch web bootstrap over HTTP. -Update currently 404s by design until this lands on main.

The arrow-key loop itself could not be executed in my environment (no console handle), which is why it is wrapped to degrade rather than crash.

Dev-only selfhosting helper for switching between CI builds. Resolves a
Build and Package run from a PR number, branch name, or explicit run ID,
downloads the msix-packages artifact for the host architecture, trusts the
run's signing certificate, removes the previously installed package (they
share an app execution alias), and installs the new one.

CI mints a fresh self-signed certificate per build, so trusting it needs
admin. Only that step elevates, keeping gh credentials in the user context.

-AddToPath self-installs to the user PATH so it works from anywhere.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: db5ddd3d-7017-4d4a-9b45-d7f8dc70deaf
Running winapp-pr with no target now shows a picker of open pull requests
plus the default branch, marking the currently installed build and the
branch you are on. Previously a bare invocation silently resolved to the
current git branch, which fell back to the default branch outside a repo
and installed something unexpected.

Arrow-key selection is used on a real console and degrades to a numbered
prompt when stdin/stdout are redirected or cursor control is unavailable.
Pass -NonInteractive for the old current-branch behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: db5ddd3d-7017-4d4a-9b45-d7f8dc70deaf
Pointing winapp-pr at a private repo fails with a bare 'gh: Not Found
(HTTP 404)' when the active gh account cannot see it, which gives no hint
that the problem is account selection rather than the repo or the tool.

Report which GitHub user the lookup ran as, list the other accounts gh has
configured, and suggest gh auth switch and SSO authorization.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: db5ddd3d-7017-4d4a-9b45-d7f8dc70deaf
Installing previously required a clone, since -AddToPath copied the script
from \. When run as a scriptblock straight from the web there
is no file on disk, so capture the script's own source at script scope and
write that instead.

Adds -Update to pull the latest copy from main, since the installed copy is
a snapshot rather than a link into a repo.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: db5ddd3d-7017-4d4a-9b45-d7f8dc70deaf
Put the irm bootstrap in the script description so it is discoverable from
the file and from Get-Help.

A leading '#!/usr/bin/env pwsh' suppresses comment-based help discovery
entirely, so Get-Help returned only a syntax line. A blank line between the
shebang and the help block restores it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: db5ddd3d-7017-4d4a-9b45-d7f8dc70deaf
Copilot AI review requested due to automatic review settings July 29, 2026 22:41
@nmetulev
Nikola Metulev (nmetulev) merged commit ef1ee88 into main Jul 29, 2026
15 checks passed
@nmetulev
Nikola Metulev (nmetulev) deleted the nmetulev-winapp-pr-install-tool branch July 29, 2026 22:42

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.

Pull request overview

Adds a developer-only PowerShell helper for installing CI-built winapp MSIX packages from PRs, branches, or workflow runs.

Changes:

  • Resolves and downloads GitHub Actions MSIX artifacts.
  • Manages certificate trust, package replacement, and cleanup.
  • Supports interactive selection, caching, status, self-install, and updates.

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

Comment thread scripts/winapp-pr.ps1
Comment on lines +473 to +474
$runs = Invoke-Gh @('api', "repos/$RepoName/actions/runs?branch=$encoded&per_page=50",
'--jq', '.workflow_runs')
Comment thread scripts/winapp-pr.ps1
Comment on lines +239 to +242
$shim = @"
@echo off
where pwsh >nul 2>nul && (pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0winapp-pr.ps1" %*) || (powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0winapp-pr.ps1" %*)
"@
Comment thread scripts/winapp-pr.ps1
Comment on lines +666 to +668
# These certs all share the CI runner's subject, which is what makes them safe to bulk-remove.
$stale = Get-ChildItem Cert:\LocalMachine\TrustedPeople |
Where-Object { $_.Subject -eq 'CN=runneradmin' -and $_.Thumbprint -ne $KeepThumbprint }
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.

2 participants