Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1ba7629
Update Hex1b packages to 0.105.0
Mar 5, 2026
c82e404
Add Docker container smoke test for GA Aspire CLI install
Mar 5, 2026
5538486
Add Dockerfile-based E2E CLI test infrastructure
Mar 5, 2026
c18b140
Update Dockerfile for full AOT build with all sources
Mar 5, 2026
d68c065
Copy install scripts into Docker test container
Mar 5, 2026
f6817b8
Add Docker-based staging channel E2E test
Mar 5, 2026
77b9d23
Fix Docker E2E tests in CI: install gh CLI and forward env vars
Mar 5, 2026
c4283ec
Add Dockerfile variants and update Docker test helpers
Mar 5, 2026
14ef538
Convert all CLI E2E tests to Docker-based execution
Mar 5, 2026
6bb8404
Remove redundant Docker proof-of-concept tests
Mar 6, 2026
65f10c0
Fix Docker workspace mount and dev cert generation
Mar 6, 2026
2112c43
Fix remaining Docker E2E test failures
Mar 6, 2026
8233721
Fix DoctorCommand cert trust and TypeScript test variants
Mar 6, 2026
62254cf
Fix DoctorCommand pattern and WaitCommand timeout
Mar 6, 2026
7caa70b
Quarantine WaitCommandTests due to Docker-in-Docker timeout
Mar 6, 2026
fa672ca
Fix DeclineAgentInitPrompt to handle both CLI versions
Mar 6, 2026
4908046
Convert TypeScriptCodegenValidationTests to Docker, fix Dockerfile COPY
Mar 8, 2026
fe6df46
Address review: shared Dockerfiles, logging, convert new test
Mar 9, 2026
e4af2fd
Update Hex1b to 0.111.0 from nuget.org
Mar 10, 2026
c3e1416
Update Hex1b to 0.112.0-pr.226 preview to test Windows TTY fix
Mar 10, 2026
0e1a871
Update Hex1b packages to 0.112.0-pr.226 with WSL2 Docker TTY fix
Mar 10, 2026
c855f6d
Update Hex1b to 0.112.0-pr.226 with build timeout
Mar 10, 2026
c9f19d0
Increase container ready timeout to 120s
Mar 10, 2026
1d73faa
Revert Hex1b packages to 0.105.0
Mar 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Ignore build artifacts (will be rebuilt inside Docker)
artifacts/
.dotnet/

# IDE and editor files
.vs/
.vscode/
*.user
*.suo

# Git data (not needed for build)
.git/

# Node modules
**/node_modules/

# OS files
.DS_Store
Thumbs.db
2 changes: 1 addition & 1 deletion .vscode/mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"type": "stdio",
"command": "dnx",
"args": [
"Hex1b.McpServer@0.47.0",
"Hex1b.McpServer@0.105.0",
"--yes"
]
},
Expand Down
6 changes: 3 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@
<PackageVersion Include="Grpc.AspNetCore" Version="2.76.0" />
<PackageVersion Include="Grpc.Net.ClientFactory" Version="2.76.0" />
<PackageVersion Include="Grpc.Tools" Version="2.78.0" />
<PackageVersion Include="Hex1b" Version="0.97.0" />
<PackageVersion Include="Hex1b.McpServer" Version="0.97.0" />
<PackageVersion Include="Hex1b.Tool" Version="0.97.0" />
<PackageVersion Include="Hex1b" Version="0.105.0" />
<PackageVersion Include="Hex1b.McpServer" Version="0.105.0" />
<PackageVersion Include="Hex1b.Tool" Version="0.105.0" />
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
<PackageVersion Include="KubernetesClient" Version="18.0.13" />
<PackageVersion Include="JsonPatch.Net" Version="3.3.0" />
Expand Down
71 changes: 23 additions & 48 deletions tests/Aspire.Cli.EndToEnd.Tests/AgentCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@ public sealed class AgentCommandTests(ITestOutputHelper output)
[Fact]
public async Task AgentCommands_AllHelpOutputs_AreCorrect()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);
var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;
using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

Expand All @@ -41,14 +40,9 @@ public async Task AgentCommands_AllHelpOutputs_AreCorrect()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
sequenceBuilder.InstallAspireCliFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireCliEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

// Test 1: aspire agent --help
sequenceBuilder
Expand Down Expand Up @@ -119,18 +113,18 @@ public async Task AgentCommands_AllHelpOutputs_AreCorrect()
[Fact]
public async Task AgentInitCommand_MigratesDeprecatedConfig()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);
var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;
using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

// Use .mcp.json (Claude Code format) for simpler testing
// This is the same format used by the doctor test that passes
var configPath = Path.Combine(workspace.WorkspaceRoot.FullName, ".mcp.json");
var containerConfigPath = CliE2ETestHelpers.ToContainerPath(configPath, workspace);

// Patterns for agent init prompts - look for the colon at the end which indicates
// the prompt is ready for input
Expand All @@ -142,14 +136,9 @@ public async Task AgentInitCommand_MigratesDeprecatedConfig()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
sequenceBuilder.InstallAspireCliFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireCliEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

// Step 1: Create deprecated config file using Claude Code format (.mcp.json)
// This simulates a config that was created by an older version of the CLI
Expand All @@ -165,7 +154,7 @@ public async Task AgentInitCommand_MigratesDeprecatedConfig()
// Debug: Show that the file exists and where we are
var fileExistsPattern = new CellPatternSearcher().Find(".mcp.json");
sequenceBuilder
.Type($"ls -la {configPath} && pwd")
.Type($"ls -la {containerConfigPath} && pwd")
.Enter()
.WaitUntil(s => fileExistsPattern.Search(s).Count > 0, TimeSpan.FromSeconds(10))
.WaitForSuccessPrompt(counter);
Expand Down Expand Up @@ -200,10 +189,9 @@ public async Task AgentInitCommand_MigratesDeprecatedConfig()
.WaitForSuccessPrompt(counter);

