diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dbf0b9b8..e4f763d7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -42,7 +42,8 @@ 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 diff --git a/.github/workflows/ci_windows.yaml b/.github/workflows/ci_windows.yaml new file mode 100644 index 00000000..0984b985 --- /dev/null +++ b/.github/workflows/ci_windows.yaml @@ -0,0 +1,55 @@ +name: 🔁 🪟 CI +permissions: + contents: read + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + workflow_dispatch: + inputs: + verbosity: + description: 'MSBuild verbosity level' + required: false + default: 'normal' + type: choice + options: + - 'quiet' + - 'minimal' + - 'normal' + - 'detailed' + - 'diagnostic' + +jobs: + test: + 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 + + # TODO fix publish warnings and re-enable check + - 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 bf0a3b58..4f69f821 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -148,6 +148,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/Drift.sln b/Drift.sln index d29c2422..f67db7ee 100644 --- a/Drift.sln +++ b/Drift.sln @@ -61,6 +61,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workflows", "Workflows", "{ .github\workflows\ci.yaml = .github\workflows\ci.yaml .github\workflows\release.yaml = .github\workflows\release.yaml .github\workflows\prerelease.yaml = .github\workflows\prerelease.yaml + .github\workflows\ci_windows.yaml = .github\workflows\ci_windows.yaml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cli.E2ETests.Abstractions", "src\Cli.E2ETests.Abstractions\Cli.E2ETests.Abstractions.csproj", "{A2CE629F-8D56-4539-9642-C31B550F7C30}" 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 1057e5c9..12dd5551 100644 --- a/build/NukeBuild.Container.cs +++ b/build/NukeBuild.Container.cs @@ -4,6 +4,7 @@ using HLabs.Containers; using Nuke.Common; using Nuke.Common.Tools.Docker; +using Nuke.Common.Tools.DotNet; using Serilog; // ReSharper disable VariableHidesOuterVariable @@ -25,6 +26,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 dfb2e038..fe611918 100644 --- a/build/NukeBuild.Test.cs +++ b/build/NukeBuild.Test.cs @@ -17,6 +17,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,38 +78,37 @@ sealed partial class NukeBuild { var version = await Versioning.Value.GetVersionAsync(); - 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 }, - // TODO use this! - // { "DRIFT_CONTAINER_IMAGE_REF", ImageReference.Localhost( "drift", version ).ToString() } - { "DRIFT_CONTAINER_IMAGE_REF", ImageReference.Localhost( "drift", version ).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 }, + // TODO use this! + // { "DRIFT_CONTAINER_IMAGE_REF", ImageReference.Localhost( "drift", version ).ToString() } + { "DRIFT_CONTAINER_IMAGE_REF", ImageReference.Localhost( "drift", version ).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/DriftImageFixture.cs b/src/Cli.E2ETests/DriftImageFixture.cs index 39597418..ddb8d635 100644 --- a/src/Cli.E2ETests/DriftImageFixture.cs +++ b/src/Cli.E2ETests/DriftImageFixture.cs @@ -5,6 +5,8 @@ namespace Drift.Cli.E2ETests; +// TODO can run on linux too, as long as the image is available from the Windows CI runner +[Platform("Linux")] internal abstract class DriftImageFixture { protected static ImageReference DriftImage { get; 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.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 100% 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 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 100% 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 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..141e68ec --- /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 @@ +[