diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 5d902d1..07c5353 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -1,123 +1,145 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/build", - "title": "Build Schema", - "definitions": { - "build": { - "type": "object", - "properties": { - "Configuration": { - "type": "string", - "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", - "enum": [ - "Debug", - "Release" - ] - }, - "Continue": { - "type": "boolean", - "description": "Indicates to continue a previously failed build attempt" - }, - "GitHubAuthenticationToken": { - "type": "string", - "description": "authtoken", - "default": "Secrets must be entered via 'nuke :secrets [profile]'" - }, - "Help": { - "type": "boolean", - "description": "Shows the help text for this build assembly" - }, - "Host": { - "type": "string", - "description": "Host for execution. Default is 'automatic'", - "enum": [ - "AppVeyor", - "AzurePipelines", - "Bamboo", - "Bitbucket", - "Bitrise", - "GitHubActions", - "GitLab", - "Jenkins", - "Rider", - "SpaceAutomation", - "TeamCity", - "Terminal", - "TravisCI", - "VisualStudio", - "VSCode" - ] - }, - "NoLogo": { - "type": "boolean", - "description": "Disables displaying the NUKE logo" - }, - "Partition": { - "type": "string", - "description": "Partition to use on CI" - }, - "Plan": { - "type": "boolean", - "description": "Shows the execution plan (HTML)" - }, - "Profile": { - "type": "array", - "description": "Defines the profiles to load", - "items": { - "type": "string" - } - }, - "Root": { - "type": "string", - "description": "Root directory during build execution" - }, - "Skip": { - "type": "array", - "description": "List of targets to be skipped. Empty list skips all dependencies", - "items": { - "type": "string", - "enum": [ - "Clean", - "PackAndroid", - "PackDebian", - "PackWindows", - "Publish", - "PublishGitHubRelease", - "RestoreWorkloads" - ] - } - }, - "Solution": { - "type": "string", - "description": "Path to a solution file that is automatically loaded" - }, - "Target": { - "type": "array", - "description": "List of targets to be invoked. Default is '{default_target}'", - "items": { - "type": "string", - "enum": [ - "Clean", - "PackAndroid", - "PackDebian", - "PackWindows", - "Publish", - "PublishGitHubRelease", - "RestoreWorkloads" - ] - } - }, - "Verbosity": { - "type": "string", - "description": "Logging verbosity during build execution. Default is 'Normal'", - "enum": [ - "Minimal", - "Normal", - "Quiet", - "Verbose" - ] - } - } - } - } -} +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/build", + "title": "Build Schema", + "definitions": { + "build": { + "type": "object", + "properties": { + "AndroidSigningKeyAlias": { + "type": "string", + "description": "The alias for the key in the keystore" + }, + "AndroidSigningKeyPass": { + "type": "string", + "description": "The password of the key within the keystore file", + "default": "Secrets must be entered via 'nuke :secrets [profile]'" + }, + "AndroidSigningStorePass": { + "type": "string", + "description": "The password for the keystore file", + "default": "Secrets must be entered via 'nuke :secrets [profile]'" + }, + "Base64Keystore": { + "type": "string", + "description": "Contents of the keystore encoded as Base64" + }, + "Configuration": { + "type": "string", + "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", + "enum": [ + "Debug", + "Release" + ] + }, + "Continue": { + "type": "boolean", + "description": "Indicates to continue a previously failed build attempt" + }, + "GitHubAuthenticationToken": { + "type": "string", + "description": "GitHub Authentication Token", + "default": "Secrets must be entered via 'nuke :secrets [profile]'" + }, + "Help": { + "type": "boolean", + "description": "Shows the help text for this build assembly" + }, + "Host": { + "type": "string", + "description": "Host for execution. Default is 'automatic'", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitbucket", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "NoLogo": { + "type": "boolean", + "description": "Disables displaying the NUKE logo" + }, + "Partition": { + "type": "string", + "description": "Partition to use on CI" + }, + "Plan": { + "type": "boolean", + "description": "Shows the execution plan (HTML)" + }, + "Profile": { + "type": "array", + "description": "Defines the profiles to load", + "items": { + "type": "string" + } + }, + "Root": { + "type": "string", + "description": "Root directory during build execution" + }, + "Skip": { + "type": "array", + "description": "List of targets to be skipped. Empty list skips all dependencies", + "items": { + "type": "string", + "enum": [ + "Clean", + "PackAndroid", + "PackAppImages", + "PackDeb", + "PackWindows", + "Publish", + "PublishGitHubRelease", + "PublishLinux", + "RestoreWorkloads" + ] + } + }, + "Solution": { + "type": "string", + "description": "Path to a solution file that is automatically loaded" + }, + "Target": { + "type": "array", + "description": "List of targets to be invoked. Default is '{default_target}'", + "items": { + "type": "string", + "enum": [ + "Clean", + "PackAndroid", + "PackAppImages", + "PackDeb", + "PackWindows", + "Publish", + "PublishGitHubRelease", + "PublishLinux", + "RestoreWorkloads" + ] + } + }, + "Verbosity": { + "type": "string", + "description": "Logging verbosity during build execution. Default is 'Normal'", + "enum": [ + "Minimal", + "Normal", + "Quiet", + "Verbose" + ] + } + } + } + } +} diff --git a/build/Build.cs b/build/Build.cs index 283e4c0..7b337ed 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -1,140 +1,180 @@ -using System; -using System.Linq; -using Nuke.Common; -using Nuke.Common.IO; -using Nuke.Common.ProjectModel; -using Nuke.Common.Tooling; -using Nuke.Common.Tools.GitVersion; -using Nuke.Common.Git; -using Nuke.Common.Tools.DotNet; -using Nuke.Common.Utilities.Collections; -using Nuke.GitHub; -using Serilog; - -using static Nuke.Common.Tools.DotNet.DotNetTasks; -using static Nuke.GitHub.GitHubTasks; -using static Nuke.Common.Tooling.ProcessTasks; - -class Build : NukeBuild -{ - public static int Main() => Execute(x => x.PublishGitHubRelease); - - public AbsolutePath OutputDirectory = RootDirectory / "output"; - public AbsolutePath PublishDirectory => OutputDirectory / "publish"; - public AbsolutePath PackagesDirectory => OutputDirectory / "packages"; - - [Solution] Solution Solution; - [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; - [GitVersion] readonly GitVersion GitVersion; - [GitRepository] readonly GitRepository Repository; - - [Parameter("GitHub Authentication Token")] [Secret] readonly string GitHubAuthenticationToken; - [Parameter("Contents of the keystore encoded as Base64.")] readonly string Base64Keystore; - [Parameter("The alias for the key in the keystore.")] readonly string AndroidSigningKeyAlias; - [Parameter("The password for the keystore file.")][Secret] readonly string AndroidSigningStorePass; - [Parameter("The password of the key within the keystore file.")] [Secret] readonly string AndroidSigningKeyPass; - - Target Clean => td => td - .Executes(() => - { - OutputDirectory.CreateOrCleanDirectory(); - var absolutePaths = RootDirectory.GlobDirectories("**/bin", "**/obj").Where(a => !((string)a).Contains("build")).ToList(); - Log.Information("Deleting {Dirs}", absolutePaths); - absolutePaths.DeleteDirectories(); - }); - - Target RestoreWorkloads => td => td - .Executes(() => - { - StartShell(@$"dotnet workload restore {Solution.Path}").AssertZeroExitCode(); - }); - - Target PackDebian => td => td - .DependsOn(Clean) - .DependsOn(RestoreWorkloads) - .Executes(() => DebPackages.Create(Solution, Configuration, PublishDirectory, PackagesDirectory, GitVersion.MajorMinorPatch)); - - Target PackWindows => td => td - .DependsOn(Clean) - .DependsOn(RestoreWorkloads) - .Executes(() => - { - var desktopProject = Solution.AllProjects.First(project => project.Name.EndsWith("Desktop")); - var runtimes = new[] { "win-x64", }; - - DotNetPublish(settings => settings - .SetConfiguration(Configuration) - .SetProject(desktopProject) - .CombineWith(runtimes, (c, runtime) => - c.SetRuntime(runtime) - .SetOutput(PublishDirectory / runtime))); - - runtimes.ForEach(rt => - { - var src = PublishDirectory / rt; - var zipName = $"{Solution.Name}-{rt.Replace("win", "Windows")}.zip"; - var dest = PackagesDirectory / zipName; - Log.Information("Zipping {Input} to {Output}", src, dest); - src.ZipTo(dest); - }); - }); - - Target PackAndroid => td => td - .DependsOn(Clean) - .DependsOn(RestoreWorkloads) - .Executes(() => - { - var androidProject = Solution.AllProjects.First(project => project.Name.EndsWith("Android")); - var keystore = OutputDirectory / "temp.keystore"; - keystore.WriteAllBytes(Convert.FromBase64String(Base64Keystore)); - - DotNetPublish(settings => settings - .SetProperty("ApplicationVersion", GitVersion.CommitsSinceVersionSource) - .SetProperty("ApplicationDisplayVersion", GitVersion.MajorMinorPatch) - .SetProperty("AndroidKeyStore", "true") - .SetProperty("AndroidSigningKeyStore", keystore) - .SetProperty("AndroidSigningKeyAlias", AndroidSigningKeyAlias) - .SetProperty("AndroidSigningStorePass", AndroidSigningStorePass) - .SetProperty("AndroidSigningKeyPass", AndroidSigningKeyPass) - .SetConfiguration(Configuration) - .SetProject(androidProject) - .SetOutput(PackagesDirectory)); - - keystore.DeleteFile(); - }); - - - Target Publish => td => td - .DependsOn(PackDebian) - .DependsOn(PackWindows) - .DependsOn(PackAndroid); - - Target PublishGitHubRelease => td => td - .OnlyWhenStatic(() => Repository.IsOnMainOrMasterBranch()) - .DependsOn(Publish) - .Requires(() => GitHubAuthenticationToken) - .Executes(async () => - { - var releaseTag = $"v{GitVersion.MajorMinorPatch}"; - - var repositoryInfo = GetGitHubRepositoryInfo(Repository); - - Log.Information("Commit for the release: {GitVersionSha}", GitVersion.Sha); - - Log.Information("Getting list of files in {Path}", PackagesDirectory); - var artifacts = PackagesDirectory.GetFiles().ToList(); - Log.Information("List of files obtained successfully"); - - Assert.NotEmpty(artifacts, - "Could not find any package to upload to the release"); - - await PublishRelease(x => x - .SetArtifactPaths(artifacts.Select(path => (string)path).ToArray()) - .SetCommitSha(GitVersion.Sha) - .SetRepositoryName(repositoryInfo.repositoryName) - .SetRepositoryOwner(repositoryInfo.gitHubOwner) - .SetTag(releaseTag) - .SetToken(GitHubAuthenticationToken) - ); - }); +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Abstractions; +using System.Linq; +using System.Threading.Tasks; +using CSharpFunctionalExtensions; +using DotnetPackaging.AppImage; +using DotnetPackaging.AppImage.Core; +using Nuke.Common; +using Nuke.Common.IO; +using Nuke.Common.ProjectModel; +using Nuke.Common.Tooling; +using Nuke.Common.Tools.GitVersion; +using Nuke.Common.Git; +using Nuke.Common.Tools.DotNet; +using Nuke.Common.Utilities.Collections; +using Nuke.GitHub; +using Serilog; +using Zafiro.FileSystem.Lightweight; +using static Nuke.Common.Tools.DotNet.DotNetTasks; +using static Nuke.GitHub.GitHubTasks; +using static Nuke.Common.Tooling.ProcessTasks; + +class Build : NukeBuild +{ + public static int Main() => Execute(x => x.PublishGitHubRelease); + + public AbsolutePath OutputDirectory = RootDirectory / "output"; + public AbsolutePath PublishDirectory => OutputDirectory / "publish"; + public AbsolutePath PackagesDirectory => OutputDirectory / "packages"; + + [Solution] Solution Solution; + [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; + [GitVersion] readonly GitVersion GitVersion; + [GitRepository] readonly GitRepository Repository; + + [Parameter("GitHub Authentication Token")][Secret] readonly string GitHubAuthenticationToken; + [Parameter("Contents of the keystore encoded as Base64.")] readonly string Base64Keystore; + [Parameter("The alias for the key in the keystore.")] readonly string AndroidSigningKeyAlias; + [Parameter("The password for the keystore file.")][Secret] readonly string AndroidSigningStorePass; + [Parameter("The password of the key within the keystore file.")][Secret] readonly string AndroidSigningKeyPass; + + Target Clean => td => td + .Executes(() => + { + OutputDirectory.CreateOrCleanDirectory(); + var absolutePaths = RootDirectory.GlobDirectories("**/bin", "**/obj").Where(a => !((string)a).Contains("build")).ToList(); + Log.Information("Deleting {Dirs}", absolutePaths); + absolutePaths.DeleteDirectories(); + }); + + Target RestoreWorkloads => td => td + .Executes(() => + { + StartShell(@$"dotnet workload restore {Solution.Path}").AssertZeroExitCode(); + }); + + Target PackDeb => td => td + .DependsOn(Clean) + .DependsOn(RestoreWorkloads) + .Executes(() => DebPackages.Create(Solution, Configuration, PublishDirectory, PackagesDirectory, GitVersion.MajorMinorPatch)); + + Target PublishLinux => td => td + .DependsOn(Clean) + .DependsOn(RestoreWorkloads) + .Executes(() => + { + var desktopProject = Solution.AllProjects.First(project => project.Name.EndsWith("Desktop")); + List runtimes = ["linux-x64", "linux-arm64"]; + DotNetPublish(settings => settings + .SetProject(desktopProject) + .SetConfiguration(Configuration) + .SetSelfContained(true) + .CombineWith(runtimes, (c, runtime) => + c.SetRuntime(runtime) + .SetOutput(PublishDirectory / runtime))); + }); + + Target PackAppImages => td => td + .DependsOn(PublishLinux) + .Executes(() => + { + var fs = new FileSystem(); + var linuxDirs = PublishDirectory.GlobDirectories("linux-*"); + var packagingTasks = linuxDirs.Select(async linuxDir => + { + Debugger.Launch(); + var inputDir = new DirectorioIODirectory(Maybe.None, fs.DirectoryInfo.New(linuxDir)); + var packagePath = PackagesDirectory / Solution.Name + "_" + GitVersion.MajorMinorPatch + "_" + linuxDir.Name + ".appimage"; + packagePath.Parent.CreateDirectory(); + await using var output = fs.File.Open(packagePath, FileMode.Create); + await AppImage.WriteFromBuildDirectory(output, inputDir, Maybe.None); + }); + + return Task.WhenAll(packagingTasks); + }); + + Target PackWindows => td => td + .DependsOn(Clean) + .DependsOn(RestoreWorkloads) + .Executes(() => + { + var desktopProject = Solution.AllProjects.First(project => project.Name.EndsWith("Desktop")); + var runtimes = new[] { "win-x64", }; + + DotNetPublish(settings => settings + .SetConfiguration(Configuration) + .SetProject(desktopProject) + .CombineWith(runtimes, (c, runtime) => + c.SetRuntime(runtime) + .SetOutput(PublishDirectory / runtime))); + + runtimes.ForEach(rt => + { + var src = PublishDirectory / rt; + var zipName = $"{Solution.Name}-{rt.Replace("win", "Windows")}.zip"; + var dest = PackagesDirectory / zipName; + Log.Information("Zipping {Input} to {Output}", src, dest); + src.ZipTo(dest); + }); + }); + + Target PackAndroid => td => td + .DependsOn(Clean) + .DependsOn(RestoreWorkloads) + .Executes(() => + { + var androidProject = Solution.AllProjects.First(project => project.Name.EndsWith("Android")); + var keystore = OutputDirectory / "temp.keystore"; + keystore.WriteAllBytes(Convert.FromBase64String(Base64Keystore)); + + DotNetPublish(settings => settings + .SetProperty("ApplicationVersion", GitVersion.CommitsSinceVersionSource) + .SetProperty("ApplicationDisplayVersion", GitVersion.MajorMinorPatch) + .SetProperty("AndroidKeyStore", "true") + .SetProperty("AndroidSigningKeyStore", keystore) + .SetProperty("AndroidSigningKeyAlias", AndroidSigningKeyAlias) + .SetProperty("AndroidSigningStorePass", AndroidSigningStorePass) + .SetProperty("AndroidSigningKeyPass", AndroidSigningKeyPass) + .SetConfiguration(Configuration) + .SetProject(androidProject) + .SetOutput(PackagesDirectory)); + + keystore.DeleteFile(); + }); + + + Target Publish => td => td.DependsOn(PackDeb, PackWindows, PackAndroid, PackAppImages); + + Target PublishGitHubRelease => td => td + .OnlyWhenStatic(() => Repository.IsOnMainOrMasterBranch()) + .DependsOn(Publish) + .Requires(() => GitHubAuthenticationToken) + .Executes(async () => + { + var releaseTag = $"v{GitVersion.MajorMinorPatch}"; + + var repositoryInfo = GetGitHubRepositoryInfo(Repository); + + Log.Information("Commit for the release: {GitVersionSha}", GitVersion.Sha); + + Log.Information("Getting list of files in {Path}", PackagesDirectory); + var artifacts = PackagesDirectory.GetFiles().ToList(); + Log.Information("List of files obtained successfully"); + + Assert.NotEmpty(artifacts, + "Could not find any package to upload to the release"); + + await PublishRelease(x => x + .SetArtifactPaths(artifacts.Select(path => (string)path).ToArray()) + .SetCommitSha(GitVersion.Sha) + .SetRepositoryName(repositoryInfo.repositoryName) + .SetRepositoryOwner(repositoryInfo.gitHubOwner) + .SetTag(releaseTag) + .SetToken(GitHubAuthenticationToken) + ); + }); } \ No newline at end of file diff --git a/build/DebPackages.cs b/build/DebPackages.cs index d16bd50..a5a927c 100644 --- a/build/DebPackages.cs +++ b/build/DebPackages.cs @@ -36,7 +36,7 @@ public static async Task Create(Solution solution, string projectName = solution.Name; string architecture = runtime.Split("-")[1]; - string packageName = $"{projectName!.Replace(" ", "").ToLower()}_{version}_{architecture}.deb"; + string packageName = $"{projectName!.Replace(" ", "").ToLower()}_{version}_{runtime}.deb"; var fromFile = await new FileInfo(solution.Directory / "metadata.deb.json").ToPackageDefinition(); var packageDefinition = fromFile with diff --git a/build/_build.csproj b/build/_build.csproj index 40b096e..8c03ecb 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -1,19 +1,21 @@  - - Exe - net8.0 - - CS0649;CS0169 - .. - .. - 1 - - - - - - - - - + + Exe + net8.0 + + CS0649;CS0169 + .. + .. + 1 + + + + + + + + + + + \ No newline at end of file