Skip to content

Commit 94d0d48

Browse files
committed
Centralize bundle extraction into BundleService, simplify update, update CI
- Extract IBundleService/BundleService with thread-safe extraction - Create ArchiveHelper to deduplicate extraction utilities - Simplify UpdateCommand: remove ExecuteBundleSelfUpdateAsync path - CI: upload self-extracting binary instead of directory tree - PR scripts: simplified to place binary in bin/ (lazy extraction) - Drop --archive from Bundle.proj, remove archive artifact upload - Update bundle spec with self-extracting binary architecture
1 parent 7286d4d commit 94d0d48

24 files changed

+732
-941
lines changed

.github/workflows/build-bundle.yml

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ jobs:
2121
targets:
2222
- rid: linux-x64
2323
runner: 8-core-ubuntu-latest # Larger runner for bundle disk space
24-
archive_ext: tar.gz
24+
cli_exe: aspire
2525
- rid: win-x64
2626
runner: windows-latest
27-
archive_ext: zip
27+
cli_exe: aspire.exe
2828
- rid: osx-arm64
2929
runner: macos-latest
30-
archive_ext: tar.gz
30+
cli_exe: aspire
3131

3232
steps:
3333
- name: Checkout code
@@ -89,19 +89,10 @@ jobs:
8989
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
9090
with:
9191
name: aspire-bundle-${{ matrix.targets.rid }}
92-
path: artifacts/bundle/${{ matrix.targets.rid }}
92+
path: artifacts/bundle/${{ matrix.targets.rid }}/${{ matrix.targets.cli_exe }}
9393
retention-days: 15
9494
if-no-files-found: error
9595

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-
10596
- name: Upload logs
10697
if: always()
10798
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1

.github/workflows/polyglot-validation.yml

Lines changed: 20 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -37,54 +37,11 @@ jobs:
3737
name: built-nugets-for-linux-x64
3838
path: ${{ github.workspace }}/artifacts/nugets-rid
3939

40-
- name: Debug - List all downloaded artifacts
40+
- name: Verify bundle artifact
4141
run: |
42-
echo "=== DEBUG: Full artifact tree ==="
43-
echo "Working directory: $(pwd)"
44-
echo "GITHUB_WORKSPACE: ${{ github.workspace }}"
45-
echo ""
46-
echo "=== Setting execute permissions on bundle executables ==="
47-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire || echo "aspire not found"
48-
chmod +x ${{ github.workspace }}/artifacts/bundle/runtime/dotnet || echo "dotnet not found"
49-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/aspire-nuget/aspire-nuget || echo "aspire-nuget not found"
50-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/dev-certs/aspire-dev-certs || echo "aspire-dev-certs not found"
51-
chmod +x ${{ github.workspace }}/artifacts/bundle/dashboard/aspire-dashboard || echo "Dashboard not found"
52-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire-server/aspire-server || echo "RemoteHost not found"
53-
chmod +x ${{ github.workspace }}/artifacts/bundle/dcp/dcp || echo "dcp not found"
54-
echo ""
55-
echo "=== artifacts/ directory ==="
56-
ls -la ${{ github.workspace }}/artifacts/ || echo "artifacts/ does not exist"
57-
echo ""
58-
echo "=== artifacts/bundle/ directory ==="
59-
ls -la ${{ github.workspace }}/artifacts/bundle/ || echo "artifacts/bundle/ does not exist"
60-
echo ""
61-
echo "=== artifacts/bundle/ recursive (first 3 levels) ==="
62-
find ${{ github.workspace }}/artifacts/bundle -maxdepth 3 -type f 2>/dev/null | head -50 || echo "No files found"
63-
find ${{ github.workspace }}/artifacts/bundle -maxdepth 3 -type d 2>/dev/null || echo "No directories found"
64-
echo ""
65-
echo "=== Check for aspire CLI ==="
66-
ls -la ${{ github.workspace }}/artifacts/bundle/aspire 2>/dev/null || echo "aspire CLI not found at expected path"
67-
find ${{ github.workspace }}/artifacts -name "aspire" -type f 2>/dev/null || echo "aspire CLI not found anywhere"
68-
echo ""
69-
echo "=== Check for runtime/dotnet ==="
70-
ls -la ${{ github.workspace }}/artifacts/bundle/runtime/dotnet 2>/dev/null || echo "runtime/dotnet not found at expected path"
71-
find ${{ github.workspace }}/artifacts -name "dotnet" -type f 2>/dev/null || echo "dotnet not found anywhere"
72-
echo ""
73-
echo "=== Check for key directories ==="
74-
for dir in runtime dashboard dcp aspire-server tools; do
75-
if [ -d "${{ github.workspace }}/artifacts/bundle/$dir" ]; then
76-
echo "✓ $dir/ exists"
77-
ls -la "${{ github.workspace }}/artifacts/bundle/$dir" | head -5
78-
else
79-
echo "✗ $dir/ MISSING"
80-
fi
81-
done
82-
echo ""
83-
echo "=== artifacts/nugets/ sample ==="
84-
find ${{ github.workspace }}/artifacts/nugets -name "*.nupkg" 2>/dev/null | head -10 || echo "No nupkg files found"
85-
echo ""
86-
echo "=== artifacts/nugets-rid/ sample ==="
87-
find ${{ github.workspace }}/artifacts/nugets-rid -name "*.nupkg" 2>/dev/null | head -10 || echo "No nupkg files found"
42+
echo "=== Verifying self-extracting binary ==="
43+
ls -la ${{ github.workspace }}/artifacts/bundle/aspire || { echo "ERROR: aspire binary not found"; exit 1; }
44+
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire
8845
8946
- name: Build Python validation image
9047
run: |
@@ -125,31 +82,11 @@ jobs:
12582
name: built-nugets-for-linux-x64
12683
path: ${{ github.workspace }}/artifacts/nugets-rid
12784

