Build.cs 12 KB

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