Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .github/workflows/Steeltoe.All.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,15 @@ jobs:
-RepoRoot ${{ github.workspace }}
-ProjectRelativePath src/Management/src/GitProperties.Build

- name: Upload crash/hang dumps (on failure)
- name: Upload crash dumps and build diagnostics (on failure)
if: ${{ !cancelled() && (steps.test.outcome == 'failure' || steps.test-memory-dumps.outcome == 'failure' || steps.test-gitproperties.outcome == 'failure') }}
uses: actions/upload-artifact@v7
with:
name: FailedTestOutput-${{ matrix.os }}
path: |
${{ github.workspace }}/TestOutput/**/*.dmp
${{ github.workspace }}/TestOutput/**/Sequence_*.xml
${{ github.workspace }}/TestOutput/**/*.binlog
if-no-files-found: ignore

- name: Report test results
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/component-shared-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,15 @@ jobs:
if: ${{ inputs.component == 'Management' }}
run: dotnet test src/Management/test/Endpoint.Test --filter "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }}

- name: Upload crash/hang dumps (on failure)
- name: Upload crash dumps and build diagnostics (on failure)
if: ${{ !cancelled() && (steps.test.outcome == 'failure' || steps.test-memory-dumps.outcome == 'failure') }}
uses: actions/upload-artifact@v7
with:
name: FailedTestOutput-${{ inputs.OS }}-latest
path: |
${{ github.workspace }}/TestOutput/**/*.dmp
${{ github.workspace }}/TestOutput/**/Sequence_*.xml
${{ github.workspace }}/TestOutput/**/*.binlog
if-no-files-found: ignore

- name: Report test results
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/sonarcube.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,15 @@ jobs:
run: dotnet build ${{ env.SOLUTION_FILE }} --no-restore --configuration Release --verbosity minimal /p:NuGetAuditLevel=low /p:WarningsNotAsErrors='${{ env.NUGET_VULNERABLE_PACKAGE_WARNINGS }}'

- name: Test
id: test
run: dotnet test ${{ env.SOLUTION_FILE }} --filter "Category!=MemoryDumps&Category!=GitProperties" ${{ env.COMMON_TEST_ARGS }} ${{ env.COVERAGE_COLLECT_ARGS }}

- name: Test (memory dumps)
id: test-memory-dumps
run: dotnet test src/Management/test/Endpoint.Test --filter "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} ${{ env.COVERAGE_COLLECT_ARGS }}

- name: Test (git.properties)
id: test-gitproperties
run: >-
dotnet dotnet-coverage collect -f cobertura -o ${{ github.workspace }}/TestOutput/GitProperties.Build.Test.cobertura.xml --
dotnet test src/Management/test/GitProperties.Build.Test ${{ env.COMMON_TEST_ARGS }}
Expand All @@ -119,6 +122,17 @@ jobs:
-RepoRoot ${{ github.workspace }}
-ProjectRelativePath src/Management/src/GitProperties.Build

- name: Upload crash dumps and build diagnostics (on failure)
if: ${{ !cancelled() && (steps.test.outcome == 'failure' || steps.test-memory-dumps.outcome == 'failure' || steps.test-gitproperties.outcome == 'failure') }}
uses: actions/upload-artifact@v7
with:
name: FailedTestOutput-sonarcube
path: |
${{ github.workspace }}/TestOutput/**/*.dmp
${{ github.workspace }}/TestOutput/**/Sequence_*.xml
${{ github.workspace }}/TestOutput/**/*.binlog
if-no-files-found: ignore

