diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 0ebcab236..d4375cd75 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -157,12 +157,35 @@ jobs: name: npm-logs-${{ matrix.name }}-${{ matrix.os }} path: ${{ runner.os == 'Windows' && 'C:\\npm\\cache\\_logs\\**' || '~/.npm/cache/_logs/**' }} + - name: Resolve Aspire CLI log directory + # Aspire CLI logs live next to the resolved `aspire` executable, not always under $HOME. + if: failure() && steps.run-tests.outcome != 'skipped' + id: aspire-log-dir + shell: bash + run: | + aspire_bin="$(command -v aspire || true)" + if [ -n "$aspire_bin" ]; then + resolved_dir="$(cd "$(dirname "$aspire_bin")/.." && pwd)/logs" + else + resolved_dir="$HOME/.aspire/logs" + fi + + if [ "${RUNNER_OS}" = "Windows" ] && command -v cygpath >/dev/null 2>&1; then + resolved_dir="$(cygpath -w "$resolved_dir")" + fi + + echo "Resolved Aspire CLI log directory: ${resolved_dir}" + echo "dir=${resolved_dir}" >> "$GITHUB_OUTPUT" + - name: Upload TypeScript app host logs if failed if: failure() && steps.run-tests.outcome != 'skipped' uses: actions/upload-artifact@v7 with: name: ts-app-host-logs-${{ matrix.name }}-${{ matrix.os }} - path: ${{ runner.os == 'Windows' && 'C:\\Users\\runneradmin\\.aspire\\logs\\**' || '/home/runner/.aspire/logs/**' }} + path: | + ${{ steps.aspire-log-dir.outputs.dir }}/** + ${{ runner.os == 'Windows' && 'C:\\Users\\runneradmin\\.aspire\\logs\\**' || '/home/runner/.aspire/logs/**' }} + if-no-files-found: warn - name: Aspire doctor if: failure() && steps.run-tests.outcome != 'skipped' diff --git a/eng/testing/validate-typescript-apphost.ps1 b/eng/testing/validate-typescript-apphost.ps1 index 03139cf5a..748939bc9 100644 --- a/eng/testing/validate-typescript-apphost.ps1 +++ b/eng/testing/validate-typescript-apphost.ps1 @@ -60,6 +60,24 @@ function Invoke-ExternalCommand { } } +function Write-DiagnosticsSection { + param( + [Parameter(Mandatory = $true)] + [string]$Title, + + [Parameter(Mandatory = $true)] + [scriptblock]$Action + ) + + Write-Host "::group::$Title" + try { + & $Action 2>&1 | Out-String | Write-Host + } + finally { + Write-Host "::endgroup::" + } +} + function Invoke-ExternalCommandWithRetry { param( [Parameter(Mandatory = $true)] @@ -105,6 +123,7 @@ function Invoke-CleanupStep { & $Action } catch { + Write-Host ($_ | Out-String) $message = "Cleanup step '$Description' failed: $($_.Exception.Message)" if ($null -ne $Failures) { $Failures.Add($message) @@ -204,14 +223,33 @@ try { $appStarted = $true foreach ($resource in $WaitForResources) { - Invoke-ExternalCommand "aspire" @( - "wait", - $resource, - "--status", $WaitStatus, - "--apphost", $resolvedAppHostPath, - "--timeout", $WaitTimeoutSeconds, - "--log-level", "debug" - ) + try { + Invoke-ExternalCommand "aspire" @( + "wait", + $resource, + "--status", $WaitStatus, + "--apphost", $resolvedAppHostPath, + "--timeout", $WaitTimeoutSeconds, + "--log-level", "debug" + ) + } + catch { + Write-DiagnosticsSection -Title "aspire describe" -Action { + aspire @("describe", "--apphost", $resolvedAppHostPath, "--format", "Json", "--log-level", "debug") + } + + foreach ($waitedResource in $WaitForResources) { + Write-DiagnosticsSection -Title "aspire logs $waitedResource" -Action { + aspire @("logs", $waitedResource, "--apphost", $resolvedAppHostPath, "--timestamps") + } + } + + Write-DiagnosticsSection -Title "aspire logs (all resources)" -Action { + aspire @("logs", "--apphost", $resolvedAppHostPath, "--timestamps") + } + + throw + } } Invoke-ExternalCommand "aspire" @( @@ -231,6 +269,7 @@ catch { finally { Invoke-CleanupStep -Description "stop Aspire app" -Action { if ($appStarted) { + Write-Host "Shutting down Aspire app..." Push-Location $appHostDirectory try { Invoke-ExternalCommand "aspire" @(