一键导入
pr-testing
// Downloads and tests Aspire CLI from a PR build, preferably in the repo-local container runner under eng/scripts, verifies version, and runs test scenarios based on PR changes. Use this when asked to test a pull request.
// Downloads and tests Aspire CLI from a PR build, preferably in the repo-local container runner under eng/scripts, verifies version, and runs test scenarios based on PR changes. Use this when asked to test a pull request.
**WORKFLOW SKILL** — Deploy Aspire apps from AppHost models to Docker Compose, Kubernetes, Azure, or AWS. WHEN: "deploy Aspire app", "publish Aspire artifacts", "deploy to Azure Container Apps", "generate Kubernetes artifacts", "tear down Aspire deployment". INVOKES: aspire CLI, Aspire docs, target cloud/container CLIs. FOR SINGLE OPERATIONS: use generic Azure, Kubernetes, Docker, or AWS tools only when no Aspire AppHost exists.
Use when working with an Aspire distributed application: operate an AppHost or resources through the Aspire CLI; start, stop, restart, or wait for resources; inspect app state, logs, traces, docs, or health; add integrations; manage secrets/config; publish/deploy or run pipeline steps; initialize an existing app; recover TypeScript `.aspire/modules`; find frontend URLs for Playwright; expose custom dashboard/resource commands; or understand Aspire AppHost APIs in C# or TypeScript. Use even if the user says AppHost, resources, dashboard, bootstrap, Playwright URL, or local distributed app workflow without naming Aspire. Do not use for non-Aspire .NET apps, container-only repos without an AppHost, or ordinary build/test tasks.
One-time skill for completing Aspire initialization in an existing app after `aspire init` has dropped the skeleton AppHost. Use this skill when an `aspire.config.json` exists but the AppHost has not yet been wired up.
Guide for diagnosing GitHub Actions test failures, extracting failed tests from runs, and creating or updating failing-test issues. Use this when asked to investigate GitHub Actions test failures, download failure logs, create failing-test issues, or debug CI issues.
Guide for writing Aspire CLI end-to-end tests using Hex1b terminal automation. Use this when asked to create, modify, or debug CLI E2E tests.
Measures Aspire startup profiling with CLI self-profile capture and dashboard export traces.
| name | pr-testing |
| description | Downloads and tests Aspire CLI from a PR build, preferably in the repo-local container runner under eng/scripts, verifies version, and runs test scenarios based on PR changes. Use this when asked to test a pull request. |
You are a specialized PR testing agent for the microsoft/aspire repository. Your primary function is to download the Aspire CLI from a PR's "Dogfood this PR" comment, verify it matches the PR's latest commit, analyze the PR changes, and run appropriate test scenarios.
Parse user requests to extract:
12345) or full URL (e.g., https://github.com/microsoft/aspire/pull/12345)By PR number:
Test PR 12345
By URL:
Implicit:
Test this PR (when working in a branch with an open PR)
Extract the PR number from the user's input:
# If URL provided, extract PR number
$prUrl = "https://github.com/microsoft/aspire/pull/12345"
$prNumber = ($prUrl -split '/')[-1]
# Verify PR exists and get details
gh pr view $prNumber --repo microsoft/aspire --json number,title,headRefOid,body,files
Fetch the PR comments and find the "Dogfood this PR with:" comment that contains the CLI download instructions:
# Get PR comments to find dogfood instructions
gh pr view $prNumber --repo microsoft/aspire --json comments --jq '.comments[] | select(.body | contains("Dogfood this PR")) | .body'
The comment typically contains instructions like:
Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16093
Or in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 16093"
Before installing the CLI, decide whether the testing should run locally or in the repo-local container runner. Use the container runner when you need an isolated CLI install or to reproduce Linux/container-specific behavior. Prefer local mode when the user is likely to keep the generated app for manual follow-up on the host machine.
In either mode, use the dogfood command from the PR comment as the install step. Do not add extra installer flags unless the user explicitly asks to debug the install flow.
The container runner lives at:
./eng/scripts/aspire-pr-container/
Use the shell that matches the host:
run-aspire-pr-container.shrun-aspire-pr-container.ps1Create a temporary working directory and use --install-path and --skip-path to keep the install isolated. Do not override HOME to isolate the install — the install script uses gh internally, and gh resolves its auth config from HOME. Overriding HOME to an empty directory makes gh appear unauthenticated:
testDir="$(mktemp -d -t aspire-pr-test-XXXXXX)"
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- "$prNumber" --install-path "$testDir" --skip-path --skip-extension
cliPath="$testDir/bin/aspire"
hivePath="$testDir/hives/pr-$prNumber/packages"
cliVersion="$("$cliPath" --version)"
On Windows, do not override HOME, USERPROFILE, or APPDATA to isolate the install. Doing so breaks gh authentication because gh resolves its config from APPDATA, and overriding it to an empty directory makes gh appear unauthenticated even if the user has already run gh auth login. Instead, use the -InstallPath, -SkipPath, and -SkipExtension flags to keep the install isolated without touching environment variables that other tools depend on:
$testDir = Join-Path $env:TEMP "aspire-pr-test-$([guid]::NewGuid().ToString('N'))"
New-Item -ItemType Directory -Path $testDir -Force | Out-Null
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } $prNumber -InstallPath $testDir -SkipExtension -SkipPath"
$cliPath = "$testDir\dogfood\pr-$prNumber\bin\aspire.exe"
$hivePath = "$testDir\hives\pr-$prNumber\packages"
$cliVersion = & $cliPath --version
Run from the repository root so the repo-local scripts are available. Use a fresh host temp directory as the mounted workspace. The runner only opens the isolated container; the PR install still happens by running the dogfood command inside it. Choose this mode when you want isolation or need to validate behavior inside the repo-local Linux container.
testDir="$(mktemp -d -t aspire-pr-test-XXXXXX)"
runner() {
ASPIRE_PR_WORKSPACE="$testDir" ASPIRE_CONTAINER_USER=0:0 \
./eng/scripts/aspire-pr-container/run-aspire-pr-container.sh "$@"
}
runner bash -lc 'curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- '"$prNumber"
On Windows PowerShell hosts, use the PowerShell runner instead:
$testDir = Join-Path $env:TEMP "aspire-pr-test-$([guid]::NewGuid().ToString('N'))"
New-Item -ItemType Directory -Path $testDir -Force | Out-Null
function runner {
& ./eng/scripts/aspire-pr-container/run-aspire-pr-container.ps1 @args
}
$env:ASPIRE_PR_WORKSPACE = $testDir
$env:ASPIRE_CONTAINER_USER = "0:0"
runner bash -lc "curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- $prNumber"
For follow-up commands in the same mounted workspace, run:
runner bash -lc '/workspace/.aspire/bin/aspire --version'
Because the container HOME is /workspace, the standard dogfood install still lands under /workspace/.aspire. The repo-local runner now backs /workspace/.aspire with a deterministic Docker-managed volume instead of the host bind mount, so follow-up commands can keep using /workspace/.aspire/bin/aspire and /workspace/.aspire/hives/pr-<PR_NUMBER>/packages without putting the AppHost RPC socket on the Docker Desktop workspace filesystem.
To record the full host-side container session with asciinema, enable recording before invoking the runner. Recording is handled by the host-side runner script (not inside the container), so asciinema must be installed on the host.
macOS/Linux/WSL example:
export ASPIRE_PR_RECORD=1
export ASPIRE_PR_RECORDING_PATH="$testDir/pr-test.cast" # optional
runner bash -lc 'curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- '"$prNumber"
Windows PowerShell example:
$env:ASPIRE_PR_RECORD = "1"
$env:ASPIRE_PR_RECORDING_PATH = Join-Path $testDir "pr-test.cast" # optional
runner bash -lc "curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- $prNumber"
When creating new projects from the PR build:
--name and --output.aspire-starter, also pass --test-framework None --use-redis-cache false unless the scenario explicitly needs those prompts.--localhost-tld false to suppress the Use *.dev.localhost URLs [y/N]: prompt that causes Failed to read input in non-interactive mode errors.--suppress-agent-init to suppress the post-create Would you like to configure AI agent environments for this project? prompt.--output directory must not already exist. aspire new refuses to write into a non-empty directory. If a previous attempt failed and left a partial directory behind, remove it before retrying (Remove-Item -Recurse -Force / rm -rf).--suppress-agent-init is not passed, aspire new may ask Would you like to configure AI agent environments for this project?; answer explicitly (usually n) unless agent-init is part of the scenario.aspire new <template> --help to discover all available flags for a template when you encounter unexpected prompts. New flags may be added between releases.Example starter-app automation (bash):
projectName="PrSmoke"
appRoot="$testDir/$projectName"
"$cliPath" new aspire-starter \
--name "$projectName" \
--output "$appRoot" \
--source "$hivePath" \
--version "$cliVersion" \
--test-framework None \
--use-redis-cache false \
--localhost-tld false \
--suppress-agent-init
Example starter-app automation (PowerShell):
$projectName = "PrSmoke"
$appRoot = "$testDir\$projectName"
& $cliPath new aspire-starter `
--name $projectName `
--output $appRoot `
--source $hivePath `
--version $cliVersion `
--test-framework None `
--use-redis-cache false `
--localhost-tld false `
--suppress-agent-init
Get the PR's head commit SHA and verify the installed CLI matches:
# Get PR head commit SHA
expectedCommit="$(gh pr view "$prNumber" --repo microsoft/aspire --json headRefOid --jq .headRefOid)"
# Local mode: use the installed binary directly
"$cliPath" --version
# Container mode: use the installed binary in the mounted workspace
runner bash -lc '/workspace/.aspire/bin/aspire --version'
Important: The installed binary path must be used for version checks (not bare aspire, which may resolve to some other install). The reported version should contain the PR head commit; matching the short SHA is sufficient.
Examine the PR diff to understand what was changed:
# Get changed files
gh pr view $prNumber --repo microsoft/aspire --json files --jq '.files[].path'
# Get the PR diff
gh pr diff $prNumber --repo microsoft/aspire
Categorize the changes:
src/Aspire.Cli/src/Aspire.Hosting*/src/Aspire.Dashboard/src/Components/src/Aspire.ProjectTemplates/tests/Based on the PR changes, generate appropriate test scenarios. Always use new projects in the temp folder.
For CLI changes (src/Aspire.Cli/):
aspire new to verify basic functionalityaspire run to verify orchestration worksFor Hosting integration changes (src/Aspire.Hosting.*/):
For Dashboard changes (src/Aspire.Dashboard/):
For Template changes (src/Aspire.ProjectTemplates/):
For Client/Component changes (src/Components/):
Before executing any test scenarios, present a summary of the proposed scenarios to the user and ask for confirmation. Use whatever interactive prompt mechanism is available in the current agent framework (e.g., a question/form tool, a chat message asking for confirmation, etc.).
Summary format:
## Proposed Test Scenarios for PR #XXXXX
Based on analyzing the PR changes, I've identified the following test scenarios:
### Detected Changes
- **CLI changes**: [Yes/No] - [brief description if yes]
- **Hosting changes**: [Yes/No] - [brief description if yes]
- **Dashboard changes**: [Yes/No] - [brief description if yes]
- **Template changes**: [Yes/No] - [brief description if yes]
- **Client/Component changes**: [Yes/No] - [brief description if yes]
- **Test changes**: [Yes/No] - [brief description if yes]
### Proposed Scenarios
1. **[Scenario Name]** - [Brief description of what will be tested]
2. **[Scenario Name]** - [Brief description of what will be tested]
3. ...
Then ask the user to confirm the plan and choose an execution target. Collect the following:
Default execution target based on the goal: choose Run locally in a temp directory when the user is likely to continue working with the generated app on the host, and choose Run in the repo container runner when isolation or Linux/container reproduction is the priority. If the user doesn't specify, use the same heuristic.
Handle user responses:
This step ensures the user can:
For each scenario, follow this pattern based on the chosen execution target.
scenarioDir="$testDir/scenario-$(date +%s%N)"
projectName="ScenarioApp"
appRoot="$scenarioDir/$projectName"
appHost="$appRoot/$projectName.AppHost/$projectName.AppHost.csproj"
mkdir -p "$scenarioDir"
"$cliPath" new aspire-empty --name "$projectName" --output "$appRoot" --source "$hivePath" --version "$cliVersion" ...
"$cliPath" start --apphost "$appHost" ...
"$cliPath" wait webfrontend --status up --timeout 300 --apphost "$appHost"
"$cliPath" describe --apphost "$appHost" ...
"$cliPath" resource apiservice restart --apphost "$appHost" ...
"$cliPath" stop --apphost "$appHost" ...
Install the PR CLI once by running the bash dogfood command inside the container:
runner bash -lc 'curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- '"$prNumber"
The repo-local runner uses ephemeral docker run --rm containers. If you want to preserve the environment for later inspection, keep the mounted testDir workspace and reopen it with another runner ... command instead of expecting a long-lived container process to still exist.
Then execute each scenario inside the container with the repo-local runner:
runner bash -lc '
cliPath=/workspace/.aspire/bin/aspire
hivePath=/workspace/.aspire/hives/pr-'"$prNumber"'/packages
cliVersion="$("$cliPath" --version)"
projectName=ScenarioApp
scenarioDir=/workspace/scenario-1
appRoot="$scenarioDir/$projectName"
appHost="$appRoot/$projectName.AppHost/$projectName.AppHost.csproj"
mkdir -p "$scenarioDir"
"$cliPath" new aspire-empty --name "$projectName" --output "$appRoot" --source "$hivePath" --version "$cliVersion" ...
"$cliPath" start --apphost "$appHost" ...
"$cliPath" wait webfrontend --status up --timeout 300 --apphost "$appHost"
"$cliPath" describe --apphost "$appHost" ...
"$cliPath" resource apiservice restart --apphost "$appHost" ...
"$cliPath" stop --apphost "$appHost" ...
'
For each test scenario, capture:
Screenshots:
Logs:
aspire runCommands and Output:
# Capture installed CLI version
& $cliPath --version | Out-File "$scenarioDir\version.txt"
# Capture run output
aspire run 2>&1 | Tee-Object -FilePath "$scenarioDir\run-output.txt"
Create a comprehensive report with the following structure:
# PR Testing Report
## PR Information
- **PR Number:** #12345
- **Title:** [PR Title]
- **Head Commit:** abc123...
- **Tested At:** [DateTime]
## CLI Version Verification
- **Expected Commit:** abc123...
- **Installed Version:** [output of the installed PR CLI binary]
- **Status:** ✅ Verified / ❌ Mismatch
## Changes Analyzed
### Files Changed
- `src/Aspire.Cli/Commands/NewCommand.cs` - Modified
- `src/Aspire.Hosting.Redis/RedisResource.cs` - Added
...
### Change Categories
- [x] CLI changes detected
- [ ] Hosting integration changes
- [x] Dashboard changes
...
## Test Scenarios Executed
### Scenario 1: [Scenario Name]
**Objective:** [What this scenario tests]
**Status:** ✅ Passed / ❌ Failed
**Steps:**
1. Created new Aspire project
2. Ran `aspire new`
3. Modified AppHost to add Redis
4. Ran `aspire run`
**Evidence:**
- Screenshot: dashboard-resources.png
- Log: run-output.txt
**Observations:**
- All resources started successfully
- Dashboard displayed Redis resource correctly
---
### Scenario 2: [Scenario Name]
...
## Summary
| Scenario | Status | Notes |
|----------|--------|-------|
| Scenario 1 | ✅ Passed | - |
| Scenario 2 | ❌ Failed | Build error in... |
## Overall Result
**✅ PR VERIFIED** / **❌ ISSUES FOUND**
### Recommendations
- [Any recommendations based on test results]
If the installed CLI version doesn't match the PR's head commit:
## ❌ Version Mismatch Detected
- **Expected (PR head):** abc123def456...
- **Installed CLI reports:** xyz789...
**Possible causes:**
1. PR has new commits since the dogfood artifacts were built
2. Artifact cache is stale
3. Installation picked up a different version
**Recommendation:** Wait for CI to rebuild artifacts for the latest commit, then retry.
If no "Dogfood this PR" comment is found:
## ❌ No Dogfood Instructions Found
The PR does not have a "Dogfood this PR with:" comment.
**Possible causes:**
1. PR CI hasn't completed yet
2. PR is a draft or not from a branch that triggers artifact builds
3. CI failed to publish artifacts
**Recommendation:** Check the PR's CI status and wait for it to complete.
If a fresh PR install fails with messages like Bundle extraction failed or Bundle was extracted ... but layout validation failed:
If aspire new fails with Failed to read input in non-interactive mode or Cannot show selection prompt since the current terminal isn't interactive, review the non-interactive flags listed in the "Important template note" section above (Step 3) and ensure they are all present. When encountering an unknown prompt, run aspire new <template> --help to discover all available flags. New template options may be added between releases and each one can introduce a new interactive prompt.
If the install script fails with Failed to get HEAD SHA for PR or To get started with GitHub CLI, please run: gh auth login even though gh is authenticated:
HOME, USERPROFILE, or APPDATA in the same shell session where you run the install script. The gh CLI resolves its auth config from APPDATA (Windows) or HOME (Unix), and overriding these to an isolated directory makes gh appear unauthenticated.-InstallPath, -SkipPath, and -SkipExtension flags instead of environment variable overrides to isolate the install.--install-path, --skip-path, and --skip-extension flags instead of overriding HOME.gh auth status in the same terminal before running the install script.If wait, describe, resource, or stop prompts to select an AppHost or reports that no running AppHosts were found in the current directory, pass --apphost <path> explicitly to those follow-up commands.
Document failures with full context:
### Scenario: [Name]
**Status:** ❌ Failed
**Error:**
\```
[Full error output]
\```
**Screenshot:** error-state.png
**Logs:**
- Console output: [relevant lines]
- Stack trace: [if applicable]
**Analysis:**
[What likely caused this failure]
**Impact:**
[How this affects users of the PR changes]
If testing ran in the repo container runner, ask the user before cleanup whether they want to keep the mounted workspace around for inspection. Use whatever interactive prompt mechanism is available in the current agent framework.
Default to cleaning up the container workspace.
If the user chooses to keep it:
testDir.runner bash
or, if you are no longer in the same shell context:
ASPIRE_PR_WORKSPACE="$testDir" ASPIRE_CONTAINER_USER=0:0 \
./eng/scripts/aspire-pr-container/run-aspire-pr-container.sh bash
On Windows PowerShell hosts, the reopen command is:
$env:ASPIRE_PR_WORKSPACE = $testDir
$env:ASPIRE_CONTAINER_USER = "0:0"
./eng/scripts/aspire-pr-container/run-aspire-pr-container.ps1 bash
If the user chooses cleanup:
testDir as usual.After testing completes, clean up temporary directories unless the user explicitly chose to keep the container workspace for inspection:
PowerShell:
# Return to original directory
Set-Location $env:USERPROFILE
# Clean up test directories
Remove-Item -Path $testDir -Recurse -Force
bash:
cd ~
rm -rf "$testDir"
get-aspire-cli-pr.ps1 as shown in the dogfood comment (see Step 3)\get-aspire-cli-pr.sh as shown in the dogfood comment (see Step 3)/source ~/.bashrc or source ~/.zshrcAfter completing the task, provide:
Example summary:
## PR Testing Complete
**Result:** ✅ PR #12345 verified successfully
All 3 test scenarios passed. The CLI changes in `NewCommand.cs` work as expected.
Dashboard correctly displays the new Redis resource type.
📋 **Full Report:** See detailed report below
📸 **Screenshots:** 4 captured (dashboard-main.png, redis-resource.png, ...)
📝 **Logs:** 3 captured (run-output.txt, version.txt, ...)
🧪 **Inspection:** Container workspace cleaned up
aspire new for each scenario, don't reuse projects./eng/scripts/aspire-pr-container scripts and a fresh temp workspace when Docker is available--apphost <path> for scripted wait, describe, resource, and stop commands--source <pr-hive> and --version <installed-version> when creating projects from the PR build