Build.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Threading;
  8. using System.Xml.Linq;
  9. using Nuke.Common;
  10. using Nuke.Common.Git;
  11. using Nuke.Common.ProjectModel;
  12. using Nuke.Common.Tooling;
  13. using Nuke.Common.Tools.DotNet;
  14. using Nuke.Common.Tools.MSBuild;
  15. using Nuke.Common.Tools.Npm;
  16. using Nuke.Common.Utilities;
  17. using Nuke.Common.Utilities.Collections;
  18. using static Nuke.Common.EnvironmentInfo;
  19. using static Nuke.Common.IO.FileSystemTasks;
  20. using static Nuke.Common.IO.PathConstruction;
  21. using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
  22. using static Nuke.Common.Tools.DotNet.DotNetTasks;
  23. using static Nuke.Common.Tools.Xunit.XunitTasks;
  24. using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
  25. /*
  26. Before editing this file, install support plugin for your IDE,
  27. running and debugging a particular target (optionally without deps) would be way easier
  28. ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support
  29. VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support
  30. */
  31. partial class Build : NukeBuild
  32. {
  33. [Solution("Avalonia.sln")] readonly Solution Solution;
  34. static Lazy<string> MsBuildExe = new Lazy<string>(() =>
  35. {
  36. if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  37. return null;
  38. var msBuildDirectory = VSWhere("-latest -nologo -property installationPath -format value -prerelease").FirstOrDefault().Text;
  39. if (!string.IsNullOrWhiteSpace(msBuildDirectory))
  40. {
  41. string msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\Current\Bin\MSBuild.exe");
  42. if (!System.IO.File.Exists(msBuildExe))
  43. msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\15.0\Bin\MSBuild.exe");
  44. return msBuildExe;
  45. }
  46. return null;
  47. }, false);
  48. BuildParameters Parameters { get; set; }
  49. protected override void OnBuildInitialized()
  50. {
  51. Parameters = new BuildParameters(this);
  52. Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.",
  53. Parameters.Version,
  54. Parameters.Configuration,
  55. typeof(NukeBuild).Assembly.GetName().Version.ToString());
  56. if (Parameters.IsLocalBuild)
  57. {
  58. Information("Repository Name: " + Parameters.RepositoryName);
  59. Information("Repository Branch: " + Parameters.RepositoryBranch);
  60. }
  61. Information("Configuration: " + Parameters.Configuration);
  62. Information("IsLocalBuild: " + Parameters.IsLocalBuild);
  63. Information("IsRunningOnUnix: " + Parameters.IsRunningOnUnix);
  64. Information("IsRunningOnWindows: " + Parameters.IsRunningOnWindows);
  65. Information("IsRunningOnAzure:" + Parameters.IsRunningOnAzure);
  66. Information("IsPullRequest: " + Parameters.IsPullRequest);
  67. Information("IsMainRepo: " + Parameters.IsMainRepo);
  68. Information("IsMasterBranch: " + Parameters.IsMasterBranch);
  69. Information("IsReleaseBranch: " + Parameters.IsReleaseBranch);
  70. Information("IsReleasable: " + Parameters.IsReleasable);
  71. Information("IsMyGetRelease: " + Parameters.IsMyGetRelease);
  72. Information("IsNuGetRelease: " + Parameters.IsNuGetRelease);
  73. void ExecWait(string preamble, string command, string args)
  74. {
  75. Console.WriteLine(preamble);
  76. Process.Start(new ProcessStartInfo(command, args) {UseShellExecute = false}).WaitForExit();
  77. }
  78. ExecWait("dotnet version:", "dotnet", "--version");
  79. if (Parameters.IsRunningOnUnix)
  80. ExecWait("Mono version:", "mono", "--version");
  81. }
  82. IReadOnlyCollection<Output> MsBuildCommon(
  83. string projectFile,
  84. Configure<MSBuildSettings> configurator = null)
  85. {
  86. return MSBuild(c => c
  87. .SetProjectFile(projectFile)
  88. // This is required for VS2019 image on Azure Pipelines
  89. .When(Parameters.IsRunningOnWindows &&
  90. Parameters.IsRunningOnAzure, _ => _
  91. .AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_8_X64")))
  92. .AddProperty("PackageVersion", Parameters.Version)
  93. .AddProperty("iOSRoslynPathHackRequired", true)
  94. .SetToolPath(MsBuildExe.Value)
  95. .SetConfiguration(Parameters.Configuration)
  96. .SetVerbosity(MSBuildVerbosity.Minimal)
  97. .Apply(configurator));
  98. }
  99. Target Clean => _ => _.Executes(() =>
  100. {
  101. Parameters.BuildDirs.ForEach(DeleteDirectory);
  102. Parameters.BuildDirs.ForEach(EnsureCleanDirectory);
  103. EnsureCleanDirectory(Parameters.ArtifactsDir);
  104. EnsureCleanDirectory(Parameters.NugetIntermediateRoot);
  105. EnsureCleanDirectory(Parameters.NugetRoot);
  106. EnsureCleanDirectory(Parameters.ZipRoot);
  107. EnsureCleanDirectory(Parameters.TestResultsRoot);
  108. });
  109. Target CompileHtmlPreviewer => _ => _
  110. .DependsOn(Clean)
  111. .Executes(() =>
  112. {
  113. var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp";
  114. NpmTasks.NpmInstall(c => c.SetWorkingDirectory(webappDir));
  115. NpmTasks.NpmRun(c => c
  116. .SetWorkingDirectory(webappDir)
  117. .SetCommand("dist"));
  118. });
  119. Target Compile => _ => _
  120. .DependsOn(Clean)
  121. .DependsOn(CompileHtmlPreviewer)
  122. .Executes(() =>
  123. {
  124. if (Parameters.IsRunningOnWindows)
  125. MsBuildCommon(Parameters.MSBuildSolution, c => c
  126. .SetArgumentConfigurator(a => a.Add("/r"))
  127. .AddTargets("Build")
  128. );
  129. else
  130. DotNetBuild(c => c
  131. .SetProjectFile(Parameters.MSBuildSolution)
  132. .AddProperty("PackageVersion", Parameters.Version)
  133. .SetConfiguration(Parameters.Configuration)
  134. );
  135. });
  136. void RunCoreTest(string projectName)
  137. {
  138. Information($"Running tests from {projectName}");
  139. var project = Solution.GetProject(projectName).NotNull("project != null");
  140. foreach (var fw in project.GetTargetFrameworks())
  141. {
  142. if (fw.StartsWith("net4")
  143. && RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
  144. && Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1")
  145. {
  146. Information($"Skipping {projectName} ({fw}) tests on Linux - https://github.com/mono/mono/issues/13969");
  147. continue;
  148. }
  149. Information($"Running for {projectName} ({fw}) ...");
  150. DotNetTest(c => c
  151. .SetProjectFile(project)
  152. .SetConfiguration(Parameters.Configuration)
  153. .SetFramework(fw)
  154. .EnableNoBuild()
  155. .EnableNoRestore()
  156. .When(Parameters.PublishTestResults, _ => _
  157. .SetLogger("trx")
  158. .SetResultsDirectory(Parameters.TestResultsRoot)));
  159. }
  160. }
  161. Target RunCoreLibsTests => _ => _
  162. .OnlyWhenStatic(() => !Parameters.SkipTests)
  163. .DependsOn(Compile)
  164. .Executes(() =>
  165. {
  166. RunCoreTest("Avalonia.Animation.UnitTests");
  167. RunCoreTest("Avalonia.Base.UnitTests");
  168. RunCoreTest("Avalonia.Controls.UnitTests");
  169. RunCoreTest("Avalonia.Controls.DataGrid.UnitTests");
  170. RunCoreTest("Avalonia.Input.UnitTests");
  171. RunCoreTest("Avalonia.Interactivity.UnitTests");
  172. RunCoreTest("Avalonia.Layout.UnitTests");
  173. RunCoreTest("Avalonia.Markup.UnitTests");
  174. RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
  175. RunCoreTest("Avalonia.Styling.UnitTests");
  176. RunCoreTest("Avalonia.Visuals.UnitTests");
  177. RunCoreTest("Avalonia.Skia.UnitTests");
  178. RunCoreTest("Avalonia.ReactiveUI.UnitTests");
  179. });
  180. Target RunRenderTests => _ => _
  181. .OnlyWhenStatic(() => !Parameters.SkipTests)
  182. .DependsOn(Compile)
  183. .Executes(() =>
  184. {
  185. RunCoreTest("Avalonia.Skia.RenderTests");
  186. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  187. RunCoreTest("Avalonia.Direct2D1.RenderTests");
  188. });
  189. Target RunDesignerTests => _ => _
  190. .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
  191. .DependsOn(Compile)
  192. .Executes(() =>
  193. {
  194. RunCoreTest("Avalonia.DesignerSupport.Tests");
  195. });
  196. [PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit;
  197. Target RunLeakTests => _ => _
  198. .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
  199. .DependsOn(Compile)
  200. .Executes(() =>
  201. {
  202. var testAssembly = "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll";
  203. DotMemoryUnit(
  204. $"{XunitPath.DoubleQuoteIfNeeded()} --propagate-exit-code -- {testAssembly}",
  205. timeout: 120_000);
  206. });
  207. Target ZipFiles => _ => _
  208. .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package)
  209. .Executes(() =>
  210. {
  211. var data = Parameters;
  212. Zip(data.ZipCoreArtifacts, data.BinRoot);
  213. Zip(data.ZipNuGetArtifacts, data.NugetRoot);
  214. Zip(data.ZipTargetControlCatalogDesktopDir,
  215. GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dll").Concat(
  216. GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.config")).Concat(
  217. GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.so")).Concat(
  218. GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dylib")).Concat(
  219. GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.exe")));
  220. });
  221. Target CreateIntermediateNugetPackages => _ => _
  222. .DependsOn(Compile)
  223. .After(RunTests)
  224. .Executes(() =>
  225. {
  226. if (Parameters.IsRunningOnWindows)
  227. MsBuildCommon(Parameters.MSBuildSolution, c => c
  228. .AddTargets("Pack"));
  229. else
  230. DotNetPack(c => c
  231. .SetProject(Parameters.MSBuildSolution)
  232. .SetConfiguration(Parameters.Configuration)
  233. .AddProperty("PackageVersion", Parameters.Version));
  234. });
  235. Target CreateNugetPackages => _ => _
  236. .DependsOn(CreateIntermediateNugetPackages)
  237. .Executes(() =>
  238. {
  239. BuildTasksPatcher.PatchBuildTasksInPackage(Parameters.NugetIntermediateRoot / "Avalonia.Build.Tasks." +
  240. Parameters.Version + ".nupkg");
  241. var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.config");
  242. EnsureCleanDirectory(Parameters.NugetRoot);
  243. if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
  244. new NumergeNukeLogger()))
  245. throw new Exception("Package merge failed");
  246. });
  247. Target RunTests => _ => _
  248. .DependsOn(RunCoreLibsTests)
  249. .DependsOn(RunRenderTests)
  250. .DependsOn(RunDesignerTests)
  251. .DependsOn(RunLeakTests);
  252. Target Package => _ => _
  253. .DependsOn(RunTests)
  254. .DependsOn(CreateNugetPackages);
  255. Target CiAzureLinux => _ => _
  256. .DependsOn(RunTests);
  257. Target CiAzureOSX => _ => _
  258. .DependsOn(Package)
  259. .DependsOn(ZipFiles);
  260. Target CiAzureWindows => _ => _
  261. .DependsOn(Package)
  262. .DependsOn(ZipFiles);
  263. public static int Main() =>
  264. RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
  265. ? Execute<Build>(x => x.Package)
  266. : Execute<Build>(x => x.RunTests);
  267. }
  268. public static class ToolSettingsExtensions
  269. {
  270. public static T Apply<T>(this T settings, Configure<T> configurator)
  271. {
  272. return configurator != null ? configurator(settings) : settings;
  273. }
  274. }