// Debug: Show the scanner log file to diagnose what the scanner found
var debugLogPath = Path.Combine(Path.GetTempPath(), "aspire-deprecated-scan.log");
var debugLogPattern = new CellPatternSearcher().Find("Scanning context");
sequenceBuilder
.Type($"cat {debugLogPath} 2>/dev/null || echo 'No debug log found'")
.Type("cat /tmp/aspire-deprecated-scan.log 2>/dev/null || echo 'No debug log found'")
.Enter()
.WaitUntil(s => debugLogPattern.Search(s).Count > 0, TimeSpan.FromSeconds(10))
.WaitForSuccessPrompt(counter);
Expand Down Expand Up @@ -232,12 +220,11 @@ public async Task AgentInitCommand_MigratesDeprecatedConfig()
[Fact]
public async Task DoctorCommand_DetectsDeprecatedAgentConfig()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);
var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;
using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

Expand All @@ -255,14 +242,9 @@ public async Task DoctorCommand_DetectsDeprecatedAgentConfig()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
sequenceBuilder.InstallAspireCliFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireCliEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

// Create deprecated config file
sequenceBuilder
Expand Down Expand Up @@ -297,13 +279,11 @@ public async Task DoctorCommand_DetectsDeprecatedAgentConfig()
[Fact]
public async Task AgentInitCommand_DefaultSelection_InstallsSkillOnly()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);
var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;

using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

Expand All @@ -319,14 +299,9 @@ public async Task AgentInitCommand_DefaultSelection_InstallsSkillOnly()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
sequenceBuilder.InstallAspireCliFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireCliEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

// Create .vscode folder so the scanner detects VS Code environment
sequenceBuilder
Expand Down
51 changes: 15 additions & 36 deletions tests/Aspire.Cli.EndToEnd.Tests/BannerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ public sealed class BannerTests(ITestOutputHelper output)
[Fact]
public async Task Banner_DisplayedOnFirstRun()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);
var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;

using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

Expand All @@ -39,14 +37,9 @@ public async Task Banner_DisplayedOnFirstRun()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
sequenceBuilder.InstallAspireCliFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireCliEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

// Delete the first-time use sentinel file to simulate first run
// The sentinel is stored at ~/.aspire/cli/cli.firstUseSentinel
Expand Down Expand Up @@ -81,13 +74,11 @@ public async Task Banner_DisplayedOnFirstRun()
[Fact]
public async Task Banner_DisplayedWithExplicitFlag()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);
var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;

using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

Expand All @@ -104,14 +95,9 @@ public async Task Banner_DisplayedWithExplicitFlag()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
sequenceBuilder.InstallAspireCliFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireCliEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

// Clear screen to have a clean slate for pattern matching
sequenceBuilder
Expand Down Expand Up @@ -141,13 +127,11 @@ public async Task Banner_DisplayedWithExplicitFlag()
[ActiveIssue("https://github.com/dotnet/aspire/issues/14307")]
public async Task Banner_NotDisplayedWithNoLogoFlag()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);
var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;

using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

Expand All @@ -163,14 +147,9 @@ public async Task Banner_NotDisplayedWithNoLogoFlag()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
sequenceBuilder.InstallAspireCliFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireCliEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

// Delete the first-time use sentinel file to simulate first run,
// but use --nologo to suppress the banner
Expand Down
20 changes: 6 additions & 14 deletions tests/Aspire.Cli.EndToEnd.Tests/BundleSmokeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ public sealed class BundleSmokeTests(ITestOutputHelper output)
[Fact]
public async Task CreateAndRunAspireStarterProjectWithBundle()
{
var repoRoot = CliE2ETestHelpers.GetRepoRoot();
var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot);

var workspace = TemporaryWorkspace.Create(output);

var prNumber = CliE2ETestHelpers.GetRequiredPrNumber();
var commitSha = CliE2ETestHelpers.GetRequiredCommitSha();
var isCI = CliE2ETestHelpers.IsRunningInCI;
using var terminal = CliE2ETestHelpers.CreateTestTerminal();
using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal(repoRoot, installMode, output, mountDockerSocket: true, workspace: workspace);

var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken);

Expand All @@ -36,17 +36,9 @@ public async Task CreateAndRunAspireStarterProjectWithBundle()
var counter = new SequenceCounter();
var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder();

sequenceBuilder.PrepareEnvironment(workspace, counter);
sequenceBuilder.PrepareDockerEnvironment(counter, workspace);

if (isCI)
{
// Install the full bundle (not just CLI) so that ASPIRE_LAYOUT_PATH is set.
// For .NET csproj app hosts, the hosting infrastructure resolves DCP and Dashboard
// paths through NuGet assembly metadata, NOT through bundle env vars.
sequenceBuilder.InstallAspireBundleFromPullRequest(prNumber, counter);
sequenceBuilder.SourceAspireBundleEnvironment(counter);
sequenceBuilder.VerifyAspireCliVersion(commitSha, counter);
}
sequenceBuilder.InstallAspireCliInDocker(installMode, counter);

sequenceBuilder.AspireNew("BundleStarterApp", counter)
// Start AppHost in detached mode and capture JSON output
Expand Down
Loading
Loading