Skip to content

Mirror deployment E2E summary in CLI E2E recording comment#17154

Merged
mitchdenny merged 7 commits into
mainfrom
mitchdenny/cli-e2e-test-summary
May 16, 2026
Merged

Mirror deployment E2E summary in CLI E2E recording comment#17154
mitchdenny merged 7 commits into
mainfrom
mitchdenny/cli-e2e-test-summary

Conversation

@mitchdenny
Copy link
Copy Markdown
Member

Description

Update the CLI E2E recording PR comment so the headline mirrors the Deployment E2E Tests comment style, surfacing an explicit pass/fail breakdown instead of just a recording count.

Before: ❌ **CLI E2E Test Recordings** — 2 test(s) failed, 12 recordings uploaded

After: ❌ **CLI E2E Tests failed** — 10 passed, 2 failed

The TRX-derived outcome map is already being computed; this change just tallies the Passed and Unknown buckets alongside the existing Failed count and uses them to build a summary in the same shape as deployment-tests.yml. Recording-upload failures continue to be flagged in the table and are now appended in parentheses to the headline (e.g. ... (11/12 recordings uploaded, 1 upload(s) failed)) rather than overriding the test status, since upload glitches are unrelated to test correctness. When no TRX outcomes are available the comment falls back to the existing 🎬 ... completed wording.

Fixes # (issue)

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 16, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17154

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17154"

@mitchdenny mitchdenny marked this pull request as ready for review May 16, 2026 02:27
Copilot AI review requested due to automatic review settings May 16, 2026 02:27
Mitch Denny and others added 4 commits May 16, 2026 12:28
Update the CLI E2E recording PR comment to surface a passed/failed
breakdown in the same style as the Deployment E2E Tests comment, e.g.
"✅ **CLI E2E Tests passed** — 12 passed, 0 failed".

Counts are derived from the TRX outcomes that are already parsed,
adding explicit pass and unknown tallies alongside the existing fail
count. Recording upload failures stay surfaced but no longer drive the
headline status, since they are unrelated to test correctness.

Co-authored-by: Copilot <[email protected]>
Surface the test outcome on the recording link itself, not only in the
table's Status column, so a URL pulled out of the table still tells a
reader whether it represents a pass or a failure. Failed recordings get
"❌ ▶️ View failure recording", passes get "✅ ▶️ View recording",
and unknowns keep "❔".

Co-authored-by: Copilot <[email protected]>
Adds a pr_number input to the manual trigger so the workflow can be
exercised against a chosen PR's artifacts without depending on the open
head-SHA lookup, which is needed to test changes to this workflow
before they reach main.

Co-authored-by: Copilot <[email protected]>
The previous yq query used jq-style 'if type == "!!seq"' which the Go
yq lexer rejects, so test_outcomes.json was always empty and every
recording showed as Unknown. The step had continue-on-error: true, so
the failure stayed silent until the new pass/fail summary surfaced it.

Convert TRX to JSON with yq -p xml -o json, then do all reshaping in jq
where it handles single-vs-array UnitTestResult shapes correctly. yq
also emits attributes as '+@<attr>' (newer) or '@<attr>' (older), so the
lookup tries both forms.

Co-authored-by: Copilot <[email protected]>
@mitchdenny mitchdenny force-pushed the mitchdenny/cli-e2e-test-summary branch from f05275d to a82dc76 Compare May 16, 2026 02:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Aligns the CLI E2E recording comment headline with the deployment E2E comment style (explicit pass/fail counts) and adds a more reliable test-outcome attribution mechanism via a .cast.outcome sidecar file written by a new EmitRecordingOutcomeAttribute, removing reliance on fragile TRX testName matching for theory tests.

Changes:

  • New EmitRecordingOutcomeAttribute (xUnit v3 BeforeAfterTestAttribute) that writes a <recording>.cast.outcome sidecar; applied to all CLI E2E and Deployment E2E test classes, and recording path is published into TestContext.KeyValueStorage from Hex1bTestHelpers.CreateTestTerminal and CliE2ETestHelpers.RegisterCaptureFile.
  • run-tests.yml collects .cast.outcome sidecars alongside .cast and .trx artifacts.
  • cli-e2e-recording-comment.yml reads the sidecar first (falling back to a hardened yq+jq TRX parser), tallies Passed/Failed/Unknown, formats a deployment-style headline, and adds a pr_number workflow_dispatch override for dry runs.
