From 93f14cc1aca499b5819add3f0ec10423d48d868b Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 22 Jul 2026 01:20:17 -0500 Subject: [PATCH 1/5] [tests] Use dotnet-public for CI package resolution (#12198) CFSClean reports network-isolation warnings when tests and CI tooling resolve packages directly from public NuGet endpoints. Route those package downloads through the existing dnceng `dotnet-public` Azure Artifacts feed and rely on the repository `NuGet.config` for generated test projects and the API-docs tool installation. Direct `.nupkg` test downloads now use the feed's V3 package base address, while obsolete `ExtraNuGetConfigSources` public overrides are removed. No fallback to nuget.org is retained. `Xamarin.Google.Android.InstallReferrer` 1.1.2.6 is not currently mirrored to `dotnet-public`; `InstallAndRunTests.GradleFBProj` will require that package to be mirrored. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../automation/azure-pipelines-apidocs.yaml | 2 +- .../Xamarin.Android.Build.Tests/BuildTest.cs | 4 ---- .../Tasks/FilterAssembliesTests.cs | 22 ++++++++++++++++--- .../Tests/InstallAndRunTests.cs | 3 --- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/build-tools/automation/azure-pipelines-apidocs.yaml b/build-tools/automation/azure-pipelines-apidocs.yaml index 642965e8147..9340419e86a 100644 --- a/build-tools/automation/azure-pipelines-apidocs.yaml +++ b/build-tools/automation/azure-pipelines-apidocs.yaml @@ -131,7 +131,7 @@ extends: inputs: forceReinstallCredentialProvider: true - - script: dotnet tool update -v:n boots --version 1.1.0.36 --add-source "https://api.nuget.org/v3/index.json" --global + - script: dotnet tool update -v:n boots --version 1.1.0.36 --global displayName: Install boots - script: boots https://download.mono-project.com/archive/6.12.0/macos-10-universal/MonoFramework-MDK-6.12.0.188.macos10.xamarin.universal.pkg diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index a895295d526..eb7ce433760 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -33,10 +33,6 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo ProjectName = "Test Me", RootNamespace = "Test.Me", EnableDefaultItems = true, - ExtraNuGetConfigSources = { - // Microsoft.AspNetCore.Components.WebView is not in dotnet-public - "https://api.nuget.org/v3/index.json", - }, PackageReferences = { new Package { Id = "Xamarin.AndroidX.AppCompat", Version = "1.3.1.1" }, // Using * here, so we explicitly get newer packages diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/FilterAssembliesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/FilterAssembliesTests.cs index 7eeba328dab..e60bfe8f56b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/FilterAssembliesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/FilterAssembliesTests.cs @@ -14,6 +14,8 @@ namespace Xamarin.Android.Build.Tests [TestFixture] public class FilterAssembliesTests : BaseTest { + const string DotNetPublicPackageBaseAddress = "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/flat2"; + string tempDirectory; [SetUp] @@ -32,6 +34,20 @@ public void TearDown () Task DownloadFromNuGet (string url, string filename = "") => Task.Factory.StartNew (() => new DownloadedCache ().GetAsFile (url, filename)); + static string GetPackageUrl (string packageId, string version) + { + var lowercaseId = packageId.ToLowerInvariant (); + var lowercaseVersion = version.ToLowerInvariant (); + return $"{DotNetPublicPackageBaseAddress}/{lowercaseId}/{lowercaseVersion}/{lowercaseId}.{lowercaseVersion}.nupkg"; + } + + [Test] + public void PackageUrlIsLowercase () + { + var actual = GetPackageUrl ("Package.ID", "1.0.0-RC1"); + Assert.AreEqual ($"{DotNetPublicPackageBaseAddress}/package.id/1.0.0-rc1/package.id.1.0.0-rc1.nupkg", actual); + } + async Task GetAssembliesFromNuGet (string url, string filename, string path) { var assemblies = new List (); @@ -65,7 +81,7 @@ string [] Run (params string [] assemblies) public async Task CircleImageView () { var assemblies = await GetAssembliesFromNuGet ( - "https://www.nuget.org/api/v2/package/Refractored.Controls.CircleImageView/1.0.1", + GetPackageUrl ("Refractored.Controls.CircleImageView", "1.0.1"), "Refractored.Controls.CircleImageView.1.0.1.nupkg", "lib/MonoAndroid10/"); var actual = Run (assemblies); @@ -77,7 +93,7 @@ public async Task CircleImageView () public async Task XamarinForms () { var assemblies = await GetAssembliesFromNuGet ( - "https://www.nuget.org/api/v2/package/Xamarin.Forms/3.6.0.220655", + GetPackageUrl ("Xamarin.Forms", "3.6.0.220655"), "Xamarin.Forms.3.6.0.220655.nupkg", "lib/MonoAndroid90/"); var actual = Run (assemblies); @@ -93,7 +109,7 @@ public async Task XamarinForms () public async Task GuavaListenableFuture () { var assemblies = await GetAssembliesFromNuGet ( - "https://www.nuget.org/api/v2/package/Xamarin.Google.Guava.ListenableFuture/1.0.0", + GetPackageUrl ("Xamarin.Google.Guava.ListenableFuture", "1.0.0"), "Xamarin.Google.Guava.ListenableFuture.1.0.0.nupkg", "lib/MonoAndroid50/"); var actual = Run (assemblies); diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 054d3ab75dc..83af3ab9280 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -1668,9 +1668,6 @@ public static void logEvent(String eventName) {{ var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, - ExtraNuGetConfigSources = { - "https://api.nuget.org/v3/index.json", - }, OtherBuildItems = { new AndroidItem.TransformFile ("Transforms\\Metadata.xml") { TextContent = () => $@"Facebook", From 4304c9063fa0ce1c9f25f50947b9dce51e92fdd4 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 11 Aug 2026 14:09:54 -0500 Subject: [PATCH 2/5] [ci] Prevent isolated NuGet access (#12336) Internal [build 14925232](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=14925232) reported CFSClean violations during **Create MAUI template**. The pipeline needs to suppress three independent .NET network paths: 1. `DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE=true` prevents background workload advertising-manifest updates. 2. `DOTNET_SDK_VULNERABILITY_CHECK_DISABLE=true` prevents the .NET CLI's separate background SDK release/vulnerability/EOL metadata refresh. The SDK invokes this refresh from restoring commands such as `dotnet build` and `dotnet restore`. 3. `NuGetAudit=false` disables NuGet restore's package-advisory lookup. This is a distinct MSBuild property and does not replace the SDK-level variable. The immediate MAUI violation came from `dotnet new maui`, which runs a restore post-action by default. That restore had no project-specific `NuGet.config`, so it contacted public NuGet and workload advertising-manifest hosts. Passing `--no-restore` creates the template without running that post-action. This does not remove the intended MAUI restore/build. The following Debug and Release build steps remain unchanged and explicitly pass `--configfile $(Build.SourcesDirectory)/maui/NuGet.config`, keeping package acquisition on the configured sources. Disabling these metadata checks also does not disable package hash/signature validation; it prevents external metadata lookups in network-isolated jobs. - Retain `DOTNET_SDK_VULNERABILITY_CHECK_DISABLE=true` and add `NuGetAudit=false` alongside it in shared pipeline variables and the internal override. - Add `--no-restore` to MAUI template creation in the main, public, and internal pipeline definitions. - Parsed all changed YAML files successfully. - Ran `git diff --check`. - Verified every MAUI template-creation variant uses `--no-restore`. - Verified all three isolation controls remain present where expected. - Verified `dotnet new --no-restore` creates a project without producing a restore assets file. - Confirmed the separate SDK behavior in [`RestoringCommand`](https://github.com/dotnet/sdk/blob/8795d0128cf1efbb900edd5cfbd8e9789be10653/src/Cli/dotnet/Commands/Restore/RestoringCommand.cs) and [`SdkReleaseMetadataCache`](https://github.com/dotnet/sdk/blob/8795d0128cf1efbb900edd5cfbd8e9789be10653/src/Cli/dotnet/SdkVulnerability/SdkReleaseMetadataCache.cs). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- build-tools/automation/azure-pipelines.yaml | 2 +- build-tools/automation/yaml-templates/variables.yaml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index 61be4053073..571a8443945 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -188,7 +188,7 @@ extends: - template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml@self parameters: command: new - arguments: maui -o $(Build.StagingDirectory)/MauiTestProj + arguments: maui -o $(Build.StagingDirectory)/MauiTestProj --no-restore xaSourcePath: $(Build.SourcesDirectory)/android displayName: Create MAUI template continueOnError: false diff --git a/build-tools/automation/yaml-templates/variables.yaml b/build-tools/automation/yaml-templates/variables.yaml index 9fa934e62db..23efd8699c9 100644 --- a/build-tools/automation/yaml-templates/variables.yaml +++ b/build-tools/automation/yaml-templates/variables.yaml @@ -80,3 +80,11 @@ variables: value: true - name: DOTNET_GENERATE_ASPNET_CERTIFICATE value: false +# Fix network isolation requirements +# See https://devdiv.visualstudio.com/DevDiv/_git/Xamarin.yaml-templates/pullrequest/750402 +- name: DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE + value: 'true' +- name: DOTNET_SDK_VULNERABILITY_CHECK_DISABLE + value: 'true' +- name: NuGetAudit + value: 'false' From 9a35a16275b0d3ff3f0d2d64d5b9da04593fbb01 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 11 Aug 2026 15:40:03 -0500 Subject: [PATCH 3/5] [tests] Keep `dotnet new` restores on approved feeds (#12338) - declare the standard `skipRestore` symbol in every Android project template - map `skipRestore` to the user-facing `--no-restore` option through each template's `dotnetcli.host.json` - prevent `XASdkTests.DotNetNew` from restoring generated projects implicitly - copy the repository `NuGet.config` into generated projects before builds restore - route `AndroidMavenLibrary` items with blank repository metadata through `dotnet-public-maven` in test scope `--no-restore` is presented as a standard `dotnet new` option, but project templates must opt into accepting it by declaring a `skipRestore` boolean symbol and mapping that symbol to `--no-restore` in `dotnetcli.host.json`. This follows the symbol/mapping convention used by the .NET SDK and .NET MAUI templates. The Android templates intentionally do not add a restore post-action. They therefore preserve their existing default behavior and avoid restoring before test call sites configure approved package versions and feeds. The new option lets `XASdkTests` explicitly document and enforce that expectation before copying the repository `NuGet.config` into generated projects. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../.template.config/dotnetcli.host.json | 9 +++++ .../.template.config/template.json | 6 +++ .../.template.config/dotnetcli.host.json | 9 +++++ .../.template.config/template.json | 6 +++ .../.template.config/dotnetcli.host.json | 9 +++++ .../android/.template.config/template.json | 6 +++ .../.template.config/dotnetcli.host.json | 9 +++++ .../androidlib/.template.config/template.json | 6 +++ .../.template.config/dotnetcli.host.json | 9 +++++ .../.template.config/template.json | 40 +++++++++++++++++++ .../Xamarin.Android.Build.Tests/XASdkTests.cs | 32 +++++++++++++-- .../dotnet-public-maven.targets | 10 +++++ .../Xamarin.ProjectTools/Common/DotNetCLI.cs | 5 ++- 13 files changed, 151 insertions(+), 5 deletions(-) create mode 100644 src/Microsoft.Android.Templates/android-bindinglib/.template.config/dotnetcli.host.json create mode 100644 src/Microsoft.Android.Templates/android-wear/.template.config/dotnetcli.host.json create mode 100644 src/Microsoft.Android.Templates/android/.template.config/dotnetcli.host.json create mode 100644 src/Microsoft.Android.Templates/androidlib/.template.config/dotnetcli.host.json create mode 100644 src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json create mode 100644 src/Microsoft.Android.Templates/androidtest/.template.config/template.json create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/dotnet-public-maven.targets diff --git a/src/Microsoft.Android.Templates/android-bindinglib/.template.config/dotnetcli.host.json b/src/Microsoft.Android.Templates/android-bindinglib/.template.config/dotnetcli.host.json new file mode 100644 index 00000000000..f0a41abf603 --- /dev/null +++ b/src/Microsoft.Android.Templates/android-bindinglib/.template.config/dotnetcli.host.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/dotnetcli.host", + "symbolInfo": { + "skipRestore": { + "longName": "no-restore", + "shortName": "" + } + } +} diff --git a/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json b/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json index c6e8c6ca8ee..13dcc6bc077 100644 --- a/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json +++ b/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json @@ -22,6 +22,12 @@ "datatype": "string", "replaces": "SUPPORTED_OS_PLATFORM_VERSION", "defaultValue": "24" + }, + "skipRestore": { + "type": "parameter", + "datatype": "bool", + "description": "If specified, skips the automatic restore of the project on create.", + "defaultValue": "false" } }, "defaultName": "AndroidBinding1" diff --git a/src/Microsoft.Android.Templates/android-wear/.template.config/dotnetcli.host.json b/src/Microsoft.Android.Templates/android-wear/.template.config/dotnetcli.host.json new file mode 100644 index 00000000000..f0a41abf603 --- /dev/null +++ b/src/Microsoft.Android.Templates/android-wear/.template.config/dotnetcli.host.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/dotnetcli.host", + "symbolInfo": { + "skipRestore": { + "longName": "no-restore", + "shortName": "" + } + } +} diff --git a/src/Microsoft.Android.Templates/android-wear/.template.config/template.json b/src/Microsoft.Android.Templates/android-wear/.template.config/template.json index 912b864de55..f098607fcd3 100644 --- a/src/Microsoft.Android.Templates/android-wear/.template.config/template.json +++ b/src/Microsoft.Android.Templates/android-wear/.template.config/template.json @@ -35,6 +35,12 @@ "datatype": "string", "replaces": "SUPPORTED_OS_PLATFORM_VERSION", "defaultValue": "24" + }, + "skipRestore": { + "type": "parameter", + "datatype": "bool", + "description": "If specified, skips the automatic restore of the project on create.", + "defaultValue": "false" } }, "defaultName": "AndroidApp1" diff --git a/src/Microsoft.Android.Templates/android/.template.config/dotnetcli.host.json b/src/Microsoft.Android.Templates/android/.template.config/dotnetcli.host.json new file mode 100644 index 00000000000..f0a41abf603 --- /dev/null +++ b/src/Microsoft.Android.Templates/android/.template.config/dotnetcli.host.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/dotnetcli.host", + "symbolInfo": { + "skipRestore": { + "longName": "no-restore", + "shortName": "" + } + } +} diff --git a/src/Microsoft.Android.Templates/android/.template.config/template.json b/src/Microsoft.Android.Templates/android/.template.config/template.json index 8ec941ba0a1..a7d3c05c87b 100644 --- a/src/Microsoft.Android.Templates/android/.template.config/template.json +++ b/src/Microsoft.Android.Templates/android/.template.config/template.json @@ -35,6 +35,12 @@ "datatype": "string", "replaces": "SUPPORTED_OS_PLATFORM_VERSION", "defaultValue": "24" + }, + "skipRestore": { + "type": "parameter", + "datatype": "bool", + "description": "If specified, skips the automatic restore of the project on create.", + "defaultValue": "false" } }, "defaultName": "AndroidApp1" diff --git a/src/Microsoft.Android.Templates/androidlib/.template.config/dotnetcli.host.json b/src/Microsoft.Android.Templates/androidlib/.template.config/dotnetcli.host.json new file mode 100644 index 00000000000..f0a41abf603 --- /dev/null +++ b/src/Microsoft.Android.Templates/androidlib/.template.config/dotnetcli.host.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/dotnetcli.host", + "symbolInfo": { + "skipRestore": { + "longName": "no-restore", + "shortName": "" + } + } +} diff --git a/src/Microsoft.Android.Templates/androidlib/.template.config/template.json b/src/Microsoft.Android.Templates/androidlib/.template.config/template.json index 517bd32482e..506b4c4a10f 100644 --- a/src/Microsoft.Android.Templates/androidlib/.template.config/template.json +++ b/src/Microsoft.Android.Templates/androidlib/.template.config/template.json @@ -22,6 +22,12 @@ "datatype": "string", "replaces": "SUPPORTED_OS_PLATFORM_VERSION", "defaultValue": "24" + }, + "skipRestore": { + "type": "parameter", + "datatype": "bool", + "description": "If specified, skips the automatic restore of the project on create.", + "defaultValue": "false" } }, "defaultName": "AndroidLib1" diff --git a/src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json b/src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json new file mode 100644 index 00000000000..f0a41abf603 --- /dev/null +++ b/src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/dotnetcli.host", + "symbolInfo": { + "skipRestore": { + "longName": "no-restore", + "shortName": "" + } + } +} diff --git a/src/Microsoft.Android.Templates/androidtest/.template.config/template.json b/src/Microsoft.Android.Templates/androidtest/.template.config/template.json new file mode 100644 index 00000000000..425261385aa --- /dev/null +++ b/src/Microsoft.Android.Templates/androidtest/.template.config/template.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json.schemastore.org/template", + "author": "Microsoft", + "classifications": [ "Android", "Mobile", "Test" ], + "identity": "Microsoft.Android.AndroidTest", + "name": "Android Test Project", + "description": "A project for creating a .NET for Android test project using MSTest", + "shortName": "androidtest", + "tags": { + "language": "C#", + "type": "project" + }, + "sourceName": "AndroidTest1", + "preferNameDirectory": true, + "primaryOutputs": [ + { "path": "AndroidTest1.csproj" } + ], + "symbols": { + "packageName": { + "type": "parameter", + "description": "Overrides the package name in the AndroidManifest.xml", + "datatype": "string", + "replaces": "com.companyname.AndroidTest1" + }, + "supportedOSVersion": { + "type": "parameter", + "description": "Overrides $(SupportedOSPlatformVersion) in the project", + "datatype": "string", + "replaces": "SUPPORTED_OS_PLATFORM_VERSION", + "defaultValue": "24" + }, + "skipRestore": { + "type": "parameter", + "datatype": "bool", + "description": "If specified, skips the automatic restore of the project on create.", + "defaultValue": "false" + } + }, + "defaultName": "AndroidTest1" +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs index 5a2e4963605..d64e029ebe9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Linq; using System.Reflection; using System.Text; using NUnit.Framework; @@ -32,18 +31,43 @@ public void DotNetNew ([Values ("android", "androidlib", "android-bindinglib", " TestOutputDirectories [TestContext.CurrentContext.Test.ID] = templatePath; var dotnet = new DotNetCLI (Path.Combine (templatePath, $"{templateName}.csproj")); - Assert.IsTrue (dotnet.New (template), $"`dotnet new {template}` should succeed"); + Assert.IsTrue (dotnet.New (template, noRestore: true), $"`dotnet new {template} --no-restore` should succeed"); + + var repoNuGetConfig = Path.Combine (XABuildPaths.TopDirectory, "NuGet.config"); + var projectNuGetConfig = Path.Combine (dotnet.ProjectDirectory, "NuGet.config"); + File.Copy (repoNuGetConfig, projectNuGetConfig); + FileAssert.AreEqual (repoNuGetConfig, projectNuGetConfig); + File.WriteAllBytes (Path.Combine (dotnet.ProjectDirectory, "foo.jar"), ResourceData.JavaSourceJarTestJar); Assert.IsTrue (dotnet.New ("android-activity"), "`dotnet new android-activity` should succeed"); Assert.IsTrue (dotnet.New ("android-layout", Path.Combine (dotnet.ProjectDirectory, "Resources", "layout")), "`dotnet new android-layout` should succeed"); // Debug build - Assert.IsTrue (dotnet.Build (parameters: new [] { "Configuration=Debug", "TrimmerSingleWarn=false" }), "`dotnet build` should succeed"); + Assert.IsTrue (dotnet.Build (parameters: GetBuildParameters ("Debug")), "`dotnet build` should succeed"); dotnet.AssertHasNoWarnings (); // Release build - Assert.IsTrue (dotnet.Build (parameters: new [] { "Configuration=Release", "TrimmerSingleWarn=false" }), "`dotnet build` should succeed"); + Assert.IsTrue (dotnet.Build (parameters: GetBuildParameters ("Release")), "`dotnet build` should succeed"); dotnet.AssertHasNoWarnings (); + + string [] GetBuildParameters (string configuration) + { + var parameters = new List { + $"Configuration={configuration}", + "TrimmerSingleWarn=false", + }; + if (template == "androidwear") { + var mavenTargets = Path.Combine ( + XABuildPaths.TopDirectory, + "src", + "Xamarin.Android.Build.Tasks", + "Tests", + "Xamarin.Android.Build.Tests", + "dotnet-public-maven.targets"); + parameters.Add ($"CustomAfterMicrosoftCommonTargets=\"{mavenTargets}\""); + } + return parameters.ToArray (); + } } static readonly object[] DotNetPackTargetFrameworks = new object[] { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/dotnet-public-maven.targets b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/dotnet-public-maven.targets new file mode 100644 index 00000000000..b29eaa03a16 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/dotnet-public-maven.targets @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs index af412c959c5..5edef3715b2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs @@ -104,13 +104,16 @@ protected bool Execute (params string [] args) return succeeded; } - public bool New (string template, string output = null) + public bool New (string template, string output = null, bool noRestore = false) { var arguments = new List { "new", template, "--output", $"\"{output ?? ProjectDirectory}\"", }; + if (noRestore) { + arguments.Add ("--no-restore"); + } return Execute (arguments.ToArray ()); } From af5b7e7f2f9abeb7c4cf2290761e3e822a40067c Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 12 Aug 2026 09:57:29 -0500 Subject: [PATCH 4/5] [ci] Use repo NuGet config for template smoke build (#12335) Depends on #12336. The Windows template smoke project is generated under `$(Build.StagingDirectory)`, outside the repository `NuGet.config` hierarchy. Its implicit build restore therefore falls back to the agent's machine NuGet configuration and may access unapproved package feeds. - Pass `RestoreConfigFile=$(System.DefaultWorkingDirectory)\NuGet.config` to the template build. - Quote the template creation and build staging paths using Windows path syntax. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../yaml-templates/build-windows.yaml | 6 ++- .../.template.config/dotnetcli.host.json | 9 ----- .../.template.config/template.json | 40 ------------------- 3 files changed, 4 insertions(+), 51 deletions(-) delete mode 100644 src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json delete mode 100644 src/Microsoft.Android.Templates/androidtest/.template.config/template.json diff --git a/build-tools/automation/yaml-templates/build-windows.yaml b/build-tools/automation/yaml-templates/build-windows.yaml index 713f484e92c..eec9fa2a776 100644 --- a/build-tools/automation/yaml-templates/build-windows.yaml +++ b/build-tools/automation/yaml-templates/build-windows.yaml @@ -104,13 +104,15 @@ stages: displayName: Test dotnet-local.cmd - create template inputs: filename: dotnet-local.cmd - arguments: new android -o $(Build.StagingDirectory)/LocalWorkloadTest + arguments: new android -o "$(Build.StagingDirectory)\LocalWorkloadTest" - task: BatchScript@1 displayName: Test dotnet-local.cmd - build template inputs: filename: dotnet-local.cmd - arguments: build -v:n $(Build.StagingDirectory)/LocalWorkloadTest + arguments: >- + build -v:n "$(Build.StagingDirectory)\LocalWorkloadTest" + -p:RestoreConfigFile="$(System.DefaultWorkingDirectory)\NuGet.config" # Pack .nupkgs and extract workload packs to dotnet preview test directory - template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml diff --git a/src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json b/src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json deleted file mode 100644 index f0a41abf603..00000000000 --- a/src/Microsoft.Android.Templates/androidtest/.template.config/dotnetcli.host.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/dotnetcli.host", - "symbolInfo": { - "skipRestore": { - "longName": "no-restore", - "shortName": "" - } - } -} diff --git a/src/Microsoft.Android.Templates/androidtest/.template.config/template.json b/src/Microsoft.Android.Templates/androidtest/.template.config/template.json deleted file mode 100644 index 425261385aa..00000000000 --- a/src/Microsoft.Android.Templates/androidtest/.template.config/template.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/template", - "author": "Microsoft", - "classifications": [ "Android", "Mobile", "Test" ], - "identity": "Microsoft.Android.AndroidTest", - "name": "Android Test Project", - "description": "A project for creating a .NET for Android test project using MSTest", - "shortName": "androidtest", - "tags": { - "language": "C#", - "type": "project" - }, - "sourceName": "AndroidTest1", - "preferNameDirectory": true, - "primaryOutputs": [ - { "path": "AndroidTest1.csproj" } - ], - "symbols": { - "packageName": { - "type": "parameter", - "description": "Overrides the package name in the AndroidManifest.xml", - "datatype": "string", - "replaces": "com.companyname.AndroidTest1" - }, - "supportedOSVersion": { - "type": "parameter", - "description": "Overrides $(SupportedOSPlatformVersion) in the project", - "datatype": "string", - "replaces": "SUPPORTED_OS_PLATFORM_VERSION", - "defaultValue": "24" - }, - "skipRestore": { - "type": "parameter", - "datatype": "bool", - "description": "If specified, skips the automatic restore of the project on create.", - "defaultValue": "false" - } - }, - "defaultName": "AndroidTest1" -} From dd6228e6522936f1e7fd2d0f83b137f5d33a3804 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 12 Aug 2026 23:08:18 -0500 Subject: [PATCH 5/5] [tests] Fix CodeBehind NuGet config placement (#12367) `CodeBehindTests` passed a file path to `CopyNuGetConfig`, which expects a directory and appends `NuGet.config`. This placed the repository configuration in a nested path, so generated projects could miss it and contact external package feeds. Pass the temporary project root instead. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs index da088199ffd..19ff0be59f1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs @@ -691,7 +691,7 @@ string PrepareProject (string testName) CopyRecursively (CommonSampleLibraryRootDirectory, Path.Combine (tempRoot, CommonSampleLibraryName), ignore); CopyFile (Path.Combine (XABuildPaths.TopDirectory, "Directory.Build.props"), Path.Combine (tempRoot, "Directory.Build.props" )); var project = new XamarinAndroidApplicationProject (); - project.CopyNuGetConfig (Path.Combine (tempRoot, "NuGet.config")); + project.CopyNuGetConfig (tempRoot); return temporaryProjectPath; }