Skip to content

Commit a6b68c7

Browse files
Add self-contained bundle infrastructure for polyglot apphost (#14105)
* Add self-contained bundle infrastructure for polyglot AppHosts * Add --debug flag to failing E2E tests for diagnostics * Retry CI - PDB file lock was transient * Make localhive install aspire.exe * Fix local hive packages location * Hande previous local hive layout * Update clie2e test * Fix LogsCommandTests: output to terminal, add ps verification Root cause: aspire logs apiservice > logs.txt 2>&1 captured stderr (dotnet runtime warnings) and Spectre.Console spinner output instead of actual log content. The grep for [apiservice] found nothing, timing out after 10 seconds. Changes: - Add aspire ps step to verify AppHost is discoverable before logs - Output aspire logs directly to terminal instead of file redirect - Search for [apiservice] in terminal buffer (30s timeout) - Search for 'logs' key in JSON output instead of 'resourceName' - Remove intermediate file-based verification steps (wc/head/grep) - Align with PsCommandTests pattern (proven to work in CI) * Fix LogsCommandTests: don't assert on log content in snapshot mode The aspire logs command in snapshot mode (without --follow) returns empty output even when the AppHost is running and resources are producing logs. This is a known limitation of the current implementation where GetResourceLogsAsync/GetAllAsync returns no buffered logs. The test now verifies: - aspire ps finds the running AppHost (content check) - aspire logs apiservice completes successfully (exit code check) - aspire logs --format json returns valid JSON with 'logs' key (content check) - aspire stop completes successfully (content check) * Add CLI and AppHost SDK version logging to LogsCommandTests Log aspire --version and the AppHost csproj SDK version during the test for diagnostics. This helps verify whether a version mismatch between the CLI and AppHost is causing empty logs output. * Add diagnostic logging to aspire logs pipeline and E2E test * Upgrade diagnostic logging to Information level for AppHost log visibility * Add stderr diagnostics in ResourceLoggerState.GetAllAsync to trace console logs path * Fix LogsCommandTests: increase template search timeout, remove diagnostic logging * Add file-based diagnostics to trace empty aspire logs root cause * Fix aspire logs returning empty output DCP-sourced logs were only stored in the backlog when Dashboard subscribers were actively watching the resource. Without subscribers, AddLog silently dropped DCP logs, and GetAllAsync could not retrieve them since DCP snapshot streams return empty when a follow-mode stream is already consuming logs. Fix: Always store all log entries (both DCP and in-memory) in the backlog regardless of subscriber status. This ensures aspire logs can retrieve accumulated logs at any time. The WatchAsync replay of in-memory entries on first subscription is no longer needed since the backlog already contains everything. * Restore log content assertions in LogsCommandTests * Add diagnostic logging to trace empty aspire logs on CI TEMP: File-based diagnostic logging at three key points: - RPC target: resource name, resolved names, logger keys - ResourceLoggerState.GetAllAsync: backlog count, in-memory count - DcpExecutor.GetAllLogsAsync: resource map keys, lookup result The test dumps these diag files from /tmp after running aspire logs. This logging will be removed once the root cause is identified. * TEMP: Disable unrelated CI jobs, keep only CLI E2E tests Speeds up inner loop for debugging LogsCommandTests. Disabled: integrations, templates, endtoend, polyglot, extension tests. Disabled: macOS and Windows setup jobs. Will be reverted once LogsCommandTests is fixed. * Fix aspire logs: temporarily subscribe to trigger DCP log stream When GetAllAsync finds an empty backlog, it means no subscriber has triggered StartLogStream in DCP yet. Fix by temporarily subscribing to the OnNewLog event (which triggers SubscribersChanged -> StartLogStream), waiting 5s for log entries to arrive, then returning collected entries. This ensures 'aspire logs' works in snapshot mode even when no dashboard or other viewer has opened the resource's console logs. * Add more diag logging, wait 30s before logs, add unfiltered logs call, WatchAsync fallback fix * Switch logs test to webfrontend (apiservice has no console output), keep diag logging * Add direct dotnet run diag + ResourceLogSource stream-level diag for apiservice * Add fd comparison and DCP log dir diagnostics for apiservice vs webfrontend * Fix aspire logs for executables: always start log streams, revert diagnostics DCP does not reliably serve executable logs via snapshot (follow=false) requests. Fix by always starting follow-mode log streams for executables when logs become available, regardless of subscriber state. This populates the backlog so snapshot reads return data. Also add a WatchAsync fallback in GetAllAsync as a safety net: if no logs are found from the backlog or DCP snapshot, temporarily subscribe to trigger the log stream and collect whatever arrives within 10 seconds. Revert all temporary CI workflow changes and diagnostic logging. * Add resource status and dashboard diagnostics to LogsCommandTests * Fix dashboard binary name mismatch, revert DcpExecutor/ResourceLoggerService workarounds The AssemblyName change to 'aspire-dashboard' in Aspire.Dashboard.csproj renamed the output binary, but three MSBuild files still referenced the old name 'Aspire.Dashboard'. On Linux (case-sensitive), the dashboard failed to launch, which prevented DCP from capturing executable logs. Updated: - eng/dashboardpack/Sdk.targets - eng/dashboardpack/UnixFilePermissions.xml - src/Aspire.Hosting.AppHost/build/Aspire.Hosting.AppHost.in.targets Reverted the DcpExecutor and ResourceLoggerService workarounds as they are no longer needed with the dashboard launching correctly. * Restore build_bundle job in tests.yml for polyglot validation The build_bundle job was lost when tests.yml was reverted to main during debugging. The polyglot validation workflow requires the aspire-bundle artifact which is produced by build-bundle.yml. * Centralize dashboard binary name into single MSBuild property Define AspireDashboardBinaryName in Directory.Build.props as the single source of truth. Use it in the Dashboard csproj and AppHost.in.targets. Add comments to NuGet-shipped files (Sdk.targets, UnixFilePermissions.xml) and BundleDiscovery.cs pointing to the source of truth. Add EnsureDashboardBinaryNameIsConsistentAcrossFiles test that validates all 5 files reference the same binary name, preventing the silent name mismatch that caused the LogsCommandTests CI failure. * Fix EnsureDashboardBinaryNameIsConsistentAcrossFiles assertion The DoesNotContain assertion was too broad - searching for 'aspire-dashboard') matched unrelated content in the targets file. Narrowed it to check specifically that NormalizePath doesn't use a hardcoded name. * Remove DotNetSdkBasedAppHostServerProject and merge DevAppHostServerProject into base class - Delete DotNetSdkBasedAppHostServerProject (SDK-based package reference mode) - Merge DevAppHostServerProject into DotNetBasedAppHostServerProject (now sealed) - Update AppHostServerProjectFactory to remove SDK fallback path - Remove SDK-specific tests and snapshot - Update stale comments in PrebuiltAppHostServer * Remove unused sdkVersion parameter from CreateProjectFilesAsync * Auto-detect Aspire repo root and improve factory fallback - Priority 1: Dev mode if ASPIRE_REPO_ROOT is set or CLI runs from Aspire source repo (detected via .git + Aspire.slnx) - Priority 2: PrebuiltAppHostServer if bundle layout is available - Fallback: Throw explaining both options are needed * Import repo Directory.Packages.props and fix dashboard binary name - Generate Directory.Packages.props in project model path that imports the repo's central package management, enabling version-less PackageReferences - Remove hardcoded StreamJsonRpc/Google.Protobuf versions (now from CPM) - Add AspireDashboardBinaryName property to fix empty dashboard DLL path * Revert dashboard assembly name changes, set ASPNETCORE_ENVIRONMENT=Development in dev mode Revert all changes that renamed the dashboard binary from Aspire.Dashboard to aspire-dashboard. The assembly name returns to its default (project name). Set ASPNETCORE_ENVIRONMENT=Development on the AppHost server process in dev mode so the dashboard can resolve static web assets from the debug build via the .staticwebassets.runtime.json manifest. * Fix dashboard startup in bundle mode for .NET csproj app hosts Remove ConfigureLayoutEnvironment from DotNetAppHostProject. .NET csproj app hosts resolve DCP and Dashboard paths through NuGet assembly metadata, so setting ASPIRE_DASHBOARD_PATH/ASPIRE_DCP_PATH env vars from the bundle layout is unnecessary and was causing the dashboard to fail (the env var pointed to a directory, but the hosting code expected an executable path). Polyglot/guest app hosts (PrebuiltAppHostServer) still correctly set these env vars since they don't have NuGet packages. Add BundleSmokeTests E2E test that creates a starter app with the full bundle installed and verifies the dashboard is actually reachable via curl (not just that the URL appears on screen). * Install bundle to ~/.aspire instead of ~/.aspire/bundle Align PR bundle install scripts with the release install script layout. The CLI binary and all components (runtime, dashboard, dcp, aspire-server) are siblings in ~/.aspire/, so auto-discovery works without needing ASPIRE_LAYOUT_PATH. This also avoids conflicts with the CLI-only install at ~/.aspire/bin/. * Use aspire CLI commands in BundleSmokeTests instead of grep - Use 'aspire ps --format json' for dashboard URL extraction instead of grep -oP which is not available on macOS (BSD grep lacks -P flag) - Use 'aspire stop' for graceful cleanup instead of manual PID management - Add -L to curl to follow 302 redirect from dashboard base URL * Fix NullReferenceException in ResourceSnapshotMapper when collection properties are null When resource snapshots are deserialized from the backchannel RPC, collection properties (Urls, Volumes, HealthReports, EnvironmentVariables, Properties, Relationships, Commands) can be null despite having default values in the class definition. This caused 'aspire resources --format Json' to throw a NullReferenceException. Add null-coalescing (?? []) to all collection property accesses in MapToResourceJson() and a null-check before calling ResourceSource.GetSourceModel() with Properties. * Fix 'aspire new' with --non-interactive failing for templates with prompts GetTemplates() did not pass the nonInteractive flag to GetTemplatesCore(), so templates like aspire-apphost-singlefile always used the interactive code path with prompts. When --non-interactive was set, the prompt methods threw InvalidOperationException ('Interactive input is not supported'). Inject ICliHostEnvironment into DotNetTemplateFactory and derive the GetTemplates(). * Move bundle CLI to bin/ subdir for consistent install path - LayoutDiscovery.TryDiscoverRelativeLayout() now checks parent dir for bundle components (CLI at bin/aspire, components at ../) - Bundle install scripts move CLI to bin/ after extraction - PATH uses ~/.aspire/bin (same as CLI-only install) * Fix bundle script CDN caching: use commit SHA instead of branch ref The install script is fetched from raw.githubusercontent.com which has CDN caching. Using the branch ref can serve stale content after a push. Use .head.sha instead of .head.ref to ensure the latest script is used. Also add both ~/.aspire/bin and ~/.aspire to PATH for backwards compatibility during the transition. * Add diagnostics to BundleSmokeTests for dashboardUrl:null debugging * Fix bundle install: set PR channel for template version compatibility The bundle install script was not setting the global channel to 'pr-{N}', unlike the CLI-only install script. This caused 'aspire new' to use stable 13.1.0 templates which lack GetDashboardUrlsAsync RPC method, resulting in dashboardUrl:null in detach mode. Also removes diagnostic output from BundleSmokeTests. * Add NuGet hive install to bundle scripts for PR template compatibility The bundle install scripts were missing NuGet hive package installation, which the CLI-only install scripts already do. Without the hive, setting channel to 'pr-{N}' fails because the PR channel packages don't exist. Now both bash and PowerShell bundle scripts download built-nugets and built-nugets-for-{rid} artifacts and install them to the hive directory at ~/.aspire/hives/pr-{N}/packages, matching the CLI-only behavior. * Extract XML doc files alongside DLLs in NuGetHelper LayoutCommand When creating the flat DLL layout for the AppHost server, also copy the .xml documentation file for each runtime assembly if it exists. This enables IntelliSense and MCP context for polyglot AppHosts. * Unquarantine TypeScriptPolyglotTests * Update bundle spec and fix TypeScriptPolyglotTests version selection - Update docs/specs/bundle.md to reflect current install layout (~/.aspire/bin/ + sibling components) - Fix TypeScriptPolyglotTests: navigate down to pr-{N} channel in aspire add version prompt * Clean up: use IConfiguration in AssemblyLoader, remove IL3000 suppression, remove debug flags from E2E tests * Restore IL3000 suppression - needed for single-file bundle publish * Make PrebuiltAppHostServer channel-aware - Resolve configured channel (local settings.json → global config fallback) - Filter NuGet sources to resolved channel instead of all explicit channels - Return channel name in PrepareResult so it flows to settings.json - Remove DownArrow workaround in TypeScriptPolyglotTests (channel auto-resolves) * Fix TypeScriptPolyglotTests: accept version prompt after channel auto-resolve * Fix TypeScriptPolyglotTests: wait for version string, not prompt title Spectre.Console briefly renders the channel name before redrawing with the actual version. Waiting for the prompt title caused Enter to be sent during the redraw window, where it was swallowed. Instead, wait for the version string (e.g. 'pr.14105') which only appears after the prompt is fully rendered. * Add delay before Enter on version prompt in TypeScriptPolyglotTests Spectre.Console selection prompts need a brief delay after rendering before they accept input. Without this, Enter is sent before the prompt's input handler is ready and gets discarded. This follows the same pattern used in AgentCommandTests. * Auto-select single-item version prompts in aspire add When the version selection has only one channel or one version, auto-select it instead of showing a single-item Spectre prompt. This improves UX and fixes the flaky TypeScript E2E test where two back-to-back single-item prompts caused Enter to be lost. * Remove accidentally committed cast file * Remove debug artifacts from CI investigation * Fix inaccurate README content for CreateLayout and install scripts - Fix option name: --version → --bundle-version - Fix example version: 9.2.0 → 13.2.0 - Fix build script syntax: build.sh --restore --build -bundle → build.sh -bundle - Fix package sizes: CLI ~25 MB, bundle ~200 MB compressed - Fix runtime download: actually downloads SDK, extracts runtimes + dev-certs - Fix output structure: remove incorrect DLL names, add dotnet muxer - Remove overly specific internal file names from layout diagram --------- Co-authored-by: Sebastien Ros <sebastienros@gmail.com>
1 parent 159854b commit a6b68c7