128-
- name: Debug - List all downloaded artifacts
85+
- name: Verify bundle artifact
12986
run: |
130-
echo "=== DEBUG: Go validation - artifact tree ==="
131-
echo "=== Setting execute permissions on bundle executables ==="
132-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire || echo "aspire not found"
133-
chmod +x ${{ github.workspace }}/artifacts/bundle/runtime/dotnet || echo "dotnet not found"
134-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/aspire-nuget/aspire-nuget || echo "aspire-nuget not found"
135-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/dev-certs/aspire-dev-certs || echo "aspire-dev-certs not found"
136-
chmod +x ${{ github.workspace }}/artifacts/bundle/dashboard/aspire-dashboard || echo "Dashboard not found"
137-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire-server/aspire-server || echo "RemoteHost not found"
138-
chmod +x ${{ github.workspace }}/artifacts/bundle/dcp/dcp || echo "dcp not found"
139-
echo ""
140-
echo "=== artifacts/bundle/ ==="
141-
ls -la ${{ github.workspace }}/artifacts/bundle/ || echo "bundle/ does not exist"
142-
echo ""
143-
echo "=== Bundle structure check ==="
144-
for dir in runtime dashboard dcp aspire-server; do
145-
if [ -d "${{ github.workspace }}/artifacts/bundle/$dir" ]; then
146-
echo "✓ $dir/"
147-
else
148-
echo "✗ $dir/ MISSING"
149-
fi
150-
done
151-
ls -la ${{ github.workspace }}/artifacts/bundle/aspire 2>/dev/null || echo "aspire CLI MISSING"
152-
ls -la ${{ github.workspace }}/artifacts/bundle/runtime/dotnet 2>/dev/null || echo "runtime/dotnet MISSING"
87+
echo "=== Verifying self-extracting binary ==="
88+
ls -la ${{ github.workspace }}/artifacts/bundle/aspire || { echo "ERROR: aspire binary not found"; exit 1; }
89+
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire
15390
15491
- name: Build Go validation image
15592
run: |
@@ -190,31 +127,11 @@ jobs:
190127
name: built-nugets-for-linux-x64
191128
path: ${{ github.workspace }}/artifacts/nugets-rid
192129

