From b051ade22cd976266f0e59679b654a0f9eb604ec Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Mon, 5 Feb 2024 10:35:43 +0200 Subject: [PATCH] Get build running on Linux and MacOS (#3777) --- .gitattributes | 2 +- .github/workflows/build.yml | 24 +++ .github/workflows/pr.yml | 37 ++++- build/Build.CI.GitHubActions.cs | 43 +++--- build/Build.Pack.cs | 1 + build/Build.cs | 140 +++++++++++------- .../Document/ExecuteDocumentCommand.cs | 4 +- .../GenerateSampleSpecificationTests.cs | 4 +- src/NSwag.NoInstaller.slnf | 41 +++++ src/NSwag.sln | 1 + 10 files changed, 219 insertions(+), 78 deletions(-) create mode 100644 src/NSwag.NoInstaller.slnf diff --git a/.gitattributes b/.gitattributes index c41bc636d5..511db42163 100644 --- a/.gitattributes +++ b/.gitattributes @@ -36,7 +36,7 @@ nswag.js text eol=lf *.sass text *.scm text *.scss text -*.sh text +*.sh text eol=lf *.sql text *.styl text *.tpl text diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 08b821ccad..82c3d65546 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,3 +68,27 @@ jobs: with: name: NuGet Packages path: artifacts/*.nupkg + ubuntu-latest: + name: ubuntu-latest + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: 'Run: Compile, Test, Pack, Publish' + run: ./build.cmd Compile Test Pack Publish + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + MYGET_API_KEY: ${{ secrets.MYGET_API_KEY }} + CHOCO_API_KEY: ${{ secrets.CHOCO_API_KEY }} + NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + macos-latest: + name: macos-latest + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - name: 'Run: Compile, Test, Pack, Publish' + run: ./build.cmd Compile Test Pack Publish + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + MYGET_API_KEY: ${{ secrets.MYGET_API_KEY }} + CHOCO_API_KEY: ${{ secrets.CHOCO_API_KEY }} + NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 36077a496c..78bd0912de 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -29,9 +29,6 @@ jobs: windows-latest: name: windows-latest runs-on: windows-latest - concurrency: - group: ${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.run_id }} - cancel-in-progress: true steps: - name: 'Allow long file path' run: git config --system core.longpaths true @@ -44,3 +41,37 @@ jobs: - uses: actions/checkout@v3 - name: 'Run: Compile, Test, Pack' run: ./build.cmd Compile Test Pack + - name: 'Publish: NSwag.zip' + uses: actions/upload-artifact@v3 + with: + name: NSwag.zip + path: artifacts/NSwag.zip + - name: 'Publish: NSwag.Npm.zip' + uses: actions/upload-artifact@v3 + with: + name: NSwag.Npm.zip + path: artifacts/NSwag.Npm.zip + - name: 'Publish: NSwagStudio.msi' + uses: actions/upload-artifact@v3 + with: + name: NSwagStudio.msi + path: artifacts/NSwagStudio.msi + - name: 'Publish: NuGet Packages' + uses: actions/upload-artifact@v3 + with: + name: NuGet Packages + path: artifacts/*.nupkg + ubuntu-latest: + name: ubuntu-latest + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: 'Run: Compile, Test, Pack' + run: ./build.cmd Compile Test Pack + macos-latest: + name: macos-latest + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - name: 'Run: Compile, Test, Pack' + run: ./build.cmd Compile Test Pack diff --git a/build/Build.CI.GitHubActions.cs b/build/Build.CI.GitHubActions.cs index 63df39a1e1..2ad653c7ea 100644 --- a/build/Build.CI.GitHubActions.cs +++ b/build/Build.CI.GitHubActions.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Nuke.Common.CI.GitHubActions; using Nuke.Common.CI.GitHubActions.Configuration; @@ -7,28 +8,28 @@ [CustomGitHubActions( "pr", GitHubActionsImage.WindowsLatest, - // GitHubActionsImage.UbuntuLatest, - // GitHubActionsImage.MacOsLatest, - OnPullRequestBranches = new[] { "master", "main" }, - OnPullRequestIncludePaths = new[] { "**/*.*" }, - OnPullRequestExcludePaths = new[] { "**/*.md" }, - PublishArtifacts = false, - InvokedTargets = new[] { nameof(Compile), nameof(Test), nameof(Pack) }, + GitHubActionsImage.UbuntuLatest, + GitHubActionsImage.MacOsLatest, + OnPullRequestBranches = ["master", "main"], + OnPullRequestIncludePaths = ["**/*.*"], + OnPullRequestExcludePaths = ["**/*.md"], + PublishArtifacts = true, + InvokedTargets = [nameof(Compile), nameof(Test), nameof(Pack)], CacheKeyFiles = new string[0], - JobConcurrencyCancelInProgress = true), + JobConcurrencyCancelInProgress = false), ] [CustomGitHubActions( "build", GitHubActionsImage.WindowsLatest, - // GitHubActionsImage.UbuntuLatest, - // GitHubActionsImage.MacOsLatest, - OnPushBranches = new[] { "master", "main" }, - OnPushTags = new[] { "v*.*.*" }, - OnPushIncludePaths = new[] { "**/*.*" }, - OnPushExcludePaths = new[] { "**/*.md" }, + GitHubActionsImage.UbuntuLatest, + GitHubActionsImage.MacOsLatest, + OnPushBranches = ["master", "main"], + OnPushTags = ["v*.*.*"], + OnPushIncludePaths = ["**/*.*"], + OnPushExcludePaths = ["**/*.md"], PublishArtifacts = true, - InvokedTargets = new[] { nameof(Compile), nameof(Test), nameof(Pack), nameof(Publish) }, - ImportSecrets = new[] { "NUGET_API_KEY", "MYGET_API_KEY", "CHOCO_API_KEY", "NPM_AUTH_TOKEN" }, + InvokedTargets = [nameof(Compile), nameof(Test), nameof(Pack), nameof(Publish)], + ImportSecrets = ["NUGET_API_KEY", "MYGET_API_KEY", "CHOCO_API_KEY", "NPM_AUTH_TOKEN"], CacheKeyFiles = new string[0]) ] public partial class Build @@ -55,11 +56,15 @@ protected override GitHubActionsJob GetJobs(GitHubActionsImage image, IReadOnlyC })); */ - newSteps.Insert(0, new GitHubActionsUseGnuTarStep()); - newSteps.Insert(0, new GitHubActionsConfigureLongPathsStep()); + var onWindows = image.ToString().StartsWith("windows", StringComparison.OrdinalIgnoreCase); + if (onWindows) + { + newSteps.Insert(0, new GitHubActionsUseGnuTarStep()); + newSteps.Insert(0, new GitHubActionsConfigureLongPathsStep()); + } // add artifacts manually as they would otherwise by hard to configure via attributes - if (PublishArtifacts) + if (PublishArtifacts && onWindows) { newSteps.Add(new GitHubActionsArtifactStep { Name = "NSwag.zip", Path = "artifacts/NSwag.zip" }); newSteps.Add(new GitHubActionsArtifactStep { Name = "NSwag.Npm.zip", Path = "artifacts/NSwag.Npm.zip" }); diff --git a/build/Build.Pack.cs b/build/Build.Pack.cs index 46e525f04b..7a0b4e0d76 100644 --- a/build/Build.Pack.cs +++ b/build/Build.Pack.cs @@ -23,6 +23,7 @@ public partial class Build Target Pack => _ => _ .DependsOn(Compile) .After(Test) + .OnlyWhenDynamic(() => IsRunningOnWindows) .Executes(() => { if (Configuration != Configuration.Release) diff --git a/build/Build.cs b/build/Build.cs index e32a3f7c10..fe6a754028 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -51,6 +51,10 @@ public Build() readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; [Solution] readonly Solution Solution; + + // the file we want to build, can be either full solution on Windows or a filtered one on other platforms + AbsolutePath SolutionFile; + [GitRepository] readonly GitRepository GitRepository; AbsolutePath SourceDirectory => RootDirectory / "src"; @@ -85,6 +89,8 @@ string DetermineVersionPrefix() protected override void OnBuildInitialized() { + SolutionFile = IsRunningOnWindows ? Solution.Path : SourceDirectory / "NSwag.NoInstaller.slnf"; + VersionPrefix = DetermineVersionPrefix(); var versionParts = VersionPrefix.Split('-'); @@ -122,6 +128,7 @@ protected override void OnBuildInitialized() Target InstallDependencies => _ => _ .Before(Restore, Compile) + .OnlyWhenDynamic(() => !IsServerBuild) .Executes(() => { Chocolatey("install wixtoolset -y"); @@ -138,16 +145,8 @@ protected override void OnBuildInitialized() .SetProcessWorkingDirectory(SourceDirectory / "NSwag.Npm") ); - MSBuild(x => x - .SetTargetPath(Solution) - .SetTargets("Restore") - .SetMaxCpuCount(Environment.ProcessorCount) - .SetNodeReuse(IsLocalBuild) - .SetVerbosity(MSBuildVerbosity.Minimal) - ); - DotNetRestore(x => x - .SetProjectFile(Solution) + .SetProjectFile(SolutionFile) .SetVerbosity(DotNetVerbosity.minimal) ); }); @@ -162,41 +161,66 @@ protected override void OnBuildInitialized() Serilog.Log.Information("Build and copy full .NET command line with configuration {Configuration}", Configuration); - // TODO: Fix build here - MSBuild(x => x - .SetProjectFile(GetProject("NSwagStudio")) - .SetTargets("Build") - .SetAssemblyVersion(VersionPrefix) - .SetFileVersion(VersionPrefix) - .SetInformationalVersion(VersionPrefix) - .SetConfiguration(Configuration) - .SetMaxCpuCount(Environment.ProcessorCount) - .SetNodeReuse(IsLocalBuild) - .SetVerbosity(MSBuildVerbosity.Minimal) - .SetProperty("Deterministic", IsServerBuild) - .SetProperty("ContinuousIntegrationBuild", IsServerBuild) - ); + if (IsRunningOnWindows) + { + DotNetMSBuild(x => x + .SetTargetPath(GetProject("NSwagStudio")) + .SetAssemblyVersion(VersionPrefix) + .SetFileVersion(VersionPrefix) + .SetInformationalVersion(VersionPrefix) + .SetConfiguration(Configuration) + .SetMaxCpuCount(Environment.ProcessorCount) + .SetNodeReuse(IsLocalBuild) + .SetVerbosity(DotNetVerbosity.minimal) + .SetDeterministic(IsServerBuild) + .SetContinuousIntegrationBuild(IsServerBuild) + // ensure we don't generate too much output in CI run + // 0 Turns off emission of all warning messages + // 1 Displays severe warning messages + .SetWarningLevel(IsServerBuild ? 0 : 1) + ); - MSBuild(x => x - .SetTargetPath(Solution) - .SetTargets("Build") - .SetAssemblyVersion(VersionPrefix) - .SetFileVersion(VersionPrefix) - .SetInformationalVersion(VersionPrefix) - .SetConfiguration(Configuration) - .SetMaxCpuCount(Environment.ProcessorCount) - .SetNodeReuse(IsLocalBuild) - .SetVerbosity(MSBuildVerbosity.Minimal) - .SetProperty("Deterministic", IsServerBuild) - .SetProperty("ContinuousIntegrationBuild", IsServerBuild) - ); + MSBuild(x => x + .SetTargetPath(SolutionFile) + .SetAssemblyVersion(VersionPrefix) + .SetFileVersion(VersionPrefix) + .SetInformationalVersion(VersionPrefix) + .SetConfiguration(Configuration) + .SetMaxCpuCount(Environment.ProcessorCount) + .SetNodeReuse(IsLocalBuild) + .SetVerbosity(MSBuildVerbosity.Minimal) + .SetProperty("Deterministic", IsServerBuild) + .SetProperty("ContinuousIntegrationBuild", IsServerBuild) + // ensure we don't generate too much output in CI run + // 0 Turns off emission of all warning messages + // 1 Displays severe warning messages + .SetWarningLevel(IsServerBuild ? 0 : 1) + ); + } + else + { + DotNetBuild(x => x + .SetProjectFile(SolutionFile) + .SetAssemblyVersion(VersionPrefix) + .SetFileVersion(VersionPrefix) + .SetInformationalVersion(VersionPrefix) + .SetConfiguration(Configuration) + .SetVerbosity(DotNetVerbosity.minimal) + .SetDeterministic(IsServerBuild) + .SetContinuousIntegrationBuild(IsServerBuild) + // ensure we don't generate too much output in CI run + // 0 Turns off emission of all warning messages + // 1 Displays severe warning messages + .SetWarningLevel(IsServerBuild ? 0 : 1) + ); + } // later steps need to have binaries in correct places PublishAndCopyConsoleProjects(); }); Target Test => _ => _ - .After(Compile) + .DependsOn(Compile) .Executes(() => { foreach (var project in Solution.AllProjects.Where(p => p.Name.EndsWith(".Tests"))) @@ -204,6 +228,7 @@ protected override void OnBuildInitialized() DotNetTest(x => x .SetProjectFile(project) .EnableNoRestore() + .EnableNoBuild() .SetConfiguration(Configuration) ); } @@ -230,34 +255,47 @@ void PublishConsoleProject(Project project, string[] targetFrameworks) .SetConfiguration(Configuration) .SetDeterministic(IsServerBuild) .SetContinuousIntegrationBuild(IsServerBuild) + // ensure we don't generate too much output in CI run + // 0 Turns off emission of all warning messages + // 1 Displays severe warning messages + .SetWarningLevel(IsServerBuild ? 0 : 1) ); } } - PublishConsoleProject(consoleX86Project, new[] { "net462" }); - PublishConsoleProject(consoleProject, new[] { "net462" }); - PublishConsoleProject(consoleCoreProject, new[] { "net6.0", "net7.0", "net8.0" }); + if (IsRunningOnWindows) + { + PublishConsoleProject(consoleX86Project, ["net462"]); + PublishConsoleProject(consoleProject, ["net462"]); + } + PublishConsoleProject(consoleCoreProject, ["net6.0", "net7.0", "net8.0"]); void CopyConsoleBinaries(AbsolutePath target) { // take just exe from X86 as other files are shared with console project - var consoleX86Directory = ArtifactsDirectory / "publish" / consoleX86Project.Name / Configuration; - CopyFileToDirectory(consoleX86Directory / "NSwag.x86.exe", target / "Win"); - CopyFileToDirectory(consoleX86Directory / "NSwag.x86.exe.config", target / "Win"); + var configuration = Configuration.ToString().ToLowerInvariant(); - CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleProject.Name / Configuration, target / "Win", DirectoryExistsPolicy.Merge); + if (IsRunningOnWindows) + { + var consoleX86Directory = ArtifactsDirectory / "publish" / consoleX86Project.Name / configuration; + CopyFileToDirectory(consoleX86Directory / "NSwag.x86.exe", target / "Win"); + CopyFileToDirectory(consoleX86Directory / "NSwag.x86.exe.config", target / "Win"); - CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleCoreProject.Name / (Configuration + "_net6.0"), target / "Net60"); - CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleCoreProject.Name / (Configuration + "_net7.0"), target / "Net70"); - CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleCoreProject.Name / (Configuration + "_net8.0"), target / "Net80"); - } + CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleProject.Name / configuration, target / "Win", DirectoryExistsPolicy.Merge); + } - Serilog.Log.Information("Copy published Console for NSwagStudio"); + CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleCoreProject.Name / (configuration + "_net6.0"), target / "Net60"); + CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleCoreProject.Name / (configuration + "_net7.0"), target / "Net70"); + CopyDirectoryRecursively(ArtifactsDirectory / "publish" / consoleCoreProject.Name / (configuration + "_net8.0"), target / "Net80"); + } - CopyConsoleBinaries(target: NSwagStudioBinaries); + if (IsRunningOnWindows) + { + Serilog.Log.Information("Copy published Console for NSwagStudio"); + CopyConsoleBinaries(target: NSwagStudioBinaries); + } Serilog.Log.Information("Copy published Console for NPM"); - CopyConsoleBinaries(target: SourceDirectory / "NSwag.Npm" / "bin" / "binaries"); } diff --git a/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs b/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs index 0cdb9c344d..6c6538ba4f 100644 --- a/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs +++ b/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs @@ -11,7 +11,6 @@ using System.Linq; using System.Threading.Tasks; using NConsole; -using NJsonSchema.Infrastructure; #pragma warning disable 1591 @@ -28,7 +27,8 @@ public class ExecuteDocumentCommand : IConsoleCommand public async Task RunAsync(CommandLineProcessor processor, IConsoleHost host) { - if (!string.IsNullOrEmpty(Input) && !Input.StartsWith("/") && !Input.StartsWith("-")) + // input can be nix-like file path starting with / + if (!string.IsNullOrEmpty(Input) && (!Input.StartsWith("/") || File.Exists(Input) || Input.EndsWith("nswag.json")) && !Input.StartsWith("-")) { await ExecuteDocumentAsync(host, Input); } diff --git a/src/NSwag.ConsoleCore.Tests/GenerateSampleSpecificationTests.cs b/src/NSwag.ConsoleCore.Tests/GenerateSampleSpecificationTests.cs index 8507990e9b..f9db6bf172 100644 --- a/src/NSwag.ConsoleCore.Tests/GenerateSampleSpecificationTests.cs +++ b/src/NSwag.ConsoleCore.Tests/GenerateSampleSpecificationTests.cs @@ -20,9 +20,9 @@ public async Task Should_generate_openapi_for_project(string projectName, string { // Arrange #if DEBUG - const string configuration = "Debug"; + const string configuration = "debug"; #else - const string configuration = "Release"; + const string configuration = "release"; #endif var executablePath = Path.GetFullPath($"../../../../artifacts/bin/NSwag.ConsoleCore/{configuration}_{targetFramework}/dotnet-nswag.dll"); var nswagJsonPath = Path.GetFullPath($"../../../../src/{projectName}/nswag.json"); diff --git a/src/NSwag.NoInstaller.slnf b/src/NSwag.NoInstaller.slnf new file mode 100644 index 0000000000..04cf6b380d --- /dev/null +++ b/src/NSwag.NoInstaller.slnf @@ -0,0 +1,41 @@ +{ + "solution": { + "path": "NSwag.sln", + "projects": [ + "..\\build\\_build.csproj", + "NSwag.Annotations\\NSwag.Annotations.csproj", + "NSwag.AspNet.Owin\\NSwag.AspNet.Owin.csproj", + "NSwag.AspNet.WebApi\\NSwag.AspNet.WebApi.csproj", + "NSwag.AspNetCore.Launcher.x86\\NSwag.AspNetCore.Launcher.x86.csproj", + "NSwag.AspNetCore.Launcher\\NSwag.AspNetCore.Launcher.csproj", + "NSwag.AspNetCore\\NSwag.AspNetCore.csproj", + "NSwag.CodeGeneration.CSharp.Tests\\NSwag.CodeGeneration.CSharp.Tests.csproj", + "NSwag.CodeGeneration.CSharp\\NSwag.CodeGeneration.CSharp.csproj", + "NSwag.CodeGeneration.Tests\\NSwag.CodeGeneration.Tests.csproj", + "NSwag.CodeGeneration.TypeScript.Tests\\NSwag.CodeGeneration.TypeScript.Tests.csproj", + "NSwag.CodeGeneration.TypeScript\\NSwag.CodeGeneration.TypeScript.csproj", + "NSwag.CodeGeneration\\NSwag.CodeGeneration.csproj", + "NSwag.Commands\\NSwag.Commands.csproj", + "NSwag.Console.x86\\NSwag.Console.x86.csproj", + "NSwag.ConsoleCore.Tests\\NSwag.ConsoleCore.Tests.csproj", + "NSwag.ConsoleCore\\NSwag.ConsoleCore.csproj", + "NSwag.Console\\NSwag.Console.csproj", + "NSwag.Core.Tests\\NSwag.Core.Tests.csproj", + "NSwag.Core.Yaml.Tests\\NSwag.Core.Yaml.Tests.csproj", + "NSwag.Core.Yaml\\NSwag.Core.Yaml.csproj", + "NSwag.Core\\NSwag.Core.csproj", + "NSwag.Generation.AspNetCore.Tests.Web\\NSwag.Generation.AspNetCore.Tests.Web.csproj", + "NSwag.Generation.AspNetCore.Tests\\NSwag.Generation.AspNetCore.Tests.csproj", + "NSwag.Generation.AspNetCore\\NSwag.Generation.AspNetCore.csproj", + "NSwag.Generation.Tests\\NSwag.Generation.Tests.csproj", + "NSwag.Generation.WebApi\\NSwag.Generation.WebApi.csproj", + "NSwag.Generation\\NSwag.Generation.csproj", + "NSwag.Sample.NET60Minimal\\NSwag.Sample.NET60Minimal.csproj", + "NSwag.Sample.NET60\\NSwag.Sample.NET60.csproj", + "NSwag.Sample.NET70Minimal\\NSwag.Sample.NET70Minimal.csproj", + "NSwag.Sample.NET70\\NSwag.Sample.NET70.csproj", + "NSwag.Sample.NET80Minimal\\NSwag.Sample.NET80Minimal.csproj", + "NSwag.Sample.NET80\\NSwag.Sample.NET80.csproj" + ] + } +} \ No newline at end of file diff --git a/src/NSwag.sln b/src/NSwag.sln index 3b9ba67007..0f5cf24b4f 100644 --- a/src/NSwag.sln +++ b/src/NSwag.sln @@ -115,6 +115,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "00 Build", "00 Build", "{6F azure-pipelines.yml = ..\azure-pipelines.yml Directory.Build.props = ..\Directory.Build.props global.json = ..\global.json + NSwag.NoInstaller.slnf = NSwag.NoInstaller.slnf EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "..\build\_build.csproj", "{AC3D8125-AE21-49FC-A217-D96C7B585FF9}"