File tree

121 files changed

+12880
-1591
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+12880
-1591
lines changed
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
---
2+
name: ci-test-failures
3+
description: Guide for diagnosing and fixing CI test failures using the DownloadFailingJobLogs tool. Use this when asked to investigate GitHub Actions test failures, download failure logs, or debug CI issues.
4+
---
5+
6+
# CI Test Failure Diagnosis
7+
8+
This skill provides patterns and practices for diagnosing GitHub Actions test failures in the Aspire repository using the `DownloadFailingJobLogs` tool.
9+
10+
## Overview
11+
12+
When CI tests fail, use the `DownloadFailingJobLogs.cs` tool to automatically download logs and artifacts for failed jobs. This tool eliminates manual log hunting and provides structured access to test failures.
13+
14+
**Location**: `tools/scripts/DownloadFailingJobLogs.cs`
15+
16+
## Quick Start
17+
18+
### Step 1: Find the Run ID
19+
20+
Get the run ID from the GitHub Actions URL or use the `gh` CLI:
21+
22+
```bash
23+
# From URL: https://github.com/dotnet/aspire/actions/runs/19846215629
24+
# ^^^^^^^^^^
25+
# run ID
26+
27+
# Or find the latest run on a branch
28+
gh run list --repo dotnet/aspire --branch <branch-name> --limit 1 --json databaseId --jq '.[0].databaseId'
29+
30+
# Or for a PR
31+
gh pr checks <pr-number> --repo dotnet/aspire
32+
```
33+
34+
### Step 2: Run the Tool
35+
36+
```bash
37+
cd tools/scripts
38+
dotnet run DownloadFailingJobLogs.cs -- <run-id>
39+
```
40+
41+
**Example:**
42+
```bash
43+
dotnet run DownloadFailingJobLogs.cs -- 19846215629
44+
```
45+
46+
### Step 3: Analyze Output
47+
48+
The tool creates files in your current directory:
49+
50+
| File Pattern | Contents |
51+
|--------------|----------|
52+
| `failed_job_<n>_<job-name>.log` | Raw job logs from GitHub Actions |
53+
| `artifact_<n>_<testname>_<os>.zip` | Downloaded artifact zip files |
54+
| `artifact_<n>_<testname>_<os>/` | Extracted directory with .trx files, logs, binlogs |
55+
56+
## What the Tool Does
57+
58+
1. **Finds all failed jobs** in a GitHub Actions workflow run
59+
2. **Downloads job logs** for each failed job
60+
3. **Extracts test failures and errors** from logs using regex patterns
61+
4. **Determines artifact names** from job names (pattern: `logs-{testShortName}-{os}`)
62+
5. **Downloads test artifacts** containing .trx files and test logs
63+
6. **Extracts artifacts** to local directories for inspection
64+
65+
## Example Workflow
66+
67+
```bash
68+
# 1. Check failed jobs on a PR
69+
gh pr checks 14105 --repo dotnet/aspire 2>&1 | Where-Object { $_ -match "fail" }
70+
71+
# 2. Get the run ID
72+
$runId = gh run list --repo dotnet/aspire --branch davidfowl/my-branch --limit 1 --json databaseId --jq '.[0].databaseId'
73+
74+
# 3. Download failure logs
75+
cd tools/scripts
76+
dotnet run DownloadFailingJobLogs.cs -- $runId
77+
78+
# 4. Search for errors in downloaded logs
79+
Get-Content "failed_job_0_*.log" | Select-String -Pattern "error|Error:" -Context 2,3 | Select-Object -First 20
80+
81+
# 5. Check .trx files for test failures
82+
Get-ChildItem -Recurse -Filter "*.trx" | ForEach-Object {
83+
[xml]$xml = Get-Content $_.FullName
84+
$xml.TestRun.Results.UnitTestResult | Where-Object { $_.outcome -eq "Failed" }
85+
}
86+
```
87+
88+
## Understanding Job Log Output
89+
90+
The tool prints a summary for each failed job:
91+
92+
```
93+
=== Failed Job 1/1 ===
94+
Name: Tests / Integrations macos (Hosting.Azure) / Hosting.Azure (macos-latest)
95+
ID: 56864254427
96+
URL: https://github.com/dotnet/aspire/actions/runs/19846215629/job/56864254427
97+
Downloading job logs...
98+
Saved job logs to: failed_job_0_Tests___Integrations_macos__Hosting_Azure____Hosting_Azure__macos-latest_.log
99+
100+
Errors found (2):
101+
- System.InvalidOperationException: Step 'provision-api-service' failed...
102+
```
103+
104+
## Searching Downloaded Logs
105+
106+
### Find Errors in Job Logs
107+
108+
```powershell
109+
# PowerShell
110+
Get-Content "failed_job_*.log" | Select-String -Pattern "error|Error:" -Context 2,3
111+
112+
# Bash
113+
grep -i "error" failed_job_*.log | head -50
114+
```
115+
116+
### Find Build Failures
117+
118+
```powershell
119+
Get-Content "failed_job_*.log" | Select-String -Pattern "Build FAILED|error MSB|error CS"
120+
```
121+
122+
### Find Test Failures
123+
124+
```powershell
125+
Get-Content "failed_job_*.log" | Select-String -Pattern "Failed!" -Context 5,0
126+
```
127+
128+
### Check for Disk Space Issues
129+
130+
```powershell
131+
Get-Content "failed_job_*.log" | Select-String -Pattern "No space left|disk space"
132+
```
133+
134+
### Check for Timeout Issues
135+
136+
```powershell
137+
Get-Content "failed_job_*.log" | Select-String -Pattern "timeout|timed out|Timeout"
138+
```
139+
140+
## Using GitHub API for Annotations
141+
142+
Sometimes job logs aren't available (404). Use annotations instead:
143+
144+
```bash
145+
gh api repos/dotnet/aspire/check-runs/<job-id>/annotations
146+
```
147+
148+
This returns structured error information even when full logs aren't downloadable.
149+
150+
## Common Failure Patterns
151+
152+
### Disk Space Exhaustion
153+
154+
**Symptom:** `No space left on device` in annotations or logs
155+
156+
**Diagnosis:**
157+
```powershell
158+
gh api repos/dotnet/aspire/check-runs/<job-id>/annotations 2>&1
159+
```
160+
161+
**Common fixes:**
162+
- Add disk cleanup step before build
163+
- Use larger runner (e.g., `8-core-ubuntu-latest`)
164+
- Skip unnecessary build steps (e.g., `/p:BuildTests=false`)
165+
166+
### Command Not Found
167+
168+
**Symptom:** `exit code 127` or `command not found`
169+
170+
**Diagnosis:**
171+
```powershell
172+
Get-Content "failed_job_*.log" | Select-String -Pattern "command not found|exit code 127" -Context 3,1
173+
```
174+
175+
**Common fixes:**
176+
- Ensure PATH includes required tools
177+
- Use full path to executables
178+
- Install missing dependencies
179+
180+
### Test Timeout
181+
182+
**Symptom:** Test hangs, then fails with timeout
183+
184+
**Diagnosis:**
185+
```powershell
186+
Get-Content "failed_job_*.log" | Select-String -Pattern "Test host process exited|Timeout|timed out"
187+
```
188+
189+
**Common fixes:**
190+
- Increase test timeout
191+
- Check for deadlocks in test code
192+
- Review Heartbeat.cs output for resource exhaustion
193+
194+
### Build Failure
195+
196+
**Symptom:** `Build FAILED` or MSBuild errors
197+
198+
**Diagnosis:**
199+
```powershell
200+
Get-Content "failed_job_*.log" | Select-String -Pattern "error CS|error MSB|Build FAILED" -Context 0,3
201+
```
202+
203+
**Common fixes:**
204+
- Check for missing project references
205+
- Verify package versions
206+
- Download and analyze .binlog from artifacts
207+
208+
## Artifact Contents
209+
210+
Downloaded artifacts typically contain:
211+
212+
```
213+
artifact_0_TestName_os/
214+
├── testresults/
215+
│ ├── TestName_net10.0_timestamp.trx # Test results XML
216+
│ ├── Aspire.*.Tests_*.log # Console output
217+
│ └── recordings/ # Asciinema recordings (CLI E2E tests)
218+
├── *.crash.dmp # Crash dump (if test crashed)
219+
└── test.binlog # MSBuild binary log
220+
```
221+
222+
## Parsing .trx Files
223+
224+
```powershell
225+
# Find all failed tests in .trx files
226+
Get-ChildItem -Path "artifact_*" -Recurse -Filter "*.trx" | ForEach-Object {
227+
Write-Host "=== $($_.Name) ==="
228+
[xml]$xml = Get-Content $_.FullName
229+
$xml.TestRun.Results.UnitTestResult | Where-Object { $_.outcome -eq "Failed" } | ForEach-Object {
230+
Write-Host "FAILED: $($_.testName)"
231+
Write-Host $_.Output.ErrorInfo.Message
232+
Write-Host "---"
233+
}
234+
}
235+
```
236+
237+
## Tips
238+
239+
### Clean Up Before Running
240+
241+
```powershell
242+
Remove-Item *.log -Force -ErrorAction SilentlyContinue
243+
Remove-Item *.zip -Force -ErrorAction SilentlyContinue
244+
Remove-Item -Recurse artifact_* -Force -ErrorAction SilentlyContinue
245+
```
246+
247+
### Run From tools/scripts Directory
248+
249+
The tool creates files in the current directory, so run it from `tools/scripts` to keep things organized:
250+
251+
```bash
252+
cd tools/scripts
253+
dotnet run DownloadFailingJobLogs.cs -- <run-id>
254+
```
255+
256+
### Don't Commit Log Files
257+
258+
The downloaded log files can be large. Don't commit them to the repository:
259+
260+
```bash
261+
# Before committing
262+
rm tools/scripts/*.log
263+
rm tools/scripts/*.zip
264+
rm -rf tools/scripts/artifact_*
265+
```
266+
267+
## Prerequisites
268+
269+
- .NET 10 SDK or later
270+
- GitHub CLI (`gh`) installed and authenticated
271+
- Access to the dotnet/aspire repository
272+
273+
## See Also
274+
275+
- `tools/scripts/README.md` - Full documentation
276+
- `tools/scripts/Heartbeat.cs` - System monitoring tool for diagnosing hangs
277+
- `.github/skills/cli-e2e-testing/SKILL.md` - CLI E2E test troubleshooting