193-
- name: Debug - List all downloaded artifacts
130+
- name: Verify bundle artifact
194131
run: |
195-
echo "=== DEBUG: Java validation - artifact tree ==="
196-
echo "=== Setting execute permissions on bundle executables ==="
197-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire || echo "aspire not found"
198-
chmod +x ${{ github.workspace }}/artifacts/bundle/runtime/dotnet || echo "dotnet not found"
199-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/aspire-nuget/aspire-nuget || echo "aspire-nuget not found"
200-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/dev-certs/aspire-dev-certs || echo "aspire-dev-certs not found"
201-
chmod +x ${{ github.workspace }}/artifacts/bundle/dashboard/aspire-dashboard || echo "Dashboard not found"
202-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire-server/aspire-server || echo "RemoteHost not found"
203-
chmod +x ${{ github.workspace }}/artifacts/bundle/dcp/dcp || echo "dcp not found"
204-
echo ""
205-
echo "=== artifacts/bundle/ ==="
206-
ls -la ${{ github.workspace }}/artifacts/bundle/ || echo "bundle/ does not exist"
207-
echo ""
208-
echo "=== Bundle structure check ==="
209-
for dir in runtime dashboard dcp aspire-server; do
210-
if [ -d "${{ github.workspace }}/artifacts/bundle/$dir" ]; then
211-
echo "✓ $dir/"
212-
else
213-
echo "✗ $dir/ MISSING"
214-
fi
215-
done
216-
ls -la ${{ github.workspace }}/artifacts/bundle/aspire 2>/dev/null || echo "aspire CLI MISSING"
217-
ls -la ${{ github.workspace }}/artifacts/bundle/runtime/dotnet 2>/dev/null || echo "runtime/dotnet MISSING"
132+
echo "=== Verifying self-extracting binary ==="
133+
ls -la ${{ github.workspace }}/artifacts/bundle/aspire || { echo "ERROR: aspire binary not found"; exit 1; }
134+
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire
218135
219136
- name: Build Java validation image
220137
run: |
@@ -257,31 +174,11 @@ jobs:
257174
name: built-nugets-for-linux-x64
258175
path: ${{ github.workspace }}/artifacts/nugets-rid
259176

260-
- name: Debug - List all downloaded artifacts
177+
- name: Verify bundle artifact
261178
run: |
262-
echo "=== DEBUG: Rust validation - artifact tree ==="
263-
echo "=== Setting execute permissions on bundle executables ==="
264-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire || echo "aspire not found"
265-
chmod +x ${{ github.workspace }}/artifacts/bundle/runtime/dotnet || echo "dotnet not found"
266-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/aspire-nuget/aspire-nuget || echo "aspire-nuget not found"
267-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/dev-certs/aspire-dev-certs || echo "aspire-dev-certs not found"
268-
chmod +x ${{ github.workspace }}/artifacts/bundle/dashboard/aspire-dashboard || echo "Dashboard not found"
269-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire-server/aspire-server || echo "RemoteHost not found"
270-
chmod +x ${{ github.workspace }}/artifacts/bundle/dcp/dcp || echo "dcp not found"
271-
echo ""
272-
echo "=== artifacts/bundle/ ==="
273-
ls -la ${{ github.workspace }}/artifacts/bundle/ || echo "bundle/ does not exist"
274-
echo ""
275-
echo "=== Bundle structure check ==="
276-
for dir in runtime dashboard dcp aspire-server; do
277-
if [ -d "${{ github.workspace }}/artifacts/bundle/$dir" ]; then
278-
echo "✓ $dir/"
279-
else
280-
echo "✗ $dir/ MISSING"
281-
fi
282-
done
283-
ls -la ${{ github.workspace }}/artifacts/bundle/aspire 2>/dev/null || echo "aspire CLI MISSING"
284-
ls -la ${{ github.workspace }}/artifacts/bundle/runtime/dotnet 2>/dev/null || echo "runtime/dotnet MISSING"
179+
echo "=== Verifying self-extracting binary ==="
180+
ls -la ${{ github.workspace }}/artifacts/bundle/aspire || { echo "ERROR: aspire binary not found"; exit 1; }
181+
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire
285182
286183
- name: Build Rust validation image
287184
run: |
@@ -322,31 +219,11 @@ jobs:
322219
name: built-nugets-for-linux-x64
323220
path: ${{ github.workspace }}/artifacts/nugets-rid
324221