- name: End Sonar .NET scanner
if: ${{ !cancelled() && steps.sonar_begin.outcome == 'success' }}
env:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public static async Task<PackageReference> PackAsync(DirectoryInfo sessionDirect
string projectFilePath = Path.Combine(sourceDirectory, $"{PackageId}.csproj");
await File.WriteAllTextAsync(projectFilePath, projectContent, TestContext.Current.CancellationToken);

await ProcessRunner.RunDotNetAsync(sourceDirectory, 0, null, "build", "-c", "Release", $"-p:Version={PackageVersion}",
$"-p:PackageOutputPath={nuGetFeedDirectory}");
await ProcessRunner.RunDotNetBuildWithFailureDiagnosticsAsync(sourceDirectory, "fake-endpoint-build", "build", "-c", "Release",
$"-p:Version={PackageVersion}", $"-p:PackageOutputPath={nuGetFeedDirectory}");

return new PackageReference(PackageId, PackageVersion, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public static async Task<PackageReference> PackAsync(string nuGetFeedDirectory)
string sourceDirectory = Path.Combine(repositoryRoot, "src", "Management", "src", "GitProperties.Build");
string packageVersion = $"{PackageVersionPrefix}.{$"{Guid.NewGuid():N}"[..8]}";

await ProcessRunner.RunDotNetAsync(sourceDirectory, 0, null, "build", "-c", "Release", $"-p:Version={packageVersion}",
$"-p:PackageOutputPath={nuGetFeedDirectory}");
await ProcessRunner.RunDotNetBuildWithFailureDiagnosticsAsync(sourceDirectory, "git-properties-build", "build", "-c", "Release",
$"-p:Version={packageVersion}", $"-p:PackageOutputPath={nuGetFeedDirectory}");

return new PackageReference(PackageId, packageVersion, null);
}
Expand Down
42 changes: 42 additions & 0 deletions src/Management/test/GitProperties.Build.Test/ProcessRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;

namespace Steeltoe.Management.GitProperties.Build.Test;
Expand All @@ -24,6 +25,7 @@ internal static class ProcessRunner
private static readonly TimeSpan ProcessExitTimeout = TimeSpan.FromMinutes(2);

private static readonly Task<string> RealGitExecutableTask = ResolveGitExecutableAsync();
private static readonly Task<string> DiagnosticsDirectoryTask = ResolveDiagnosticsDirectoryAsync();

private static async Task<string> ResolveGitExecutableAsync()
{
Expand All @@ -50,6 +52,46 @@ public static async Task<string> RunGitAsync(string workingDirectory, Cancellati
return output.Trim();
}

/// <summary>
/// Runs a "dotnet build" that is known to occasionally fail restore without logging a reason (MSBuild task returns false but does not log an error, for
/// example when a shared NuGet resource is briefly contended). Captures a binlog and keeps it only when the build fails, so a next occurrence can be
/// diagnosed from the CI-uploaded artifact instead of just the generic "did not log an error" message.
/// </summary>
public static async Task<string> RunDotNetBuildWithFailureDiagnosticsAsync(string workingDirectory, string diagnosticsFileNamePrefix,
params string[] arguments)
{
string diagnosticsDirectory = await DiagnosticsDirectoryTask;
string binlogPath = Path.Combine(diagnosticsDirectory, $"{diagnosticsFileNamePrefix}-{$"{Guid.NewGuid():N}"[..8]}.binlog");

string[] argumentsWithBinlog =
[
.. arguments,
$"-bl:{binlogPath}"
];

string output = await RunDotNetAsync(workingDirectory, 0, null, argumentsWithBinlog);

try
{
File.Delete(binlogPath);
}
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException)
{
// Best-effort cleanup only: a transiently locked file (e.g. an antivirus scan) must not fail the test run.
}

return output;
}

private static async Task<string> ResolveDiagnosticsDirectoryAsync([CallerFilePath] string sourceFilePath = "")
{
string sourceDirectory = Path.GetDirectoryName(sourceFilePath) ?? throw new InvalidOperationException("Could not determine the test source directory.");
string repositoryRoot = await RunGitAsync(sourceDirectory, CancellationToken.None, "rev-parse", "--show-toplevel");
string diagnosticsDirectory = Path.Combine(repositoryRoot.Replace('/', Path.DirectorySeparatorChar), "TestOutput");
Directory.CreateDirectory(diagnosticsDirectory);
return diagnosticsDirectory;
}

public static Task<string> RunDotNetAsync(string workingDirectory, int exitCodeExpected, Dictionary<string, string>? environmentVariables,
params string[] arguments)
{
Expand Down
Loading