.github/workflows/build-bundle.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
name: Build Bundle (Reusable)
2+
3+
# This workflow creates the Aspire CLI bundle by:
4+
# 1. Downloading the native CLI from the CLI archives workflow
5+
# 2. Building/publishing managed components (Dashboard, NuGetHelper, AppHostServer)
6+
# 3. Assembling everything into a bundle using CreateLayout
7+
8+
on:
9+
workflow_call:
10+
inputs:
11+
versionOverrideArg:
12+
required: false
13+
type: string
14+
15+
jobs:
16+
build_bundle:
17+
name: Build bundle (${{ matrix.targets.rid }})
18+
runs-on: ${{ matrix.targets.runner }}
19+
strategy:
20+
matrix:
21+
targets:
22+
- rid: linux-x64
23+
runner: 8-core-ubuntu-latest # Larger runner for bundle disk space
24+
archive_ext: tar.gz
25+
- rid: win-x64
26+
runner: windows-latest
27+
archive_ext: zip
28+
- rid: osx-arm64
29+
runner: macos-latest
30+
archive_ext: tar.gz
31+
32+
steps:
33+
- name: Checkout code
34+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
35+
36+
# Download CLI archive from previous workflow - this avoids rebuilding native CLI
37+
- name: Download CLI archive
38+
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
39+
with:
40+
name: cli-native-archives-${{ matrix.targets.rid }}
41+
path: artifacts/packages
42+
43+
# Download RID-specific NuGet packages (for DCP)
44+
- name: Download RID-specific NuGets
45+
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
46+
with:
47+
name: built-nugets-for-${{ matrix.targets.rid }}
48+
path: artifacts/packages/Release/Shipping
49+
50+
# Extract CLI archive to expected location so CreateLayout can find it
51+
- name: Extract CLI archive
52+
shell: pwsh
53+
run: |
54+
$rid = "${{ matrix.targets.rid }}"
55+
$ext = if ($rid -eq "win-x64") { "zip" } else { "tar.gz" }
56+
$destDir = "artifacts/bin/Aspire.Cli/Release/net10.0/$rid/native"
57+
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
58+
59+
$archive = Get-ChildItem -Path artifacts/packages -Recurse -Filter "aspire-cli-$rid-*.$ext" | Select-Object -First 1
60+
if (-not $archive) {
61+
Write-Error "CLI archive not found for $rid"
62+
exit 1
63+
}
64+
Write-Host "Extracting $($archive.FullName) to $destDir"
65+
66+
if ($ext -eq "zip") {
67+
Expand-Archive -Path $archive.FullName -DestinationPath $destDir -Force
68+
} else {
69+
tar -xzf $archive.FullName -C $destDir
70+
}
71+
Get-ChildItem $destDir
72+
73+
# Build bundle directly via MSBuild - skips native CLI build, uses pre-extracted CLI
74+
- name: Build bundle
75+
shell: pwsh
76+
run: |
77+
$dotnetCmd = if ($IsWindows) { "./dotnet.cmd" } else { "./dotnet.sh" }
78+
& $dotnetCmd msbuild eng/Bundle.proj `
79+
/restore `
80+
/p:Configuration=Release `
81+
/p:TargetRid=${{ matrix.targets.rid }} `
82+
/p:SkipNativeBuild=true `
83+
/p:ContinuousIntegrationBuild=true `
84+
/bl:${{ github.workspace }}/artifacts/log/Release/Bundle.binlog `
85+
${{ inputs.versionOverrideArg }}
86+
87+
- name: Upload bundle
88+
if: success()
89+
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
90+
with:
91+
name: aspire-bundle-${{ matrix.targets.rid }}
92+
path: artifacts/bundle/${{ matrix.targets.rid }}
93+
retention-days: 15
94+
if-no-files-found: error
95+
96+
- name: Upload bundle archive
97+
if: success()
98+
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
99+
with:
100+
name: aspire-bundle-archive-${{ matrix.targets.rid }}
101+
path: artifacts/bundle/*.${{ matrix.targets.archive_ext }}
102+
retention-days: 15
103+
if-no-files-found: warn
104+
105+
- name: Upload logs
106+
if: always()
107+
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
108+
with:
109+
name: bundle-logs-${{ matrix.targets.rid }}
110+
path: artifacts/log/**

0 commit comments

Comments
 (0)