Build.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.IO.Compression;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Threading.Tasks;
  8. using System.Xml.Linq;
  9. using Nuke.Common;
  10. using Nuke.Common.Tooling;
  11. using Nuke.Common.Tools.DotNet;
  12. using Nuke.Common.Tools.Npm;
  13. using static Nuke.Common.EnvironmentInfo;
  14. using static Nuke.Common.IO.PathConstruction;
  15. using static Nuke.Common.Tools.DotNet.DotNetTasks;
  16. using static Serilog.Log;
  17. using MicroCom.CodeGenerator;
  18. using NuGet.Configuration;
  19. using NuGet.Versioning;
  20. using Nuke.Common.CI.AzurePipelines;
  21. using Nuke.Common.IO;
  22. /*
  23. Before editing this file, install support plugin for your IDE,
  24. running and debugging a particular target (optionally without deps) would be way easier
  25. ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support
  26. VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support
  27. */
  28. partial class Build : NukeBuild
  29. {
  30. BuildParameters Parameters { get; set; }
  31. #nullable enable
  32. ApiDiffHelper.GlobalDiffInfo? GlobalDiff { get; set; }
  33. #nullable restore
  34. [NuGetPackage("Microsoft.DotNet.ApiCompat.Tool", "Microsoft.DotNet.ApiCompat.Tool.dll", Framework = "net8.0")]
  35. Tool ApiCompatTool;
  36. [NuGetPackage("Microsoft.DotNet.ApiDiff.Tool", "Microsoft.DotNet.ApiDiff.Tool.dll", Framework = "net8.0")]
  37. Tool ApiDiffTool;
  38. [NuGetPackage("dotnet-ilrepack", "ILRepackTool.dll", Framework = "net8.0")]
  39. Tool IlRepackTool;
  40. protected override void OnBuildInitialized()
  41. {
  42. Parameters = new BuildParameters(this, ScheduledTargets.Contains(BuildToNuGetCache));
  43. Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.",
  44. Parameters.Version,
  45. Parameters.Configuration,
  46. typeof(NukeBuild).Assembly.GetName().Version.ToString());
  47. if (Parameters.IsLocalBuild)
  48. {
  49. Information("Repository Name: " + Parameters.RepositoryName);
  50. Information("Repository Branch: " + Parameters.RepositoryBranch);
  51. }
  52. Information("Configuration: " + Parameters.Configuration);
  53. Information("IsLocalBuild: " + Parameters.IsLocalBuild);
  54. Information("IsRunningOnUnix: " + Parameters.IsRunningOnUnix);
  55. Information("IsRunningOnWindows: " + Parameters.IsRunningOnWindows);
  56. Information("IsRunningOnAzure:" + Parameters.IsRunningOnAzure);
  57. Information("IsPullRequest: " + Parameters.IsPullRequest);
  58. Information("IsMainRepo: " + Parameters.IsMainRepo);
  59. Information("IsMasterBranch: " + Parameters.IsMasterBranch);
  60. Information("IsReleaseBranch: " + Parameters.IsReleaseBranch);
  61. Information("IsReleasable: " + Parameters.IsReleasable);
  62. Information("IsMyGetRelease: " + Parameters.IsMyGetRelease);
  63. Information("IsNuGetRelease: " + Parameters.IsNuGetRelease);
  64. void ExecWait(string preamble, string command, string args)
  65. {
  66. Console.WriteLine(preamble);
  67. Process.Start(new ProcessStartInfo(command, args) {UseShellExecute = false}).WaitForExit();
  68. }
  69. ExecWait("dotnet version:", "dotnet", "--info");
  70. ExecWait("dotnet workloads:", "dotnet", "workload list");
  71. Information("Processor count: " + Environment.ProcessorCount);
  72. Information("Available RAM: " + GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 0x100000 + "MB");
  73. if (Host is AzurePipelines azurePipelines)
  74. azurePipelines.UpdateBuildNumber(Parameters.Version);
  75. }
  76. DotNetConfigHelper ApplySettingCore(DotNetConfigHelper c)
  77. {
  78. if (Parameters.IsRunningOnAzure)
  79. c.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_11_X64"));
  80. c.AddProperty("PackageVersion", Parameters.Version)
  81. .SetConfiguration(Parameters.Configuration)
  82. .SetVerbosity(DotNetVerbosity.minimal);
  83. if (Parameters.IsPackingToLocalCache)
  84. c
  85. .AddProperty("ForcePackAvaloniaNative", "True")
  86. .AddProperty("SkipObscurePlatforms", "True")
  87. .AddProperty("SkipBuildingSamples", "True")
  88. .AddProperty("SkipBuildingTests", "True");
  89. return c;
  90. }
  91. DotNetBuildSettings ApplySetting(DotNetBuildSettings c, Configure<DotNetBuildSettings> configurator = null) =>
  92. ApplySettingCore(c).Build.Apply(configurator);
  93. DotNetPackSettings ApplySetting(DotNetPackSettings c, Configure<DotNetPackSettings> configurator = null) =>
  94. ApplySettingCore(c).Pack.Apply(configurator);
  95. DotNetTestSettings ApplySetting(DotNetTestSettings c, Configure<DotNetTestSettings> configurator = null) =>
  96. ApplySettingCore(c).Test.Apply(configurator);
  97. Target Clean => _ => _.Executes(() =>
  98. {
  99. foreach (var buildDir in Parameters.BuildDirs)
  100. {
  101. Information("Deleting {Directory}", buildDir);
  102. buildDir.DeleteDirectory();
  103. }
  104. CleanDirectory(Parameters.ArtifactsDir);
  105. CleanDirectory(Parameters.NugetIntermediateRoot);
  106. CleanDirectory(Parameters.NugetRoot);
  107. CleanDirectory(Parameters.ZipRoot);
  108. CleanDirectory(Parameters.TestResultsRoot);
  109. void CleanDirectory(AbsolutePath path)
  110. {
  111. Information("Cleaning {Path}", path);
  112. path.CreateOrCleanDirectory();
  113. }
  114. });
  115. Target CompileHtmlPreviewer => _ => _
  116. .DependsOn(Clean)
  117. .OnlyWhenStatic(() => !Parameters.SkipPreviewer)
  118. .Executes(() =>
  119. {
  120. var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp";
  121. NpmTasks.NpmInstall(c => c
  122. .SetProcessWorkingDirectory(webappDir)
  123. .SetProcessAdditionalArguments("--silent"));
  124. NpmTasks.NpmRun(c => c
  125. .SetProcessWorkingDirectory(webappDir)
  126. .SetCommand("dist"));
  127. });
  128. Target CompileNative => _ => _
  129. .DependsOn(Clean)
  130. .DependsOn(GenerateCppHeaders)
  131. .OnlyWhenStatic(() => EnvironmentInfo.IsOsx)
  132. .Executes(() =>
  133. {
  134. var project = $"{RootDirectory}/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/";
  135. var args = $"-project {project} -configuration {Parameters.Configuration} CONFIGURATION_BUILD_DIR={RootDirectory}/Build/Products/Release";
  136. ProcessTasks.StartProcess("xcodebuild", args).AssertZeroExitCode();
  137. });
  138. Target Compile => _ => _
  139. .DependsOn(Clean, CompileNative)
  140. .DependsOn(CompileHtmlPreviewer)
  141. .Executes(() =>
  142. {
  143. DotNetBuild(c => ApplySetting(c)
  144. .SetProjectFile(Parameters.MSBuildSolution)
  145. );
  146. });
  147. Target OutputVersion => _ => _
  148. .Requires(() => VersionOutputDir)
  149. .Executes(() =>
  150. {
  151. var versionFile = Path.Combine(Parameters.VersionOutputDir, "version.txt");
  152. var currentBuildVersion = Parameters.Version;
  153. Console.WriteLine("Version is: " + currentBuildVersion);
  154. File.WriteAllText(versionFile, currentBuildVersion);
  155. var prIdFile = Path.Combine(Parameters.VersionOutputDir, "prId.txt");
  156. var prId = Environment.GetEnvironmentVariable("SYSTEM_PULLREQUEST_PULLREQUESTNUMBER");
  157. Console.WriteLine("PR Number is: " + prId);
  158. File.WriteAllText(prIdFile, prId);
  159. });
  160. void RunCoreTest(string projectName)
  161. {
  162. Information($"Running tests from {projectName}");
  163. var project = RootDirectory.GlobFiles(@$"**\{projectName}.csproj").FirstOrDefault()
  164. ?? throw new InvalidOperationException($"Project {projectName} doesn't exist");
  165. // Nuke and MSBuild tools have build-in helpers to get target frameworks from the project.
  166. // Unfortunately, it gets broken with every second SDK update, so we had to do it manually.
  167. var fileXml = XDocument.Parse(File.ReadAllText(project));
  168. var targetFrameworks = fileXml.Descendants("TargetFrameworks")
  169. .FirstOrDefault()?.Value.Split(';').Select(f => f.Trim());
  170. if (targetFrameworks is null)
  171. {
  172. var targetFramework = fileXml.Descendants("TargetFramework").FirstOrDefault()?.Value;
  173. if (targetFramework is not null)
  174. {
  175. targetFrameworks = new[] { targetFramework };
  176. }
  177. }
  178. if (targetFrameworks is null)
  179. {
  180. throw new InvalidOperationException("No target frameworks were found in the test project");
  181. }
  182. foreach (var fw in targetFrameworks)
  183. {
  184. var tfm = fw;
  185. if (tfm == "$(AvsCurrentTargetFramework)")
  186. {
  187. tfm = "net8.0";
  188. }
  189. if (tfm == "$(AvsLegacyTargetFrameworks)")
  190. {
  191. tfm = "net6.0";
  192. }
  193. if (tfm.StartsWith("net4")
  194. && (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  195. && Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1")
  196. {
  197. Information($"Skipping {projectName} ({tfm}) tests on *nix - https://github.com/mono/mono/issues/13969");
  198. continue;
  199. }
  200. Information($"Running for {projectName} ({tfm}) ...");
  201. DotNetTest(c => ApplySetting(c)
  202. .SetProjectFile(project)
  203. .SetFramework(tfm)
  204. .EnableNoBuild()
  205. .EnableNoRestore()
  206. .When(_ => Parameters.PublishTestResults, _ => _
  207. .SetLoggers("trx")
  208. .SetResultsDirectory(Parameters.TestResultsRoot)));
  209. }
  210. }
  211. Target RunHtmlPreviewerTests => _ => _
  212. .DependsOn(CompileHtmlPreviewer)
  213. .OnlyWhenStatic(() => !(Parameters.SkipPreviewer || Parameters.SkipTests))
  214. .Executes(() =>
  215. {
  216. var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp";
  217. NpmTasks.NpmInstall(c => c
  218. .SetProcessWorkingDirectory(webappTestDir)
  219. .SetProcessAdditionalArguments("--silent"));
  220. NpmTasks.NpmRun(c => c
  221. .SetProcessWorkingDirectory(webappTestDir)
  222. .SetCommand("test"));
  223. });
  224. Target RunCoreLibsTests => _ => _
  225. .OnlyWhenStatic(() => !Parameters.SkipTests)
  226. .DependsOn(Compile)
  227. .Executes(() =>
  228. {
  229. RunCoreTest("Avalonia.Base.UnitTests");
  230. RunCoreTest("Avalonia.Controls.UnitTests");
  231. RunCoreTest("Avalonia.Markup.UnitTests");
  232. RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
  233. RunCoreTest("Avalonia.Skia.UnitTests");
  234. RunCoreTest("Avalonia.ReactiveUI.UnitTests");
  235. RunCoreTest("Avalonia.Headless.NUnit.UnitTests");
  236. RunCoreTest("Avalonia.Headless.XUnit.UnitTests");
  237. });
  238. Target RunRenderTests => _ => _
  239. .OnlyWhenStatic(() => !Parameters.SkipTests)
  240. .DependsOn(Compile)
  241. .Executes(() =>
  242. {
  243. RunCoreTest("Avalonia.Skia.RenderTests");
  244. if (Parameters.IsRunningOnWindows)
  245. RunCoreTest("Avalonia.Direct2D1.RenderTests");
  246. });
  247. Target RunToolsTests => _ => _
  248. .OnlyWhenStatic(() => !Parameters.SkipTests)
  249. .DependsOn(Compile)
  250. .Executes(() =>
  251. {
  252. RunCoreTest("Avalonia.Generators.Tests");
  253. if (Parameters.IsRunningOnWindows)
  254. RunCoreTest("Avalonia.DesignerSupport.Tests");
  255. });
  256. Target RunLeakTests => _ => _
  257. .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
  258. .DependsOn(Compile)
  259. .Executes(() =>
  260. {
  261. void DoMemoryTest()
  262. {
  263. RunCoreTest("Avalonia.LeakTests");
  264. }
  265. ControlFlow.ExecuteWithRetry(DoMemoryTest, delay: TimeSpan.FromMilliseconds(3));
  266. });
  267. Target ZipFiles => _ => _
  268. .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package)
  269. .Executes(() =>
  270. {
  271. var data = Parameters;
  272. Zip(data.ZipNuGetArtifacts, data.NugetRoot);
  273. });
  274. Target CreateIntermediateNugetPackages => _ => _
  275. .DependsOn(Compile)
  276. .After(RunTests)
  277. .Executes(() =>
  278. {
  279. DotNetPack(c => ApplySetting(c).SetProject(Parameters.MSBuildSolution));
  280. });
  281. Target CreateNugetPackages => _ => _
  282. .DependsOn(CreateIntermediateNugetPackages)
  283. .Executes(() =>
  284. {
  285. BuildTasksPatcher.PatchBuildTasksInPackage(Parameters.NugetIntermediateRoot / "Avalonia.Build.Tasks." +
  286. Parameters.Version + ".nupkg",
  287. IlRepackTool);
  288. var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.config");
  289. Parameters.NugetRoot.CreateOrCleanDirectory();
  290. if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
  291. new NumergeNukeLogger()))
  292. throw new Exception("Package merge failed");
  293. RefAssemblyGenerator.GenerateRefAsmsInPackage(
  294. Parameters.NugetRoot / $"Avalonia.{Parameters.Version}.nupkg",
  295. Parameters.NugetRoot / $"Avalonia.{Parameters.Version}.snupkg");
  296. });
  297. Target DownloadApiBaselinePackages => _ => _
  298. .DependsOn(CreateNugetPackages)
  299. .Executes(async () =>
  300. {
  301. GlobalDiff = await ApiDiffHelper.DownloadAndExtractPackagesAsync(
  302. Directory.EnumerateFiles(Parameters.NugetRoot, "*.nupkg").Select(path => (AbsolutePath)path),
  303. NuGetVersion.Parse(Parameters.Version),
  304. Parameters.IsReleaseBranch,
  305. Parameters.ArtifactsDir / "api-diff" / "assemblies",
  306. Parameters.ForceApiValidationBaseline is { } forcedBaseline ? NuGetVersion.Parse(forcedBaseline) : null);
  307. });
  308. Target ValidateApiDiff => _ => _
  309. .DependsOn(DownloadApiBaselinePackages)
  310. .Executes(() =>
  311. {
  312. var globalDiff = GlobalDiff!;
  313. Parallel.ForEach(
  314. globalDiff.Packages,
  315. packageDiff => ApiDiffHelper.ValidatePackage(
  316. ApiCompatTool,
  317. packageDiff,
  318. Parameters.ArtifactsDir / "api-diff" / "assemblies",
  319. Parameters.ApiValidationSuppressionFiles,
  320. Parameters.UpdateApiValidationSuppression));
  321. });
  322. Target OutputApiDiff => _ => _
  323. .DependsOn(DownloadApiBaselinePackages)
  324. .Executes(() =>
  325. {
  326. var globalDiff = GlobalDiff!;
  327. var outputFolderPath = Parameters.ArtifactsDir / "api-diff" / "markdown";
  328. var baselineDisplay = globalDiff.BaselineVersion.ToString();
  329. var currentDisplay = globalDiff.CurrentVersion.ToString();
  330. Parallel.ForEach(
  331. globalDiff.Packages,
  332. packageDiff => ApiDiffHelper.GenerateMarkdownDiff(
  333. ApiDiffTool,
  334. packageDiff,
  335. outputFolderPath,
  336. baselineDisplay,
  337. currentDisplay));
  338. ApiDiffHelper.MergePackageMarkdownDiffFiles(outputFolderPath, baselineDisplay, currentDisplay);
  339. });
  340. Target RunTests => _ => _
  341. .DependsOn(RunCoreLibsTests)
  342. .DependsOn(RunRenderTests)
  343. .DependsOn(RunToolsTests)
  344. .DependsOn(RunHtmlPreviewerTests)
  345. .DependsOn(RunLeakTests);
  346. Target Package => _ => _
  347. .DependsOn(RunTests)
  348. .DependsOn(CreateNugetPackages)
  349. .DependsOn(ValidateApiDiff);
  350. Target CiAzureLinux => _ => _
  351. .DependsOn(RunTests);
  352. Target CiAzureOSX => _ => _
  353. .DependsOn(Package)
  354. .DependsOn(ZipFiles);
  355. Target CiAzureWindows => _ => _
  356. .DependsOn(Package)
  357. .DependsOn(VerifyXamlCompilation)
  358. .DependsOn(ZipFiles);
  359. Target BuildToNuGetCache => _ => _
  360. .DependsOn(CreateNugetPackages)
  361. .Executes(() =>
  362. {
  363. if (!Parameters.IsPackingToLocalCache)
  364. throw new InvalidOperationException();
  365. var globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder(
  366. Settings.LoadDefaultSettings(RootDirectory));
  367. foreach (var path in Parameters.NugetRoot.GlobFiles("*.nupkg"))
  368. {
  369. using var f = File.Open(path.ToString(), FileMode.Open, FileAccess.Read);
  370. using var zip = new ZipArchive(f, ZipArchiveMode.Read);
  371. var nuspecEntry = zip.Entries.First(e => e.FullName.EndsWith(".nuspec") && e.FullName == e.Name);
  372. var packageId = XDocument.Load(nuspecEntry.Open()).Document.Root
  373. .Elements().First(x => x.Name.LocalName == "metadata")
  374. .Elements().First(x => x.Name.LocalName == "id").Value;
  375. var packagePath = Path.Combine(
  376. globalPackagesFolder,
  377. packageId.ToLowerInvariant(),
  378. BuildParameters.LocalBuildVersion);
  379. if (Directory.Exists(packagePath))
  380. Directory.Delete(packagePath, true);
  381. Directory.CreateDirectory(packagePath);
  382. zip.ExtractToDirectory(packagePath);
  383. File.WriteAllText(Path.Combine(packagePath, ".nupkg.metadata"), @"{
  384. ""version"": 2,
  385. ""contentHash"": ""e900dFK7jHJ2WcprLcgJYQoOMc6ejRTwAAMi0VGOFbSczcF98ZDaqwoQIiyqpAwnja59FSbV+GUUXfc3vaQ2Jg=="",
  386. ""source"": ""https://api.nuget.org/v3/index.json""
  387. }");
  388. }
  389. });
  390. Target GenerateCppHeaders => _ => _.Executes(() =>
  391. {
  392. var file = MicroComCodeGenerator.Parse(
  393. File.ReadAllText(RootDirectory / "src" / "Avalonia.Native" / "avn.idl"));
  394. File.WriteAllText(RootDirectory / "native" / "Avalonia.Native" / "inc" / "avalonia-native.h",
  395. file.GenerateCppHeader());
  396. });
  397. Target VerifyXamlCompilation => _ => _
  398. .DependsOn(CreateNugetPackages)
  399. .Executes(() =>
  400. {
  401. var buildTestsDirectory = RootDirectory / "tests" / "BuildTests";
  402. var artifactsDirectory = buildTestsDirectory / "artifacts";
  403. var nugetCacheDirectory = artifactsDirectory / "nuget-cache";
  404. artifactsDirectory.DeleteDirectory();
  405. BuildTestsAndVerify("Debug");
  406. BuildTestsAndVerify("Release");
  407. void BuildTestsAndVerify(string configuration)
  408. {
  409. var configName = configuration.ToLowerInvariant();
  410. DotNetBuild(settings => settings
  411. .SetConfiguration(configuration)
  412. .SetProperty("AvaloniaVersion", Parameters.Version)
  413. .SetProperty("NuGetPackageRoot", nugetCacheDirectory)
  414. .SetPackageDirectory(nugetCacheDirectory)
  415. .SetProjectFile(buildTestsDirectory / "BuildTests.sln")
  416. .SetProcessAdditionalArguments("--nodeReuse:false"));
  417. // Standard compilation - should have compiled XAML
  418. VerifyBuildTestAssembly("bin", "BuildTests");
  419. VerifyBuildTestAssembly("bin", "BuildTests.Android");
  420. VerifyBuildTestAssembly("bin", "BuildTests.Browser");
  421. VerifyBuildTestAssembly("bin", "BuildTests.Desktop");
  422. VerifyBuildTestAssembly("bin", "BuildTests.FSharp");
  423. VerifyBuildTestAssembly("bin", "BuildTests.iOS");
  424. VerifyBuildTestAssembly("bin", "BuildTests.WpfHybrid");
  425. // Publish previously built project without rebuilding - should have compiled XAML
  426. PublishBuildTestProject("BuildTests.Desktop", noBuild: true);
  427. VerifyBuildTestAssembly("publish", "BuildTests.Desktop");
  428. // Publish NativeAOT build, then run it - should not crash and have the expected output
  429. PublishBuildTestProject("BuildTests.NativeAot");
  430. var exeExtension = OperatingSystem.IsWindows() ? ".exe" : null;
  431. XamlCompilationVerifier.VerifyNativeAot(
  432. GetBuildTestOutputPath("publish", "BuildTests.NativeAot", exeExtension));
  433. void PublishBuildTestProject(string projectName, bool? noBuild = null)
  434. => DotNetPublish(settings => settings
  435. .SetConfiguration(configuration)
  436. .SetProperty("AvaloniaVersion", Parameters.Version)
  437. .SetProperty("NuGetPackageRoot", nugetCacheDirectory)
  438. .SetPackageDirectory(nugetCacheDirectory)
  439. .SetNoBuild(noBuild)
  440. .SetProject(buildTestsDirectory / projectName / (projectName + ".csproj"))
  441. .SetProcessAdditionalArguments("--nodeReuse:false"));
  442. void VerifyBuildTestAssembly(string folder, string projectName)
  443. => XamlCompilationVerifier.VerifyAssemblyCompiledXaml(
  444. GetBuildTestOutputPath(folder, projectName, ".dll"));
  445. AbsolutePath GetBuildTestOutputPath(string folder, string projectName, string extension)
  446. => artifactsDirectory / folder / projectName / configName / (projectName + extension);
  447. }
  448. });
  449. public static int Main() =>
  450. RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
  451. ? Execute<Build>(x => x.Package)
  452. : Execute<Build>(x => x.RunTests);
  453. }
  454. public static class ToolSettingsExtensions
  455. {
  456. public static T Apply<T>(this T settings, Configure<T> configurator)
  457. {
  458. return configurator != null ? configurator(settings) : settings;
  459. }
  460. }