Build.cs 23 KB

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