325-
- name: Debug - List all downloaded artifacts
222+
- name: Verify bundle artifact
326223
run: |
327-
echo "=== DEBUG: TypeScript validation - artifact tree ==="
328-
echo "=== Setting execute permissions on bundle executables ==="
329-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire || echo "aspire not found"
330-
chmod +x ${{ github.workspace }}/artifacts/bundle/runtime/dotnet || echo "dotnet not found"
331-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/aspire-nuget/aspire-nuget || echo "aspire-nuget not found"
332-
chmod +x ${{ github.workspace }}/artifacts/bundle/tools/dev-certs/aspire-dev-certs || echo "aspire-dev-certs not found"
333-
chmod +x ${{ github.workspace }}/artifacts/bundle/dashboard/aspire-dashboard || echo "Dashboard not found"
334-
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire-server/aspire-server || echo "RemoteHost not found"
335-
chmod +x ${{ github.workspace }}/artifacts/bundle/dcp/dcp || echo "dcp not found"
336-
echo ""
337-
echo "=== artifacts/bundle/ ==="
338-
ls -la ${{ github.workspace }}/artifacts/bundle/ || echo "bundle/ does not exist"
339-
echo ""
340-
echo "=== Bundle structure check ==="
341-
for dir in runtime dashboard dcp aspire-server; do
342-
if [ -d "${{ github.workspace }}/artifacts/bundle/$dir" ]; then
343-
echo "✓ $dir/"
344-
else
345-
echo "✗ $dir/ MISSING"
346-
fi
347-
done
348-
ls -la ${{ github.workspace }}/artifacts/bundle/aspire 2>/dev/null || echo "aspire CLI MISSING"
349-
ls -la ${{ github.workspace }}/artifacts/bundle/runtime/dotnet 2>/dev/null || echo "runtime/dotnet MISSING"
224+
echo "=== Verifying self-extracting binary ==="
225+
ls -la ${{ github.workspace }}/artifacts/bundle/aspire || { echo "ERROR: aspire binary not found"; exit 1; }
226+
chmod +x ${{ github.workspace }}/artifacts/bundle/aspire
350227
351228
- name: Build TypeScript validation image
352229
run: |

.github/workflows/polyglot-validation/Dockerfile.go

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# -v /var/run/docker.sock:/var/run/docker.sock \
99
# polyglot-go
1010
#
11-
# Note: Expects bundle and NuGet artifacts to be pre-downloaded to /workspace/artifacts/
11+
# Note: Expects self-extracting binary and NuGet artifacts to be pre-downloaded to /workspace/artifacts/
1212
#
1313
FROM mcr.microsoft.com/devcontainers/go:1-trixie
1414