Show a summary per file
File Description
tests/Shared/EmitRecordingOutcomeAttribute.cs New attribute writing outcome sidecar after each test.
tests/Shared/Hex1bTestHelpers.cs Publishes RecordingPath into TestContext.KeyValueStorage.
tests/Aspire.Cli.EndToEnd.Tests/Helpers/CliE2ETestHelpers.cs Also publishes recording path when the capture file is recording.cast.
tests/Aspire.Cli.EndToEnd.Tests/*.cs (many) [EmitRecordingOutcome] attribute applied to all CLI E2E test classes.
tests/Aspire.Deployment.EndToEnd.Tests/*.cs (many) Same attribute applied to deployment E2E test classes.
tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj, tests/Aspire.Deployment.EndToEnd.Tests/Aspire.Deployment.EndToEnd.Tests.csproj Link the shared attribute file.
.github/workflows/run-tests.yml Copy *.cast.outcome sidecars and include them in the artifact.
.github/workflows/cli-e2e-recording-comment.yml Add PR override, hardened TRX parsing, sidecar-first outcome lookup, and new deployment-style summary headline.

Copilot's findings

  • Files reviewed: 111/111 changed files
  • Comments generated: 1

Comment thread .github/workflows/cli-e2e-recording-comment.yml
Theory test recordings (e.g. recordings produced from
[Theory] methods) are saved with their [CallerMemberName] bare method
name, while TRX reports them with parameter data appended:
'Namespace.Class.Method(toolchain: "pnpm")'. The previous parser only
keyed by the last dotted segment, which preserved those parens and so
never matched the .cast filename, leaving theory recordings reported as
'Unknown'.

Strip the parameter suffix and also key the outcome map by the bare
method name and the no-parameter FQN. 'Failed' still wins over other
outcomes when the same key is seen multiple times (retries, multiple
theory cases), so a single failing case still surfaces as ❌ in the
comment.

Co-authored-by: Copilot <[email protected]>
@mitchdenny mitchdenny force-pushed the mitchdenny/cli-e2e-test-summary branch from a82dc76 to 8aef4a3 Compare May 16, 2026 02:31
Mitch Denny and others added 2 commits May 16, 2026 12:48
Both [Fact]s delegate to a private helper that calls
CreateDockerTestTerminal, so [CallerMemberName] resolved to the helper
name. That produced a single .cast file named after the private method
with no matching TRX entry, which the comment workflow reported as
'Unknown'. Pass the public test name through explicitly so each Fact
gets its own recording and matches TRX.

Co-authored-by: Copilot <[email protected]>
When no TRX outcomes can be matched to any recording the headline used
to render '0 passed, 0 failed', which reads as 'no tests ran' rather
than 'outcome data unavailable'. Switch the fallback wording to
'<N> recording(s), outcomes unavailable' so the headline reflects what
actually happened.

Co-authored-by: Copilot <[email protected]>
Copy link
Copy Markdown
Member

@JamesNK JamesNK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The summary logic correctly handles all outcome combinations, the TRX parsing refactor is robust (null-guarded, handles both yq attribute naming conventions), and the [CallerMemberName] propagation fix in OtelLogsTests is correct.

@github-actions
Copy link
Copy Markdown
Contributor

🎬 CLI E2E Test Recordings — 86 recordings uploaded (commit 090f970)

View all recordings
Status Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost ▶️ View Recording
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles ▶️ View Recording
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View Recording
CertificatesClean_RemovesCertificates ▶️ View Recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View Recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJavaEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateJavaAppHostWithViteApp ▶️ View Recording
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain ▶️ View Recording
DashboardRunWithOtelTracesReturnsNoTraces ▶️ View Recording
DeployK8sBasicApiService ▶️ View Recording
DeployK8sWithExternalHelmChart ▶️ View Recording
DeployK8sWithGarnet ▶️ View Recording
DeployK8sWithMongoDB ▶️ View Recording
DeployK8sWithMySql ▶️ View Recording
DeployK8sWithPostgres ▶️ View Recording
DeployK8sWithRabbitMQ ▶️ View Recording
DeployK8sWithRedis ▶️ View Recording
DeployK8sWithSqlServer ▶️ View Recording
DeployK8sWithValkey ▶️ View Recording
DeployTypeScriptAppToKubernetes ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance ▶️ View Recording
DoListStepsShowsPipelineSteps ▶️ View Recording
DocsCommand_RendersInteractiveMarkdownFromLocalSource ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InitTypeScriptAppHost_AugmentsExistingViteRepoAtRoot ▶️ View Recording
InteractiveCSharpInitCreatesExpectedFiles ▶️ View Recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View Recording
LatestCliCanStartStableChannelAppHost ▶️ View Recording
LatestCliCanStartStableChannelTypeScriptAppHost ▶️ View Recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View Recording
LogLevelTrace_ProducesTraceEntriesInCliLogFile ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
OtelLogsReturnsStructuredLogsFromStarterApp ▶️ View Recording
OtelLogsReturnsStructuredLogsFromStarterAppIsolated ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View Recording
ResourceCommand_FailsWhenInteractionServiceIsRequired ▶️ View Recording
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RestoreGeneratesSdkFiles_WithConfiguredToolchain ▶️ View Recording
RestoreRefreshesGeneratedSdkAfterAddingIntegration ▶️ View Recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View Recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording
UnAwaitedChainsCompileWithAutoResolvePromises ▶️ View Recording
UpdateProjectChannelToStable_TypeScript_PicksUpStablePackages ▶️ View Recording

📹 Recordings uploaded automatically from CI run #25951116505

@mitchdenny mitchdenny merged commit cd096b9 into main May 16, 2026
588 of 591 checks passed
@mitchdenny mitchdenny deleted the mitchdenny/cli-e2e-test-summary branch May 16, 2026 03:47
@github-actions github-actions Bot added this to the 13.4 milestone May 16, 2026
@aspire-repo-bot
Copy link
Copy Markdown
Contributor

✅ No documentation update needed.

docs_optional → build_or_ci_only

No signals triggered (signal_count == 0). The advisory only_test_or_build_changes signal fired, confirming all changed files are in CI/workflow infrastructure (.github/ workflows). This PR updates the GitHub Actions comment format for CLI E2E test recording summaries — it is entirely internal CI tooling with no user-facing documentation surface.

nellshamrell pushed a commit to nellshamrell/aspire that referenced this pull request May 18, 2026
…#17154)

* Mirror deployment E2E summary in CLI E2E recording comment

Update the CLI E2E recording PR comment to surface a passed/failed
breakdown in the same style as the Deployment E2E Tests comment, e.g.
"✅ **CLI E2E Tests passed** — 12 passed, 0 failed".

Counts are derived from the TRX outcomes that are already parsed,
adding explicit pass and unknown tallies alongside the existing fail
count. Recording upload failures stay surfaced but no longer drive the
headline status, since they are unrelated to test correctness.

Co-authored-by: Copilot <[email protected]>

* Embed per-row outcome in CLI E2E recording link label

Surface the test outcome on the recording link itself, not only in the
table's Status column, so a URL pulled out of the table still tells a
reader whether it represents a pass or a failure. Failed recordings get
"❌ ▶️ View failure recording", passes get "✅ ▶️ View recording",
and unknowns keep "❔".

Co-authored-by: Copilot <[email protected]>

* Allow workflow_dispatch to override target PR for testing

Adds a pr_number input to the manual trigger so the workflow can be
exercised against a chosen PR's artifacts without depending on the open
head-SHA lookup, which is needed to test changes to this workflow
before they reach main.

Co-authored-by: Copilot <[email protected]>

* Fix TRX outcome parser

The previous yq query used jq-style 'if type == "!!seq"' which the Go
yq lexer rejects, so test_outcomes.json was always empty and every
recording showed as Unknown. The step had continue-on-error: true, so
the failure stayed silent until the new pass/fail summary surfaced it.

Convert TRX to JSON with yq -p xml -o json, then do all reshaping in jq
where it handles single-vs-array UnitTestResult shapes correctly. yq
also emits attributes as '+@<attr>' (newer) or '@<attr>' (older), so the
lookup tries both forms.

Co-authored-by: Copilot <[email protected]>

* Match cast files against TRX theory tests by bare method name

Theory test recordings (e.g. recordings produced from
[Theory] methods) are saved with their [CallerMemberName] bare method
name, while TRX reports them with parameter data appended:
'Namespace.Class.Method(toolchain: "pnpm")'. The previous parser only
keyed by the last dotted segment, which preserved those parens and so
never matched the .cast filename, leaving theory recordings reported as
'Unknown'.

Strip the parameter suffix and also key the outcome map by the bare
method name and the no-parameter FQN. 'Failed' still wins over other
outcomes when the same key is seen multiple times (retries, multiple
theory cases), so a single failing case still surfaces as ❌ in the
comment.

Co-authored-by: Copilot <[email protected]>

* Thread CallerMemberName through OtelLogs core helper

Both [Fact]s delegate to a private helper that calls
CreateDockerTestTerminal, so [CallerMemberName] resolved to the helper
name. That produced a single .cast file named after the private method
with no matching TRX entry, which the comment workflow reported as
'Unknown'. Pass the public test name through explicitly so each Fact
gets its own recording and matches TRX.

Co-authored-by: Copilot <[email protected]>

* Replace zero pass/fail counts with recording count in fallback summary

When no TRX outcomes can be matched to any recording the headline used
to render '0 passed, 0 failed', which reads as 'no tests ran' rather
than 'outcome data unavailable'. Switch the fallback wording to
'<N> recording(s), outcomes unavailable' so the headline reflects what
actually happened.

Co-authored-by: Copilot <[email protected]>

---------

Co-authored-by: Mitch Denny <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Mitch Denny <[email protected]>
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.

3 participants