diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dbf0b9b8..ca3788be 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,8 +22,8 @@ on: - 'diagnostic' jobs: - test: - name: Test + test-linux: + name: 🐧 Test runs-on: ubuntu-latest timeout-minutes: 5 env: @@ -42,16 +42,47 @@ jobs: --project ./build/_build.csproj \ --target Test \ --commit ${{ github.sha }} \ - --msbuildverbosity ${{ github.event.inputs.verbosity }} + --msbuildverbosity ${{ github.event.inputs.verbosity }} \ + --platform linux_x64 - name: Display test results continue-on-error: true if: always() run: dotnet trx --verbosity normal - # TODO fix publish warnings and re-enable check - name: Check for warnings run: | dotnet run \ --project ./build/_build.csproj \ --target CheckBuildWarnings + + test-windows: + name: 🪟 Test + runs-on: windows-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up runner + uses: ./.github/actions/setup-runner + + - name: Run tests + run: | + dotnet run ` + --project ./build/_build.csproj ` + --target Test ` + --commit ${{ github.sha }} ` + --msbuildverbosity ${{ github.event.inputs.verbosity }} ` + --platform win_x64 + + - name: Display test results + continue-on-error: true + if: always() + run: dotnet trx --verbosity normal + + - name: Check for warnings + run: | + dotnet run ` + --project ./build/_build.csproj ` + --target CheckBuildWarnings diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 40e55bc6..86cbcc7e 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -147,6 +147,45 @@ "type": "string", "description": "MsBuildVerbosity - Console output verbosity - Default is 'normal'" }, + "Platform": { + "type": "string", + "description": "Platform - A .NET RID but with underscores instead of dashes e.g. linux_x64 or win_x64", + "enum": [ + "linux_arm", + "linux_arm64", + "linux_musl_x64", + "linux_x64", + "osx_10_10_x64", + "osx_10_11_x64", + "osx_10_12_x64", + "osx_10_13_x64", + "osx_10_14_x64", + "osx_10_15_x64", + "osx_11_0_arm64", + "osx_11_0_x64", + "osx_12_arm64", + "osx_12_x64", + "osx_x64", + "rhel_6_x64", + "rhel_x64", + "tizen", + "tizen_4_0_0", + "tizen_5_0_0", + "win_arm", + "win_arm64", + "win_x64", + "win_x86", + "win10_arm", + "win10_arm64", + "win10_x64", + "win10_x86", + "win7_x64", + "win7_x86", + "win81_arm", + "win81_x64", + "win81_x86" + ] + }, "Solution": { "type": "string", "description": "Path to a solution file that is automatically loaded" diff --git a/build/NukeBuild.Binaries.cs b/build/NukeBuild.Binaries.cs index 5198e595..2e12b89c 100644 --- a/build/NukeBuild.Binaries.cs +++ b/build/NukeBuild.Binaries.cs @@ -18,29 +18,28 @@ sealed partial class NukeBuild { Target PublishBinaries => _ => _ .DependsOn( Build, CleanArtifacts ) + .Requires( () => Platform ) + .Requires( () => SupportedRuntimes.Contains( Platform ) ) .Executes( async () => { using var _ = new OperationTimer( nameof(PublishBinaries) ); - // TODO https://nuke.build/docs/common/cli-tools/#combinatorial-modifications - foreach ( var runtime in SupportedRuntimes ) { - var publishDir = Paths.PublishDirectoryForRuntime( runtime ); - var version = await Versioning.Value.GetVersionAsync(); + var publishDir = Paths.PublishDirectoryForRuntime( Platform ); + var version = await Versioning.Value.GetVersionAsync(); - Log.Information( "Publishing {Runtime} build to {PublishDir}", runtime, publishDir ); - DotNetPublish( s => s - .SetProject( Solution.Cli ) - .SetConfiguration( Configuration ) - .SetOutput( publishDir ) - .SetSelfContained( true ) - .SetVersionProperties( version ) - // TODO if not specifying a RID, apparently only x64 gets built on x64 host - .SetRuntime( runtime ) - .SetProcessAdditionalArguments( $"-bl:{BinaryPublishLogName}" ) - .EnableNoLogo() - .EnableNoRestore() - .EnableNoBuild() - ); - } + Log.Information( "Publishing {Runtime} build to {PublishDir}", Platform, publishDir ); + Log.Debug( "Supported runtimes are {SupportedRuntimes}", string.Join( ", ", SupportedRuntimes ) ); + DotNetPublish( s => s + .SetProject( Solution.Cli ) + .SetConfiguration( Configuration ) + .SetOutput( publishDir ) + .SetSelfContained( true ) + .SetVersionProperties( version ) + .SetRuntime( Platform ) + .SetProcessAdditionalArguments( $"-bl:{BinaryPublishLogName}" ) + .EnableNoLogo() + .EnableNoRestore() + .EnableNoBuild() + ); } ); diff --git a/build/NukeBuild.Container.cs b/build/NukeBuild.Container.cs index 75c155b6..dca6872c 100644 --- a/build/NukeBuild.Container.cs +++ b/build/NukeBuild.Container.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using Nuke.Common; using Nuke.Common.Tools.Docker; +using Nuke.Common.Tools.DotNet; using Serilog; using Versioning; @@ -33,6 +34,7 @@ partial class NukeBuild { Target PublishContainer => _ => _ .DependsOn( PublishBinaries, CleanArtifacts ) + .OnlyWhenDynamic( () => Platform != DotNetRuntimeIdentifier.win_x64 ) .Requires( () => Commit ) .Executes( async () => { using var _ = new OperationTimer( nameof(PublishContainer) ); diff --git a/build/NukeBuild.Test.cs b/build/NukeBuild.Test.cs index dfdbc08c..b2919c11 100644 --- a/build/NukeBuild.Test.cs +++ b/build/NukeBuild.Test.cs @@ -16,6 +16,11 @@ // ReSharper disable UnusedMember.Local sealed partial class NukeBuild { + private string DriftBinaryName => + Platform == DotNetRuntimeIdentifier.linux_x64 ? "drift" : + Platform == DotNetRuntimeIdentifier.win_x64 ? "drift.exe" : + throw new PlatformNotSupportedException(); + Target Test => _ => _ .DependsOn( TestSelf, TestUnit, TestE2E ); @@ -73,36 +78,35 @@ sealed partial class NukeBuild { var imageRef = _driftImageRef ?? throw new ArgumentNullException( nameof(_driftImageRef) ); Log.Information( "Using image {ImageRef}", imageRef ); - foreach ( var runtime in SupportedRuntimes ) { - var driftBinary = Paths.PublishDirectoryForRuntime( runtime ) / "drift"; - - var envVars = new Dictionary { - // { nameof(EnvVar.DRIFT_BINARY_PATH), driftBinary }, - { "DRIFT_BINARY_PATH", driftBinary }, // - { "DRIFT_CONTAINER_IMAGE_REF", imageRef.ToString() } - }; - - var alternateDockerHost = await FindAlternateDockerHostAsync(); - - DotNetTest( settings => { - if ( alternateDockerHost != null ) { - Log.Information( "Using alternate Docker host: {Host}", alternateDockerHost ); - settings.SetProcessEnvironmentVariable( "DOCKER_HOST", alternateDockerHost ); - } - - return settings - .SetProjectFile( Solution.Cli_E2ETests ) - .SetConfiguration( Configuration ) - .ConfigureLoggers( MsBuildVerbosityParsed ) - .SetBlameHangTimeout( "60s" ) - .EnableNoLogo() - .EnableNoRestore() - .EnableNoBuild() - .AddProcessEnvironmentVariables( envVars ); - } ); - - Log.Information( "Running E2E test on {Runtime} using binary {Binary}", runtime, driftBinary ); - } + var driftBinary = Paths.PublishDirectoryForRuntime( Platform ) / DriftBinaryName; + + Log.Information( "Running E2E test on {Runtime} using binary {Binary}", Platform, driftBinary ); + Log.Debug( "Supported runtimes are {SupportedRuntimes}", string.Join( ", ", SupportedRuntimes ) ); + + var envVars = new Dictionary { + // { nameof(EnvVar.DRIFT_BINARY_PATH), driftBinary }, + { "DRIFT_BINARY_PATH", driftBinary }, + { "DRIFT_CONTAINER_IMAGE_REF", imageRef.ToString() } + }; + + var alternateDockerHost = await FindAlternateDockerHostAsync(); + + DotNetTest( settings => { + if ( alternateDockerHost != null ) { + Log.Information( "Using alternate Docker host: {Host}", alternateDockerHost ); + settings.SetProcessEnvironmentVariable( "DOCKER_HOST", alternateDockerHost ); + } + + return settings + .SetProjectFile( Solution.Cli_E2ETests ) + .SetConfiguration( Configuration ) + .ConfigureLoggers( MsBuildVerbosityParsed ) + .SetBlameHangTimeout( "60s" ) + .EnableNoLogo() + .EnableNoRestore() + .EnableNoBuild() + .AddProcessEnvironmentVariables( envVars ); + } ); } ); diff --git a/build/NukeBuild.cs b/build/NukeBuild.cs index 9b2ea201..42876c5d 100644 --- a/build/NukeBuild.cs +++ b/build/NukeBuild.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Drift.Build.Utilities; @@ -64,8 +65,18 @@ public NukeBuild() { [Secret, Parameter( $"{nameof(GitHubToken)} - GitHub token used to create releases" )] public string GitHubToken; + [Parameter( $"{nameof(Platform)} - A .NET RID but with underscores instead of dashes e.g. linux_x64 or win_x64" )] + public DotNetRuntimeIdentifier Platform = IsLocalBuild + ? RuntimeInformation.IsOSPlatform( OSPlatform.Linux ) + ? DotNetRuntimeIdentifier.linux_x64 + : RuntimeInformation.IsOSPlatform( OSPlatform.Windows ) + ? DotNetRuntimeIdentifier.win_x64 + : throw new PlatformNotSupportedException() + : null; + private static readonly DotNetRuntimeIdentifier[] SupportedRuntimes = [ DotNetRuntimeIdentifier.linux_x64, + DotNetRuntimeIdentifier.win_x64 // TODO support more architectures /* , DotNetRuntimeIdentifier.linux_musl_x64 diff --git a/src/Cli.E2ETests/Commands/LintTests.InitThenLintTest.verified.txt b/src/Cli.E2ETests/Commands/LintTests.InitThenLintTest.verified.txt index e3668b27..01fd0170 100644 --- a/src/Cli.E2ETests/Commands/LintTests.InitThenLintTest.verified.txt +++ b/src/Cli.E2ETests/Commands/LintTests.InitThenLintTest.verified.txt @@ -1,2 +1,2 @@ Validating {CurrentDirectory}unittest.spec.yaml -✔ Valid +✓ Valid diff --git a/src/Cli.E2ETests/Commands/LintTests.cs b/src/Cli.E2ETests/Commands/LintTests.cs index 071a440b..02fc51da 100644 --- a/src/Cli.E2ETests/Commands/LintTests.cs +++ b/src/Cli.E2ETests/Commands/LintTests.cs @@ -14,7 +14,7 @@ public async Task InitThenLintTest() { using ( Assert.EnterMultipleScope() ) { Assert.That( initResult.ExitCode, Is.EqualTo( ExitCodes.Success ) ); - Assert.That( initResult.StdOut, Contains.Substring( "✔ Spec created" ) ); + Assert.That( initResult.StdOut, Contains.Substring( " Spec created" ) ); Assert.That( initResult.ErrOut, Is.Empty ); } diff --git a/src/Cli.E2ETests/Commands/ReadmeWorkflowTests.cs b/src/Cli.E2ETests/Commands/ReadmeWorkflowTests.cs index d3d5fb26..4c00fc83 100644 --- a/src/Cli.E2ETests/Commands/ReadmeWorkflowTests.cs +++ b/src/Cli.E2ETests/Commands/ReadmeWorkflowTests.cs @@ -18,7 +18,7 @@ public async Task InitThenScanTest() { using ( Assert.EnterMultipleScope() ) { Assert.That( initResult.ExitCode, Is.EqualTo( ExitCodes.Success ) ); - Assert.That( initResult.StdOut, Contains.Substring( "✔ Spec created /" ) ); + Assert.That( initResult.StdOut, Contains.Substring( "✓ Spec created /" ) ); } await Verify( initResult.StdOut ) diff --git a/src/Cli.E2ETests/Container/CommandTests.cs b/src/Cli.E2ETests/Container/CommandTests.cs index b2256dc3..e342c467 100644 --- a/src/Cli.E2ETests/Container/CommandTests.cs +++ b/src/Cli.E2ETests/Container/CommandTests.cs @@ -5,6 +5,7 @@ namespace Drift.Cli.E2ETests.Container; +[Platform( "Linux" )] internal sealed class CommandTests : DriftImageFixture { [Test] public async Task ValidCommand_ReturnsSuccessExitCode() { diff --git a/src/Cli.E2ETests/Container/LabelsTest.cs b/src/Cli.E2ETests/Container/LabelsTest.cs index 24ad8e7b..37de4821 100644 --- a/src/Cli.E2ETests/Container/LabelsTest.cs +++ b/src/Cli.E2ETests/Container/LabelsTest.cs @@ -3,6 +3,7 @@ namespace Drift.Cli.E2ETests.Container; +[Platform( "Linux" )] internal sealed class LabelsTest : DriftImageFixture { private readonly List _ociAnnotationsV1_1_1 = [ "org.opencontainers.image.created", diff --git a/src/Cli.E2ETests/Container/PortTest.cs b/src/Cli.E2ETests/Container/PortTest.cs index 4472c4c8..669b1e54 100644 --- a/src/Cli.E2ETests/Container/PortTest.cs +++ b/src/Cli.E2ETests/Container/PortTest.cs @@ -1,5 +1,6 @@ namespace Drift.Cli.E2ETests.Container; +[Platform( "Linux" )] internal sealed class PortTest : DriftImageFixture { [Explicit( "Not implemented yet" )] [Test] diff --git a/src/Cli.E2ETests/Installation/InstallTests.cs b/src/Cli.E2ETests/Installation/InstallTests.cs index eec1bd9d..47828bb7 100644 --- a/src/Cli.E2ETests/Installation/InstallTests.cs +++ b/src/Cli.E2ETests/Installation/InstallTests.cs @@ -10,6 +10,7 @@ namespace Drift.Cli.E2ETests.Installation; "S2325:Methods and properties that don\'t access instance data should be static", Justification = "Unimplemented test methods should not be static" )] +[Platform("Linux")] internal sealed class InstallTests { // TODO split test into at least two parts [Test] diff --git a/src/Cli.E2ETests/Schemas/SchemasAvailabilityTests.cs b/src/Cli.E2ETests/Schemas/SchemasAvailabilityTests.cs index 74427949..400e4a89 100644 --- a/src/Cli.E2ETests/Schemas/SchemasAvailabilityTests.cs +++ b/src/Cli.E2ETests/Schemas/SchemasAvailabilityTests.cs @@ -1,3 +1,5 @@ +using System.Text.RegularExpressions; + namespace Drift.Cli.E2ETests.Schemas; internal sealed class SchemasAvailabilityTests { @@ -44,6 +46,10 @@ public async Task SchemaIsAvailableAtDocumentedUrl( string documentedUrl, string // Assert Assert.DoesNotThrow( () => response.EnsureSuccessStatusCode() ); var content = await response.Content.ReadAsStringAsync(); - Assert.That( content, Contains.Substring( expectedPartialContent ) ); + + var normalizedContent = Regex.Replace( content, @"\s", string.Empty ); + var normalizedExpected = Regex.Replace( expectedPartialContent, @"\s", string.Empty ); + + Assert.That( normalizedContent, Contains.Substring( normalizedExpected ) ); } } \ No newline at end of file diff --git a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt index 8fc6f176..48b741f2 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt @@ -2,4 +2,4 @@ Found interfaces: [lo, up, 127.0.0.0/8], [enp0xxxxx, down, -], [enp8xxxxx, up, 192.168.0.0/24], [wlp, up, 192.168.0.0/24], [tun0, up, 100.100.1.9/32] Discovered subnet(s): 192.168.0.0/24 (RFC1918 addresses only) Found subnets: 192.168.0.0/24 (254 addresses, 00:00:05.0800000 estimated scan time) -✔ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml +✓ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml diff --git a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt index 2b5daee4..cb225e0c 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt @@ -1 +1 @@ -✔ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml +✓ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml diff --git a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt index 4f144e23..11301189 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt @@ -1 +1 @@ -✔ Spec created {CurrentDirectory}myNetworkWithoutDiscovery.spec.yaml +✓ Spec created {CurrentDirectory}myNetworkWithoutDiscovery.spec.yaml diff --git a/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt index 70e0e2ef..109a2439 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt @@ -1 +1 @@ -✗ Name is required \ No newline at end of file +✕ Name is required \ No newline at end of file diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=.verified.txt similarity index 90% rename from src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=.verified.txt rename to src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=.verified.txt index 8c5733ee..810c1d7e 100644 --- a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=.verified.txt +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=.verified.txt @@ -1,4 +1,4 @@ Validating {SolutionDirectory}src/Spec.Tests/resources/network_single_device_host.yaml -✗ Validation failed +✕ Validation failed • /: Required properties ["version"] are not present • /network/subnets/0: Required properties ["address"] are not present diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=log.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=log.verified.txt similarity index 100% rename from src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=log.verified.txt rename to src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=log.verified.txt diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=normal.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=normal.verified.txt similarity index 90% rename from src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=normal.verified.txt rename to src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=normal.verified.txt index 8c5733ee..810c1d7e 100644 --- a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=normal.verified.txt +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=normal.verified.txt @@ -1,4 +1,4 @@ Validating {SolutionDirectory}src/Spec.Tests/resources/network_single_device_host.yaml -✗ Validation failed +✕ Validation failed • /: Required properties ["version"] are not present • /network/subnets/0: Required properties ["address"] are not present diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=.verified.txt new file mode 100644 index 00000000..a03c53de --- /dev/null +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=.verified.txt @@ -0,0 +1,4 @@ +Validating {SolutionDirectory}src\Spec.Tests\resources\network_single_device_host.yaml +✕ Validation failed +• /: Required properties ["version"] are not present +• /network/subnets/0: Required properties ["address"] are not present diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=log.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=log.verified.txt new file mode 100644 index 00000000..b7807cca --- /dev/null +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=log.verified.txt @@ -0,0 +1,4 @@ +[