From e232447cba5c59bab5a7630b81f5cb5d95ef8469 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 14:27:13 +0100 Subject: [PATCH 01/15] [ci] Add build for core-clr --- eng/cake/dotnet.cake | 245 ++++++++++-------- .../common/ui-tests-build-sample.yml | 2 +- eng/pipelines/common/ui-tests.yml | 16 ++ 3 files changed, 155 insertions(+), 108 deletions(-) diff --git a/eng/cake/dotnet.cake b/eng/cake/dotnet.cake index ff196d9c368d..011eae4dbbbf 100644 --- a/eng/cake/dotnet.cake +++ b/eng/cake/dotnet.cake @@ -38,12 +38,14 @@ var NuGetOnlyPackages = new string[] { }; public enum RuntimeVariant { - Mono, - NativeAOT + Mono, + NativeAOT, + CoreCLR } RuntimeVariant RUNTIME_VARIANT = Argument("runtimevariant", RuntimeVariant.Mono); bool USE_NATIVE_AOT = RUNTIME_VARIANT == RuntimeVariant.NativeAOT ? true : false; +bool USE_CORECLR = RUNTIME_VARIANT == RuntimeVariant.CoreCLR ? true : false; ProcessTFMSwitches(); @@ -53,11 +55,11 @@ Task("dotnet") .Description("Provisions the .NET SDK into bin/dotnet based on eng/Versions.props") .Does(() => { - if (!localDotnet) + if (!localDotnet) return; //We are passing a nuget folder with nuget locations - if(!string.IsNullOrEmpty(nugetSource)) + if (!string.IsNullOrEmpty(nugetSource)) { EnsureDirectoryExists(nugetSource); var originalNuget = File($"{rootFolder}/NuGet.config"); @@ -72,19 +74,20 @@ Task("dotnet") .SetConfiguration(configuration), }); - DotNetTool("tool", new DotNetToolSettings { - ToolPath = dotnetPath, - DiagnosticOutput = true, - ArgumentCustomization = args => args.Append("restore") - }); + DotNetTool("tool", new DotNetToolSettings + { + ToolPath = dotnetPath, + DiagnosticOutput = true, + ArgumentCustomization = args => args.Append("restore") + }); }); Task("dotnet-local-workloads") .Does(() => { - if (!localDotnet) + if (!localDotnet) return; - + DotNetBuild("./src/DotNet/DotNet.csproj", new DotNetBuildSettings { MSBuildSettings = new DotNetMSBuildSettings() @@ -102,11 +105,12 @@ Task("dotnet-local-workloads") ToolPath = dotnetPath, }); - DotNetTool("tool", new DotNetToolSettings { - ToolPath = dotnetPath, - DiagnosticOutput = true, - ArgumentCustomization = args => args.Append("restore") - }); + DotNetTool("tool", new DotNetToolSettings + { + ToolPath = dotnetPath, + DiagnosticOutput = true, + ArgumentCustomization = args => args.Append("restore") + }); }); Task("dotnet-buildtasks") @@ -158,9 +162,10 @@ Task("dotnet-samples") var properties = new Dictionary(); - if(useNuget) + if (useNuget) { - properties = new Dictionary { + properties = new Dictionary + { ["UseWorkload"] = "true", // ["GenerateAppxPackageOnBuild"] = "true", ["RestoreConfigFile"] = tempDir.CombineWithFilePath("NuGet.config").FullPath, @@ -198,13 +203,25 @@ Task("uitests-apphost") var properties = new Dictionary(); - if(useNuget) + if (USE_CORECLR) { - properties = new Dictionary { - ["UseWorkload"] = "true", - // ["GenerateAppxPackageOnBuild"] = "true", - ["RestoreConfigFile"] = tempDir.CombineWithFilePath("NuGet.config").FullPath, - }; + Information("Building for CoreCLR"); + properties.Add("UseMonoRuntime", "false"); + } + + if (USE_NATIVE_AOT) + { + Information("Building for NativeAOT"); + properties.Add("_UseNativeAot", "true"); + properties.Add("RuntimeIdentifier", "iossimulator-x64"); + } + + if (useNuget) + { + properties.Add("UseWorkload", "true"); + // properties.Add("GenerateAppxPackageOnBuild", "true"); + // We are passing a nuget folder with nuget locations + properties.Add("RestoreConfigFile", tempDir.CombineWithFilePath("NuGet.config").FullPath); } RunMSBuildWithDotNet("./src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj", properties, binlogPrefix: "uitests-apphost-"); }); @@ -234,7 +251,7 @@ Task("dotnet-test") .Description("Build the solutions") .Does(() => { - var tests = new [] + var tests = new[] { "**/Controls.Core.UnitTests.csproj", // "**/Controls.Core.Design.UnitTests.csproj", @@ -252,7 +269,7 @@ Task("dotnet-test") foreach (var test in tests) { - if (!IsRunningOnWindows() && (test.Contains("Compatibility.Core.UnitTests") || test.Contains("Controls.Core.Design.UnitTests"))) + if (!IsRunningOnWindows() && (test.Contains("Compatibility.Core.UnitTests") || test.Contains("Controls.Core.Design.UnitTests"))) { continue; } @@ -292,8 +309,8 @@ Task("dotnet-pack-maui") { sln = "./eng/Microsoft.Maui.Packages-mac.slnf"; } - - if(string.IsNullOrEmpty(officialBuildId)) + + if (string.IsNullOrEmpty(officialBuildId)) { officialBuildId = DateTime.UtcNow.ToString("yyyyMMdd.1"); } @@ -529,47 +546,58 @@ Task("VS") UseLocalNuGetCacheFolder(); StartVisualStudioForDotNet(); - }); + }); Task("GenerateCgManifest") .Description("Generates the cgmanifest.json file with versions from Versions.props") - .Does(() => + .Does(() => { Information("Generating cgmanifest.json from Versions.props"); - + // Use pwsh on all platforms var pwshExecutable = "pwsh"; - + // Check if pwsh is available - try { - if (IsRunningOnWindows()) { - var exitCode = StartProcess("where", new ProcessSettings { + try + { + if (IsRunningOnWindows()) + { + var exitCode = StartProcess("where", new ProcessSettings + { Arguments = "pwsh", - RedirectStandardOutput = true, + RedirectStandardOutput = true, RedirectStandardError = true }); - if (exitCode != 0) { + if (exitCode != 0) + { Information("pwsh not found, falling back to powershell"); pwshExecutable = "powershell"; } - } else { - var exitCode = StartProcess("which", new ProcessSettings { + } + else + { + var exitCode = StartProcess("which", new ProcessSettings + { Arguments = "pwsh", RedirectStandardOutput = true, RedirectStandardError = true }); - if (exitCode != 0) { + if (exitCode != 0) + { throw new Exception("PowerShell Core (pwsh) is not installed. Please install it to continue."); } } - } catch (Exception ex) when (!IsRunningOnWindows()) { + } + catch (Exception ex) when (!IsRunningOnWindows()) + { Error("Error checking for pwsh: " + ex.Message); throw new Exception("PowerShell Core (pwsh) is required on non-Windows platforms. Please install it and try again."); } - + // Execute the PowerShell script - StartProcess(pwshExecutable, new ProcessSettings { + StartProcess(pwshExecutable, new ProcessSettings + { Arguments = "-NonInteractive -ExecutionPolicy Bypass -File ./eng/scripts/update-cgmanifest.ps1" }); }); @@ -582,17 +610,17 @@ Task("publicapi") var controlsPublicApiDir = MakeAbsolute(Directory("./src/Controls/src/Core/PublicAPI")); var essentialsPublicApiDir = MakeAbsolute(Directory("./src/Essentials/src/PublicAPI")); var graphicsPublicApiDir = MakeAbsolute(Directory("./src/Graphics/src/Graphics/PublicAPI")); - + Information("Resetting PublicAPI.Unshipped.txt files..."); - + // Find and clear all PublicAPI.Unshipped.txt files in Core, Controls, Essentials, and Graphics var coreUnshippedFiles = GetFiles($"{corePublicApiDir}/**/PublicAPI.Unshipped.txt"); var controlsUnshippedFiles = GetFiles($"{controlsPublicApiDir}/**/PublicAPI.Unshipped.txt"); var essentialsUnshippedFiles = GetFiles($"{essentialsPublicApiDir}/**/PublicAPI.Unshipped.txt"); var graphicsUnshippedFiles = GetFiles($"{graphicsPublicApiDir}/**/PublicAPI.Unshipped.txt"); var allUnshippedFiles = coreUnshippedFiles.Concat(controlsUnshippedFiles).Concat(essentialsUnshippedFiles).Concat(graphicsUnshippedFiles); - - foreach(var file in allUnshippedFiles) + + foreach (var file in allUnshippedFiles) { // Skip Windows-specific files if not on Windows if (!IsRunningOnWindows() && file.FullPath.Contains("windows")) @@ -600,27 +628,27 @@ Task("publicapi") Information($"Skipping Windows file (not on Windows): {file}"); continue; } - + // Skip Tizen-specific files if (file.FullPath.Contains("tizen")) { Information($"Skipping Tizen file: {file}"); continue; } - + // Skip macOS-specific files if (file.FullPath.Contains("macos")) { Information($"Skipping macOS file: {file}"); continue; } - + Information($"Clearing: {file}"); System.IO.File.WriteAllText(file.FullPath, string.Empty); } - + Information("Regenerating PublicAPI..."); - + // Build Controls.Core.csproj with PublicApiType=Generate var settings = new DotNetBuildSettings { @@ -628,9 +656,9 @@ Task("publicapi") MSBuildSettings = new DotNetMSBuildSettings() }; settings.MSBuildSettings.Properties["PublicApiType"] = new List { "Generate" }; - + DotNetBuild("./src/Controls/src/Core/Controls.Core.csproj", settings); - + Information("PublicAPI reset and regeneration completed!"); }); @@ -647,7 +675,7 @@ bool RunPackTarget() // Does the user want to run a pack as part of a different target? if (HasArgument("pack") && Argument("pack", "true") != "false") return true; - + // If the request is to open a different sln then let's see if pack has ever run // if it hasn't then lets pack maui so the sln will open if (Argument("sln", null) != null) @@ -684,7 +712,7 @@ Dictionary GetDotNetEnvironmentVariables() void SetDotNetEnvironmentVariables(string dotnetDir = null) { var dotnet = dotnetDir ?? MakeAbsolute(Directory("./.dotnet/")).ToString(); - + SetEnvironmentVariable("VSDebugger_ValidateDotnetDebugLibSignatures", "0"); SetEnvironmentVariable("DOTNET_INSTALL_DIR", dotnet); SetEnvironmentVariable("DOTNET_ROOT", dotnet); @@ -724,14 +752,14 @@ void StartVisualStudioCodeForDotNet(bool useInsiders) return; } - if(localDotnet) + if (localDotnet) { SetDotNetEnvironmentVariables(); } string codeProcessName = useInsiders ? "code-insiders" : "code"; - StartProcess(codeProcessName, new ProcessSettings{ EnvironmentVariables = GetDotNetEnvironmentVariables() }); + StartProcess(codeProcessName, new ProcessSettings { EnvironmentVariables = GetDotNetEnvironmentVariables() }); } void StartVisualStudioForDotNet() @@ -761,7 +789,7 @@ void StartVisualStudioForDotNet() return; } - if(localDotnet) + if (localDotnet) { SetDotNetEnvironmentVariables(); } @@ -771,13 +799,13 @@ void StartVisualStudioForDotNet() var vsLatest = VSWhereLatest(new VSWhereLatestSettings { IncludePrerelease = includePrerelease, }); if (vsLatest == null) throw new Exception("Unable to find Visual Studio!"); - + StartProcess(vsLatest.CombineWithFilePath("./Common7/IDE/devenv.exe"), sln); } else { - - StartProcess("open", new ProcessSettings{ Arguments = sln, EnvironmentVariables = GetDotNetEnvironmentVariables() }); + + StartProcess("open", new ProcessSettings { Arguments = sln, EnvironmentVariables = GetDotNetEnvironmentVariables() }); } } @@ -801,8 +829,8 @@ void RunMSBuildWithDotNet( var binlog = string.IsNullOrEmpty(targetFramework) ? $"\"{GetLogDirectory()}/{binlogPrefix}{name}-{configuration}-{target}-{type}-{DateTime.UtcNow.ToFileTimeUtc()}.binlog\"" : $"\"{GetLogDirectory()}/{binlogPrefix}{name}-{configuration}-{target}-{targetFramework}-{type}-{DateTime.UtcNow.ToFileTimeUtc()}.binlog\""; - - if(localDotnet) + + if (localDotnet) SetDotNetEnvironmentVariables(); var msbuildSettings = new DotNetMSBuildSettings() @@ -810,8 +838,8 @@ void RunMSBuildWithDotNet( .SetMaxCpuCount(maxCpuCount) .WithTarget(target) .EnableBinaryLogger(binlog) - - // .SetVerbosity(Verbosity.Diagnostic) + + // .SetVerbosity(Verbosity.Diagnostic) ; if (warningsAsError) @@ -839,7 +867,7 @@ void RunMSBuildWithDotNet( if (!string.IsNullOrEmpty(targetFramework)) args.Append($"-f {targetFramework}"); - + return args; }; @@ -849,7 +877,7 @@ void RunMSBuildWithDotNet( DotNetBuild(sln, dotnetBuildSettings); } -void RunTestWithLocalDotNet(string csproj, string config, string pathDotnet = null, Dictionary argsExtra = null, bool noBuild = false, string resultsFileNameWithoutExtension = null, string filter = "", int maxCpuCount = 0) +void RunTestWithLocalDotNet(string csproj, string config, string pathDotnet = null, Dictionary argsExtra = null, bool noBuild = false, string resultsFileNameWithoutExtension = null, string filter = "", int maxCpuCount = 0) { if (string.IsNullOrWhiteSpace(filter)) { @@ -858,7 +886,7 @@ void RunTestWithLocalDotNet(string csproj, string config, string pathDotnet = nu if (!string.IsNullOrWhiteSpace(filter)) { - Information("Run Tests With Filter {0}", filter); + Information("Run Tests With Filter {0}", filter); } string binlog; @@ -871,7 +899,7 @@ void RunTestWithLocalDotNet(string csproj, string config, string pathDotnet = nu { // Make sure the path doesn't refer to the dotnet executable and make path absolute var localDotnetRoot = MakeAbsolute(Directory(System.IO.Path.GetDirectoryName(pathDotnet))); - Information("new dotnet root: {0}", localDotnetRoot); + Information("new dotnet root: {0}", localDotnetRoot); SetDotNetEnvironmentVariables(localDotnetRoot.FullPath); } @@ -879,7 +907,7 @@ void RunTestWithLocalDotNet(string csproj, string config, string pathDotnet = nu if (string.IsNullOrWhiteSpace(resultsFileNameWithoutExtension)) { binlog = $"{logDirectory}/{name}-{config}.binlog"; - results = $"{name}-{config}.trx"; + results = $"{name}-{config}.trx"; } else { @@ -890,47 +918,50 @@ void RunTestWithLocalDotNet(string csproj, string config, string pathDotnet = nu Information("Run Test binlog: {0}", binlog); var settings = new DotNetTestSettings - { - Configuration = config, - NoBuild = noBuild, - Filter = filter, - Loggers = { + { + Configuration = config, + NoBuild = noBuild, + Filter = filter, + Loggers = { $"trx;LogFileName={results}", $"console;verbosity=normal" - }, - ResultsDirectory = GetTestResultsDirectory(), + }, + ResultsDirectory = GetTestResultsDirectory(), // Verbosity = Cake.Common.Tools.DotNetCore.DotNetCoreVerbosity.Diagnostic, - ArgumentCustomization = args => - { - args.Append($"-bl:{binlog}"); - if(maxCpuCount > 0) - { - args.Append($"-maxcpucount:{maxCpuCount}"); - } + ArgumentCustomization = args => + { + args.Append($"-bl:{binlog}"); + if (maxCpuCount > 0) + { + args.Append($"-maxcpucount:{maxCpuCount}"); + } - if(argsExtra != null) + if (argsExtra != null) + { + foreach (var prop in argsExtra) { - foreach(var prop in argsExtra) - { - args.Append($"/p:{prop.Key}={prop.Value}"); - } - } - - // https://github.com/microsoft/vstest/issues/5112 - args.Append($"/p:VStestUseMSBuildOutput=false"); - - return args; + args.Append($"/p:{prop.Key}={prop.Value}"); + } } - }; - - if(!string.IsNullOrEmpty(pathDotnet)) + + // https://github.com/microsoft/vstest/issues/5112 + args.Append($"/p:VStestUseMSBuildOutput=false"); + + return args; + } + }; + + if (!string.IsNullOrEmpty(pathDotnet)) { settings.ToolPath = pathDotnet; } - try { + try + { DotNetTest(csproj, settings); - } finally { + } + finally + { Information("Test Run complete: {0}", results); } } @@ -974,25 +1005,25 @@ void ProcessTFMSwitches() { List replaceTarget = new List(); - if(HasArgument("android")) + if (HasArgument("android")) replaceTarget.Add("_IncludeAndroid"); - if(HasArgument("windows")) + if (HasArgument("windows")) replaceTarget.Add("_IncludeWindows"); - if(HasArgument("ios")) + if (HasArgument("ios")) replaceTarget.Add("_IncludeIos"); - if(HasArgument("catalyst") || HasArgument("maccatalyst")) + if (HasArgument("catalyst") || HasArgument("maccatalyst")) replaceTarget.Add("_IncludeMacCatalyst"); - if(HasArgument("tizen")) + if (HasArgument("tizen")) replaceTarget.Add("_IncludeTizen"); if (replaceTarget.Count > 0) { CopyFile("Directory.Build.Override.props.in", "Directory.Build.Override.props"); - foreach(var replaceWith in replaceTarget) + foreach (var replaceWith in replaceTarget) { ReplaceTextInFiles("Directory.Build.Override.props", $"<{replaceWith}>", $"<{replaceWith}>true"); } diff --git a/eng/pipelines/common/ui-tests-build-sample.yml b/eng/pipelines/common/ui-tests-build-sample.yml index b7d8712b6818..3e9f4904a2ad 100644 --- a/eng/pipelines/common/ui-tests-build-sample.yml +++ b/eng/pipelines/common/ui-tests-build-sample.yml @@ -10,7 +10,7 @@ parameters: skipProvisioning: true configuration: "Release" testFilter: '' - runtimeVariant: 'Mono' + runtimeVariant: 'Mono' #Mono, CoreCLR, NativeAOT steps: - ${{ if eq(parameters.platform, 'ios')}}: diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index e84b23ebe35d..73174c6fc9cc 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -58,6 +58,22 @@ stages: parameters: runtimeVariant: "Mono" skipProvisioning: ${{ parameters.skipProvisioning }} + + - stage: build_ui_tests_coreclr + displayName: Build UITests Sample App + dependsOn: [] + jobs: + - job: build_ui_tests + displayName: Build Sample App + pool: ${{ parameters.androidPool }} + variables: + REQUIRED_XCODE: $(DEVICETESTS_REQUIRED_XCODE) + APPIUM_HOME: $(System.DefaultWorkingDirectory)/.appium/ + steps: + - template: ui-tests-build-sample.yml + parameters: + runtimeVariant: "CoreCLR" + skipProvisioning: ${{ parameters.skipProvisioning }} - ${{ if or(parameters.BuildEverything, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}: - stage: build_ui_tests_nativeaot From b3c5f18c4b50ab32781aed4c13d82d88e197efb0 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 14:50:00 +0100 Subject: [PATCH 02/15] [iOS] Ignore iOS trimming on sample --- .../tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj b/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj index 797dd7b78342..b26478b63b83 100644 --- a/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj +++ b/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj @@ -23,7 +23,7 @@ <_FastDeploymentDiagnosticLogging>True None - $(NoWarn);CS0618;CS0672;XC0618;XC0022;XC0023 + $(NoWarn);CS0618;CS0672;XC0618;XC0022;XC0023;IL2026 From 172c4a6499a486054753707641acf0e813c7e445 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 14:50:18 +0100 Subject: [PATCH 03/15] [ci] CoreCLR just for android --- eng/cake/dotnet.cake | 3 +++ eng/pipelines/common/ui-tests.yml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/eng/cake/dotnet.cake b/eng/cake/dotnet.cake index 011eae4dbbbf..e33786b842c0 100644 --- a/eng/cake/dotnet.cake +++ b/eng/cake/dotnet.cake @@ -11,6 +11,8 @@ string MSBuildExe = Argument("msbuild", EnvironmentVariable("MSBUILD_EXE", "")); string nugetSource = Argument("nugetsource", ""); string officialBuildId = Argument("officialbuildid", ""); +string DotnetVersion = Argument("targetFrameworkVersion", EnvironmentVariable("TARGET_FRAMEWORK_VERSION") ?? "net10.0"); + string testFilter = Argument("test-filter", EnvironmentVariable("TEST_FILTER")); var rootFolder = Context.Environment.WorkingDirectory; @@ -207,6 +209,7 @@ Task("uitests-apphost") { Information("Building for CoreCLR"); properties.Add("UseMonoRuntime", "false"); + properties.Add("UseCoreCLR", $"{DotnetVersion}-android"); } if (USE_NATIVE_AOT) diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index 73174c6fc9cc..b36ffbb2128b 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -60,7 +60,7 @@ stages: skipProvisioning: ${{ parameters.skipProvisioning }} - stage: build_ui_tests_coreclr - displayName: Build UITests Sample App + displayName: Build UITests Sample App CoreCLR dependsOn: [] jobs: - job: build_ui_tests From 6632789a43a1160fc70c709dad5798bf374b8dfd Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 14:52:33 +0100 Subject: [PATCH 04/15] [ci] Run tests on macos-15 --- eng/pipelines/ui-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/ui-tests.yml b/eng/pipelines/ui-tests.yml index 3276962ebc23..c3f1f59d7ab3 100644 --- a/eng/pipelines/ui-tests.yml +++ b/eng/pipelines/ui-tests.yml @@ -107,7 +107,7 @@ parameters: type: object default: name: Azure Pipelines - vmImage: macOS-14 + vmImage: macOS-15 - name: androidCompatibilityPool type: object From a99894275696af2d97bcc182fdc9cbb680ce6280 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 14:52:52 +0100 Subject: [PATCH 05/15] [ci] Run Android on api 36 --- eng/pipelines/ui-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/ui-tests.yml b/eng/pipelines/ui-tests.yml index c3f1f59d7ab3..d8dbb7b5cd42 100644 --- a/eng/pipelines/ui-tests.yml +++ b/eng/pipelines/ui-tests.yml @@ -149,11 +149,11 @@ stages: iosCompatibilityPool: ${{ parameters.iosCompatibilityPool }} agentPoolAccessToken: $(AgentPoolAccessToken) ${{ if or(parameters.BuildEverything, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}: - androidApiLevels: [ 30 ] + androidApiLevels: [ 36 ] iosVersions: [ 'latest' ] provisionatorChannel: ${{ parameters.provisionatorChannel }} ${{ else }}: - androidApiLevels: [ 30 ] + androidApiLevels: [ 36 ] iosVersions: [ 'latest' ] provisionatorChannel: ${{ parameters.provisionatorChannel }} ${{ if parameters.CompatibilityTests }}: From b35668c3338a7c93a2f98ad4a1e3469e8c3dc8a9 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 15:05:25 +0100 Subject: [PATCH 06/15] [ci] Fix variable TargetFramework --- eng/cake/dotnet.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/cake/dotnet.cake b/eng/cake/dotnet.cake index e33786b842c0..3dfe4e01ef80 100644 --- a/eng/cake/dotnet.cake +++ b/eng/cake/dotnet.cake @@ -209,7 +209,7 @@ Task("uitests-apphost") { Information("Building for CoreCLR"); properties.Add("UseMonoRuntime", "false"); - properties.Add("UseCoreCLR", $"{DotnetVersion}-android"); + properties.Add("TargetFramework", $"{DotnetVersion}-android"); } if (USE_NATIVE_AOT) From 8904cab93bdd04c877371f757f06cf2dd4f22be9 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 15:29:28 +0100 Subject: [PATCH 07/15] [ci] Fix artifacts name --- eng/pipelines/common/ui-tests-build-sample.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/eng/pipelines/common/ui-tests-build-sample.yml b/eng/pipelines/common/ui-tests-build-sample.yml index 3e9f4904a2ad..8b4e5aa39b8a 100644 --- a/eng/pipelines/common/ui-tests-build-sample.yml +++ b/eng/pipelines/common/ui-tests-build-sample.yml @@ -73,6 +73,10 @@ steps: condition: and(ne('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.runtimeVariant }}' , 'NativeAOT'), succeeded()) artifact: ui-tests-samples-nativeaot +- publish: $(System.DefaultWorkingDirectory)/artifacts/bin + condition: and(ne('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.runtimeVariant }}' , 'CoreCLR'), succeeded()) + artifact: ui-tests-samples-coreclr + - publish: $(System.DefaultWorkingDirectory)/artifacts/bin condition: and(eq('${{ parameters.platform }}' , 'windows'), succeeded()) artifact: ui-tests-samples-windows @@ -85,6 +89,10 @@ steps: condition: and(ne('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.runtimeVariant }}' , 'NativeAOT'), failed()) artifact: ui-tests-samples-nativeaot_failed_$(System.JobAttempt) +- publish: $(System.DefaultWorkingDirectory)/artifacts/bin + condition: and(ne('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.runtimeVariant }}' , 'CoreCLR'), failed()) + artifact: ui-tests-samples-coreclr_failed_$(System.JobAttempt) + - publish: $(System.DefaultWorkingDirectory)/artifacts/bin condition: and(eq('${{ parameters.platform }}' , 'windows'), failed()) artifact: ui-tests-samples-windows_failed_$(System.JobAttempt) From 26c02e5887aaa8b481fb3160aeb37584811af1a6 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 15:29:42 +0100 Subject: [PATCH 08/15] [ci] Ignore more trimming warnings --- .../tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj b/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj index b26478b63b83..bee3c5b3fd2c 100644 --- a/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj +++ b/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj @@ -23,7 +23,7 @@ <_FastDeploymentDiagnosticLogging>True None - $(NoWarn);CS0618;CS0672;XC0618;XC0022;XC0023;IL2026 + $(NoWarn);CS0618;CS0672;XC0618;XC0022;XC0023;IL2026;IL2091;IL2067;IL2072;IL2087;IL3050 From 7f7f1b5ea55543ec03d7e0b1f256b907dda4960b Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 16:37:31 +0100 Subject: [PATCH 09/15] change variable name --- eng/cake/dotnet.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/cake/dotnet.cake b/eng/cake/dotnet.cake index 3dfe4e01ef80..0edb218a07fa 100644 --- a/eng/cake/dotnet.cake +++ b/eng/cake/dotnet.cake @@ -11,7 +11,7 @@ string MSBuildExe = Argument("msbuild", EnvironmentVariable("MSBUILD_EXE", "")); string nugetSource = Argument("nugetsource", ""); string officialBuildId = Argument("officialbuildid", ""); -string DotnetVersion = Argument("targetFrameworkVersion", EnvironmentVariable("TARGET_FRAMEWORK_VERSION") ?? "net10.0"); +string DefaultDotnetVersion = Argument("targetFrameworkVersion", EnvironmentVariable("TARGET_FRAMEWORK_VERSION") ?? "net10.0"); string testFilter = Argument("test-filter", EnvironmentVariable("TEST_FILTER")); @@ -209,7 +209,7 @@ Task("uitests-apphost") { Information("Building for CoreCLR"); properties.Add("UseMonoRuntime", "false"); - properties.Add("TargetFramework", $"{DotnetVersion}-android"); + properties.Add("TargetFramework", $"{DefaultDotnetVersion}-android"); } if (USE_NATIVE_AOT) From 7a6cd08528b1541edff96dbda02656e7889642f8 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 16:41:16 +0100 Subject: [PATCH 10/15] [ci] Add coreclr run tests --- eng/pipelines/common/ui-tests-steps.yml | 5 ++++ eng/pipelines/common/ui-tests.yml | 40 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/eng/pipelines/common/ui-tests-steps.yml b/eng/pipelines/common/ui-tests-steps.yml index 893f03d96a46..a085f151dc9d 100644 --- a/eng/pipelines/common/ui-tests-steps.yml +++ b/eng/pipelines/common/ui-tests-steps.yml @@ -24,6 +24,11 @@ steps: inputs: artifact: ui-tests-samples-nativeaot +- task: DownloadPipelineArtifact@2 + condition: and(ne('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.runtimeVariant }}' , 'CoreCLR')) + inputs: + artifact: ui-tests-samples-coreclr + - task: DownloadPipelineArtifact@2 condition: eq('${{ parameters.platform }}' , 'windows') inputs: diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index b36ffbb2128b..e4e1e490b50a 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -145,6 +145,46 @@ stages: agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} testFilter: $(CATEGORYGROUP) skipProvisioning: ${{ parameters.skipProvisioning }} + + - stage: android_ui_tests_coreclr + displayName: Android UITests + dependsOn: build_ui_tests_coreclr + jobs: + - ${{ each project in parameters.projects }}: + - ${{ if ne(project.android, '') }}: + - ${{ each api in parameters.androidApiLevels }}: + - ${{ if not(containsValue(project.androidApiLevelsExclude, api)) }}: + - job: android_ui_tests_${{ project.name }}_${{ api }} + strategy: + matrix: + ${{ each categoryGroup in parameters.categoryGroupsToTest }}: + ${{ categoryGroup }}: + CATEGORYGROUP: ${{ categoryGroup }} + timeoutInMinutes: 240 # how long to run the job before automatically cancelling + workspace: + clean: all + displayName: ${{ coalesce(project.desc, project.name) }} (API ${{ api }}) + pool: ${{ parameters.androidLinuxPool }} + variables: + REQUIRED_XCODE: $(DEVICETESTS_REQUIRED_XCODE) + APPIUM_HOME: $(System.DefaultWorkingDirectory)/.appium/ + steps: + - template: ui-tests-steps.yml + parameters: + platform: android + version: ${{ api }} + path: ${{ project.android }} + app: ${{ project.app }} + ${{ if eq(api, 27) }}: + device: android-emulator-32_${{ api }} + ${{ if not(eq(api, 27)) }}: + device: android-emulator-64_${{ api }} + provisionatorChannel: ${{ parameters.provisionatorChannel }} + agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} + testFilter: $(CATEGORYGROUP) + skipProvisioning: ${{ parameters.skipProvisioning }} + runtimeVariant : "CoreCLR" + - stage: ios_ui_tests_mono displayName: iOS UITests Mono From 13ef6793fc2ebe7010cbb0e93c025e4dde7facf8 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 17:09:59 +0100 Subject: [PATCH 11/15] [ci] Fix artifact condition --- eng/pipelines/common/ui-tests-build-sample.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/common/ui-tests-build-sample.yml b/eng/pipelines/common/ui-tests-build-sample.yml index 8b4e5aa39b8a..a3872de583cb 100644 --- a/eng/pipelines/common/ui-tests-build-sample.yml +++ b/eng/pipelines/common/ui-tests-build-sample.yml @@ -66,7 +66,7 @@ steps: continueOnError: true - publish: $(System.DefaultWorkingDirectory)/artifacts/bin - condition: and(ne('${{ parameters.platform }}' , 'windows'), ne('${{ parameters.runtimeVariant }}' , 'NativeAOT'), succeeded()) + condition: and(ne('${{ parameters.platform }}' , 'windows'), ne('${{ parameters.runtimeVariant }}' , 'NativeAOT'), ne('${{ parameters.runtimeVariant }}' , 'CoreCLR'), succeeded()) artifact: ui-tests-samples - publish: $(System.DefaultWorkingDirectory)/artifacts/bin @@ -82,7 +82,7 @@ steps: artifact: ui-tests-samples-windows - publish: $(System.DefaultWorkingDirectory)/artifacts/bin - condition: and(ne('${{ parameters.platform }}' , 'windows'), ne('${{ parameters.runtimeVariant }}' , 'NativeAOT'), failed()) + condition: and(ne('${{ parameters.platform }}' , 'windows'), ne('${{ parameters.runtimeVariant }}' , 'NativeAOT'), ne('${{ parameters.runtimeVariant }}' , 'CoreCLR'), failed()) artifact: ui-tests-samples_failed_$(System.JobAttempt) - publish: $(System.DefaultWorkingDirectory)/artifacts/bin From 63dc52af6a1cade2184d741ae42b4ccb58c84bfd Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 17:10:09 +0100 Subject: [PATCH 12/15] [ci] Improve naming --- eng/pipelines/common/ui-tests.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index e4e1e490b50a..0d62df0bc488 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -60,7 +60,7 @@ stages: skipProvisioning: ${{ parameters.skipProvisioning }} - stage: build_ui_tests_coreclr - displayName: Build UITests Sample App CoreCLR + displayName: Build UITests CoreCLR Sample App dependsOn: [] jobs: - job: build_ui_tests @@ -77,7 +77,7 @@ stages: - ${{ if or(parameters.BuildEverything, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}: - stage: build_ui_tests_nativeaot - displayName: Build UITests Sample App NativeAOT + displayName: Build UITests NativeAOT Sample App dependsOn: [] jobs: - job: build_ui_tests @@ -185,7 +185,6 @@ stages: skipProvisioning: ${{ parameters.skipProvisioning }} runtimeVariant : "CoreCLR" - - stage: ios_ui_tests_mono displayName: iOS UITests Mono dependsOn: build_ui_tests From c7fb70b6b85ba0f600426f69ba520d68264f1458 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Mon, 28 Jul 2025 11:02:15 +0100 Subject: [PATCH 13/15] Fix Name --- eng/pipelines/common/ui-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index 0d62df0bc488..cc65db785543 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -147,7 +147,7 @@ stages: skipProvisioning: ${{ parameters.skipProvisioning }} - stage: android_ui_tests_coreclr - displayName: Android UITests + displayName: Android UITests CoreClr dependsOn: build_ui_tests_coreclr jobs: - ${{ each project in parameters.projects }}: @@ -183,7 +183,7 @@ stages: agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} testFilter: $(CATEGORYGROUP) skipProvisioning: ${{ parameters.skipProvisioning }} - runtimeVariant : "CoreCLR" + runtimeVariant: "CoreCLR" - stage: ios_ui_tests_mono displayName: iOS UITests Mono From fd905c3466f3e84cec8477dad4425fadde967f5b Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 25 Jul 2025 18:37:25 +0100 Subject: [PATCH 14/15] Move back to api 30 --- eng/pipelines/ui-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/ui-tests.yml b/eng/pipelines/ui-tests.yml index d8dbb7b5cd42..c3f1f59d7ab3 100644 --- a/eng/pipelines/ui-tests.yml +++ b/eng/pipelines/ui-tests.yml @@ -149,11 +149,11 @@ stages: iosCompatibilityPool: ${{ parameters.iosCompatibilityPool }} agentPoolAccessToken: $(AgentPoolAccessToken) ${{ if or(parameters.BuildEverything, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}: - androidApiLevels: [ 36 ] + androidApiLevels: [ 30 ] iosVersions: [ 'latest' ] provisionatorChannel: ${{ parameters.provisionatorChannel }} ${{ else }}: - androidApiLevels: [ 36 ] + androidApiLevels: [ 30 ] iosVersions: [ 'latest' ] provisionatorChannel: ${{ parameters.provisionatorChannel }} ${{ if parameters.CompatibilityTests }}: From 9662b46e8dfeb50f92fb19d1a2bebb3374c45af6 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Tue, 5 Aug 2025 10:24:55 +0100 Subject: [PATCH 15/15] Update ui-tests.yml --- eng/pipelines/ui-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/ui-tests.yml b/eng/pipelines/ui-tests.yml index c3f1f59d7ab3..3276962ebc23 100644 --- a/eng/pipelines/ui-tests.yml +++ b/eng/pipelines/ui-tests.yml @@ -107,7 +107,7 @@ parameters: type: object default: name: Azure Pipelines - vmImage: macOS-15 + vmImage: macOS-14 - name: androidCompatibilityPool type: object