@@ -22,8 +22,6 @@ RUN apt-get update && apt-get install -y \
2222
jq \
2323
&& rm -rf /var/lib/apt/lists/*
2424

25-
# Note: .NET SDK is NOT required - the bundle includes the .NET runtime
26-
2725
# Pre-configure Aspire CLI path
2826
ENV PATH="/root/.aspire/bin:${PATH}"
2927

@@ -33,28 +31,11 @@ COPY setup-local-cli.sh /scripts/setup-local-cli.sh
3331
COPY test-go.sh /scripts/test-go.sh
3432
RUN chmod +x /scripts/setup-local-cli.sh /scripts/test-go.sh
3533

36-
# Entrypoint: Set up Aspire CLI from bundle, enable polyglot, run validation
37-
# Note: ASPIRE_LAYOUT_PATH must be exported before running any aspire commands
34+
# Entrypoint: Set up Aspire CLI, enable polyglot, run validation
35+
# Bundle extraction happens lazily on first command that needs the layout
3836
ENTRYPOINT ["/bin/bash", "-c", "\
3937
set -e && \
40-
echo '=== ENTRYPOINT DEBUG ===' && \
41-
echo 'Starting Docker entrypoint...' && \
42-
echo 'PWD:' $(pwd) && \
43-
echo '' && \
44-
echo '=== Running setup-local-cli.sh ===' && \
4538
/scripts/setup-local-cli.sh && \
46-
echo '' && \
47-
echo '=== Post-setup: Setting ASPIRE_LAYOUT_PATH ===' && \
48-
export ASPIRE_LAYOUT_PATH=/workspace/artifacts/bundle && \
49-
echo 'ASPIRE_LAYOUT_PATH=' $ASPIRE_LAYOUT_PATH && \
50-
echo '' && \
51-
echo '=== Verifying CLI with layout path ===' && \
52-
echo 'Running: aspire --version' && \
53-
aspire --version && \
54-
echo '' && \
55-
echo '=== Enabling polyglot support ===' && \
5639
aspire config set features:polyglotSupportEnabled true --global && \
57-
echo '' && \
58-
echo '=== Running validation ===' && \
5940
/scripts/test-go.sh \
6041
"]

.github/workflows/polyglot-validation/Dockerfile.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# -v /var/run/docker.sock:/var/run/docker.sock \
99
# polyglot-java
1010
#
11-
# Note: Expects bundle and NuGet artifacts to be pre-downloaded to /workspace/artifacts/
11+
# Note: Expects self-extracting binary and NuGet artifacts to be pre-downloaded to /workspace/artifacts/
1212
#
1313
FROM mcr.microsoft.com/devcontainers/java:17
1414

@@ -22,8 +22,6 @@
2222
jq \
2323
&& rm -rf /var/lib/apt/lists/*
2424

25-
# Note: .NET SDK is NOT required - the bundle includes the .NET runtime
26-
2725
# Pre-configure Aspire CLI path
2826
ENV PATH="/root/.aspire/bin:${PATH}"
2927

@@ -33,28 +31,11 @@
3331
COPY test-java.sh /scripts/test-java.sh
3432
RUN chmod +x /scripts/setup-local-cli.sh /scripts/test-java.sh
3533

36-
# Entrypoint: Set up Aspire CLI from bundle, enable polyglot, run validation
37-
# Note: ASPIRE_LAYOUT_PATH must be exported before running any aspire commands
34+
# Entrypoint: Set up Aspire CLI, enable polyglot, run validation
35+
# Bundle extraction happens lazily on first command that needs the layout
3836
ENTRYPOINT ["/bin/bash", "-c", "\
3937
set -e && \
40-
echo '=== ENTRYPOINT DEBUG ===' && \
41-
echo 'Starting Docker entrypoint...' && \
42-
echo 'PWD:' $(pwd) && \
43-
echo '' && \
44-
echo '=== Running setup-local-cli.sh ===' && \
4538
/scripts/setup-local-cli.sh && \
46-
echo '' && \
47-
echo '=== Post-setup: Setting ASPIRE_LAYOUT_PATH ===' && \
48-
export ASPIRE_LAYOUT_PATH=/workspace/artifacts/bundle && \
49-
echo 'ASPIRE_LAYOUT_PATH=' $ASPIRE_LAYOUT_PATH && \
50-
echo '' && \
51-
echo '=== Verifying CLI with layout path ===' && \
52-
echo 'Running: aspire --version' && \
53-
aspire --version && \
54-
echo '' && \
55-
echo '=== Enabling polyglot support ===' && \
5639
aspire config set features:polyglotSupportEnabled true --global && \
57-
echo '' && \
58-
echo '=== Running validation ===' && \
5940
/scripts/test-java.sh \
6041
"]

.github/workflows/polyglot-validation/Dockerfile.python

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# -v /var/run/docker.sock:/var/run/docker.sock \
99
# polyglot-python
1010
#
11-
# Note: Expects bundle and NuGet artifacts to be pre-downloaded to /workspace/artifacts/
11+
# Note: Expects self-extracting binary and NuGet artifacts to be pre-downloaded to /workspace/artifacts/
1212
#
1313
FROM mcr.microsoft.com/devcontainers/python:3.12
1414

@@ -22,8 +22,6 @@ RUN apt-get update && apt-get install -y \
2222
jq \
2323
&& rm -rf /var/lib/apt/lists/*
2424

25-
# Note: .NET SDK is NOT required - the bundle includes the .NET runtime
26-
2725
# Install uv package manager (Python-specific)
2826
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
2927
ENV PATH="/root/.local/bin:${PATH}"
@@ -37,28 +35,11 @@ COPY setup-local-cli.sh /scripts/setup-local-cli.sh
3735
COPY test-python.sh /scripts/test-python.sh
3836
RUN chmod +x /scripts/setup-local-cli.sh /scripts/test-python.sh
3937

40-
# Entrypoint: Set up Aspire CLI from bundle, enable polyglot, run validation
41-
# Note: ASPIRE_LAYOUT_PATH must be exported before running any aspire commands
38+
# Entrypoint: Set up Aspire CLI, enable polyglot, run validation
39+
# Bundle extraction happens lazily on first command that needs the layout
4240
ENTRYPOINT ["/bin/bash", "-c", "\
4341
set -e && \
44-
echo '=== ENTRYPOINT DEBUG ===' && \
45-
echo 'Starting Docker entrypoint...' && \
46-
echo 'PWD:' $(pwd) && \
47-
echo '' && \
48-
echo '=== Running setup-local-cli.sh ===' && \
4942
/scripts/setup-local-cli.sh && \
50-
echo '' && \
51-
echo '=== Post-setup: Setting ASPIRE_LAYOUT_PATH ===' && \
52-
export ASPIRE_LAYOUT_PATH=/workspace/artifacts/bundle && \
53-
echo 'ASPIRE_LAYOUT_PATH=' $ASPIRE_LAYOUT_PATH && \
54-
echo '' && \
55-
echo '=== Verifying CLI with layout path ===' && \
56-
echo 'Running: aspire --version' && \
57-
aspire --version && \
58-
echo '' && \
59-
echo '=== Enabling polyglot support ===' && \
6043
aspire config set features:polyglotSupportEnabled true --global && \
61-
echo '' && \
62-
echo '=== Running validation ===' && \
6344
/scripts/test-python.sh \
6445
"]

0 commit comments

Comments
 (0)