diff --git a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs b/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs index 7b7f4f28ef9e..630923439c57 100644 --- a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs +++ b/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Reflection; +using Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver; #nullable disable @@ -19,7 +20,6 @@ namespace Microsoft.DotNet.MSBuildSdkResolver // 2. Nevertheless, in the IDE, project re-evaluation can create new instances for each evaluation. // // As such, all state (instance or static) must be guarded against concurrent access/updates. - // Caches of minimum versions, compatible SDKs are static to benefit multiple IDE evaluations. // VSSettings are also effectively static (singleton instance that can be swapped by tests). public sealed class DotNetMSBuildSdkResolver : SdkResolver @@ -32,6 +32,8 @@ public sealed class DotNetMSBuildSdkResolver : SdkResolver private readonly Func _getEnvironmentVariable; private readonly NETCoreSdkResolver _netCoreSdkResolver; + private static CachingWorkloadResolver _staticWorkloadResolver = new CachingWorkloadResolver(); + public DotNetMSBuildSdkResolver() : this(Environment.GetEnvironmentVariable, VSSettings.Ambient) { @@ -44,40 +46,49 @@ public DotNetMSBuildSdkResolver(Func getEnvironmentVariable, VSS _netCoreSdkResolver = new NETCoreSdkResolver(getEnvironmentVariable, vsSettings); } - private sealed class CachedResult + private sealed class CachedState { + public string DotnetRoot; public string MSBuildSdksDir; public string NETCoreSdkVersion; + public IDictionary PropertiesToAdd; + public CachingWorkloadResolver WorkloadResolver; } public override SdkResult Resolve(SdkReference sdkReference, SdkResolverContext context, SdkResultFactory factory) { + string dotnetRoot = null; string msbuildSdksDir = null; string netcoreSdkVersion = null; IDictionary propertiesToAdd = null; IDictionary itemsToAdd = null; List warnings = null; + CachingWorkloadResolver workloadResolver = null; - if (context.State is CachedResult priorResult) + if (context.State is CachedState priorResult) { + dotnetRoot = priorResult.DotnetRoot; msbuildSdksDir = priorResult.MSBuildSdksDir; netcoreSdkVersion = priorResult.NETCoreSdkVersion; + propertiesToAdd = priorResult.PropertiesToAdd; + workloadResolver = priorResult.WorkloadResolver; } - if (msbuildSdksDir == null) + if (context.IsRunningInVisualStudio) { - // These are overrides that are used to force the resolved SDK tasks and targets to come from a given - // base directory and report a given version to msbuild (which may be null if unknown. One key use case - // for this is to test SDK tasks and targets without deploying them inside the .NET Core SDK. - msbuildSdksDir = _getEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_SDKS_DIR"); - netcoreSdkVersion = _getEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_SDKS_VER"); + workloadResolver = _staticWorkloadResolver; + } + + if (workloadResolver == null) + { + workloadResolver = new CachingWorkloadResolver(); } if (msbuildSdksDir == null) { - string dotnetExeDir = _netCoreSdkResolver.GetDotnetExeDirectory(); + dotnetRoot = _netCoreSdkResolver.GetDotnetExeDirectory(); string globalJsonStartDir = Path.GetDirectoryName(context.SolutionFilePath ?? context.ProjectFilePath); - var resolverResult = _netCoreSdkResolver.ResolveNETCoreSdkDirectory(globalJsonStartDir, context.MSBuildVersion, context.IsRunningInVisualStudio, dotnetExeDir); + var resolverResult = _netCoreSdkResolver.ResolveNETCoreSdkDirectory(globalJsonStartDir, context.MSBuildVersion, context.IsRunningInVisualStudio, dotnetRoot); if (resolverResult.ResolvedSdkDirectory == null) { @@ -89,6 +100,20 @@ public override SdkResult Resolve(SdkReference sdkReference, SdkResolverContext msbuildSdksDir = Path.Combine(resolverResult.ResolvedSdkDirectory, "Sdks"); netcoreSdkVersion = new DirectoryInfo(resolverResult.ResolvedSdkDirectory).Name; + // These are overrides that are used to force the resolved SDK tasks and targets to come from a given + // base directory and report a given version to msbuild (which may be null if unknown. One key use case + // for this is to test SDK tasks and targets without deploying them inside the .NET Core SDK. + var msbuildSdksDirFromEnv = _getEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_SDKS_DIR"); + var netcoreSdkVersionFromEnv = _getEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_SDKS_VER"); + if (!string.IsNullOrEmpty(msbuildSdksDirFromEnv)) + { + msbuildSdksDir = msbuildSdksDirFromEnv; + } + if (!string.IsNullOrEmpty(netcoreSdkVersionFromEnv)) + { + netcoreSdkVersion = netcoreSdkVersionFromEnv; + } + if (IsNetCoreSDKSmallerThanTheMinimumVersion(netcoreSdkVersion, sdkReference.MinimumVersion)) { return Failure( @@ -135,12 +160,23 @@ public override SdkResult Resolve(SdkReference sdkReference, SdkResolverContext } } - context.State = new CachedResult + context.State = new CachedState { + DotnetRoot = dotnetRoot, MSBuildSdksDir = msbuildSdksDir, - NETCoreSdkVersion = netcoreSdkVersion + NETCoreSdkVersion = netcoreSdkVersion, + PropertiesToAdd = propertiesToAdd, + WorkloadResolver = workloadResolver }; + // First check if requested SDK resolves to a workload SDK pack + var workloadResult = workloadResolver.Resolve(sdkReference.Name, dotnetRoot, netcoreSdkVersion); + + if (workloadResult is not CachingWorkloadResolver.NullResolutionResult) + { + return workloadResult.ToSdkResult(sdkReference, factory); + } + string msbuildSdkDir = Path.Combine(msbuildSdksDir, sdkReference.Name, "Sdk"); if (!Directory.Exists(msbuildSdkDir)) { diff --git a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj b/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj index 9daf6545fffa..5feaf2601132 100644 --- a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj +++ b/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj @@ -58,15 +58,10 @@ - - - - - - + @@ -78,6 +73,7 @@ + diff --git a/src/Resolvers/Microsoft.DotNet.SdkResolver/NETCoreSdkResolver.cs b/src/Resolvers/Microsoft.DotNet.SdkResolver/NETCoreSdkResolver.cs index b78457f30de9..229e6b186138 100644 --- a/src/Resolvers/Microsoft.DotNet.SdkResolver/NETCoreSdkResolver.cs +++ b/src/Resolvers/Microsoft.DotNet.SdkResolver/NETCoreSdkResolver.cs @@ -10,11 +10,15 @@ namespace Microsoft.DotNet.DotNetSdkResolver { + + // Thread safety note: + // This class is used by the MSBuild SDK resolvers, which can be called on multiple threads. public class NETCoreSdkResolver { private readonly Func _getEnvironmentVariable; private readonly VSSettings _vsSettings; + // Caches of minimum versions, compatible SDKs are static to benefit multiple IDE evaluations. private static readonly ConcurrentDictionary s_minimumMSBuildVersions = new ConcurrentDictionary(); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs new file mode 100644 index 000000000000..351b003d4a0e --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs @@ -0,0 +1,226 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Build.Framework; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Microsoft.NET.Sdk.WorkloadManifestReader; +using System.Collections.Immutable; + +#if NET +using Microsoft.DotNet.Cli; +#else +using Microsoft.DotNet.DotNetSdkResolver; +#endif + +#nullable disable + +namespace Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver +{ + + // This class contains workload SDK resolution logic which will be used by both .NET SDK MSBuild and Full Framework / Visual Studio MSBuild. + // + // Keeping this performant in Visual Studio is tricky, as VS performs a lot of evaluations, but they are not linked by an MSBuild "Submission ID", + // so the state caching support provided by MSBuild for SDK Resolvers doesn't really help. Additionally, multiple instances of the SDK resolver + // may be created, and the same instance may be called on multiple threads. So state needs to be cached staticly and be thread-safe. + // + // To keep the state static, the MSBuildSdkResolver keeps a static reference to the CachingWorkloadResolver that is used if the build is inside + // Visual Studio. To keep it thread-safe, the body of the Resolve method is all protected by a lock statement. This avoids having to make + // the classes consumed by the CachingWorkloadResolver (the manifest provider and workload resolver) thread-safe. + // + // A resolver should not over-cache and return out-of-date results. For workloads, the resolution could change due to: + // - Installation, update, or uninstallation of a workload + // - Resolved SDK changes (either due to an SDK installation or uninstallation, or a global.json change) + // For SDK or workload installation actions, we expect to be running under a new process since Visual Studio will have been restarted. + // For global.json changes, the Resolve method takes parameters for the dotnet root and the SDK version. If those values have changed + // from the previous call, the cached state will be thrown out and recreated. + class CachingWorkloadResolver + { + private sealed record CachedState + { + public string DotnetRootPath { get; init; } + public string SdkVersion { get; init; } + public IWorkloadManifestProvider ManifestProvider { get; init; } + public IWorkloadResolver WorkloadResolver { get; init; } + public ImmutableDictionary CachedResults { get; init; } + + public CachedState() + { + CachedResults = ImmutableDictionary.Create(StringComparer.OrdinalIgnoreCase); + } + } + + public object _lockObject { get; } = new object(); + private CachedState _cachedState; + private readonly bool _enabled; + + + public CachingWorkloadResolver() + { + // Support opt-out for workload resolution + _enabled = true; + var envVar = Environment.GetEnvironmentVariable("MSBuildEnableWorkloadResolver"); + if (envVar != null) + { + if (envVar.Equals("false", StringComparison.OrdinalIgnoreCase)) + { + _enabled = false; + } + } + + if (_enabled) + { + string sentinelPath = Path.Combine(Path.GetDirectoryName(typeof(CachingWorkloadResolver).Assembly.Location), "DisableWorkloadResolver.sentinel"); + if (File.Exists(sentinelPath)) + { + _enabled = false; + } + } + } + + public record ResolutionResult() + { + public SdkResult ToSdkResult(SdkReference sdkReference, SdkResultFactory factory) + { + switch (this) + { + case SinglePathResolutionResult r: + return factory.IndicateSuccess(r.Path, sdkReference.Version); + case MultiplePathResolutionResult r: + return factory.IndicateSuccess(r.Paths, sdkReference.Version); + case EmptyResolutionResult r: + return factory.IndicateSuccess(Enumerable.Empty(), sdkReference.Version, r.propertiesToAdd, r.itemsToAdd); + case NullResolutionResult: + return null; + } + + throw new InvalidOperationException("Unknown resolutionResult type: " + this.GetType()); + } + } + + public sealed record SinglePathResolutionResult( + string Path + ) : ResolutionResult; + + public sealed record MultiplePathResolutionResult( + IEnumerable Paths + ) : ResolutionResult; + + public sealed record EmptyResolutionResult( + IDictionary propertiesToAdd, + IDictionary itemsToAdd + ) : ResolutionResult; + + public sealed record NullResolutionResult() : ResolutionResult; + + private static ResolutionResult Resolve(string sdkReferenceName, IWorkloadManifestProvider manifestProvider, IWorkloadResolver workloadResolver) + { + if (sdkReferenceName.Equals("Microsoft.NET.SDK.WorkloadAutoImportPropsLocator", StringComparison.OrdinalIgnoreCase)) + { + List autoImportSdkPaths = new List(); + foreach (var sdkPackInfo in workloadResolver.GetInstalledWorkloadPacksOfKind(WorkloadPackKind.Sdk)) + { + string sdkPackSdkFolder = Path.Combine(sdkPackInfo.Path, "Sdk"); + string autoImportPath = Path.Combine(sdkPackSdkFolder, "AutoImport.props"); + if (File.Exists(autoImportPath)) + { + autoImportSdkPaths.Add(sdkPackSdkFolder); + } + } + // Call Distinct() here because with aliased packs, there may be duplicates of the same path + return new MultiplePathResolutionResult(autoImportSdkPaths.Distinct()); + } + else if (sdkReferenceName.Equals("Microsoft.NET.SDK.WorkloadManifestTargetsLocator", StringComparison.OrdinalIgnoreCase)) + { + List workloadManifestPaths = new List(); + foreach (var manifestDirectory in manifestProvider.GetManifestDirectories()) + { + var workloadManifestTargetPath = Path.Combine(manifestDirectory, "WorkloadManifest.targets"); + if (File.Exists(workloadManifestTargetPath)) + { + workloadManifestPaths.Add(manifestDirectory); + } + } + return new MultiplePathResolutionResult(workloadManifestPaths); + } + else + { + var packInfo = workloadResolver.TryGetPackInfo(sdkReferenceName); + if (packInfo != null) + { + if (Directory.Exists(packInfo.Path)) + { + return new SinglePathResolutionResult(Path.Combine(packInfo.Path, "Sdk")); + } + else + { + var itemsToAdd = new Dictionary(); + itemsToAdd.Add("MissingWorkloadPack", + new SdkResultItem(sdkReferenceName, + metadata: new Dictionary() + { + { "Version", packInfo.Version } + })); + + Dictionary propertiesToAdd = new Dictionary(); + return new EmptyResolutionResult(propertiesToAdd, itemsToAdd); + } + } + } + return new NullResolutionResult(); + } + + public ResolutionResult Resolve(string sdkReferenceName, string dotnetRootPath, string sdkVersion) + { + if (!_enabled) + { + return new NullResolutionResult(); + } + + ResolutionResult resolutionResult; + + lock (_lockObject) + { + if (_cachedState == null || + _cachedState.DotnetRootPath != dotnetRootPath || + _cachedState.SdkVersion != sdkVersion) + { + var workloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(dotnetRootPath, sdkVersion); + var workloadResolver = WorkloadResolver.Create(workloadManifestProvider, dotnetRootPath, sdkVersion); + + _cachedState = new CachedState() + { + DotnetRootPath = dotnetRootPath, + SdkVersion = sdkVersion, + ManifestProvider = workloadManifestProvider, + WorkloadResolver = workloadResolver + }; + } + + if (!_cachedState.CachedResults.TryGetValue(sdkReferenceName, out resolutionResult)) + { + resolutionResult = Resolve(sdkReferenceName, _cachedState.ManifestProvider, _cachedState.WorkloadResolver); + + _cachedState = _cachedState with + { + CachedResults = _cachedState.CachedResults.Add(sdkReferenceName, resolutionResult) + }; + } + } + + return resolutionResult; + } + } +} + + +// Add attribute to support init-only properties on .NET Framework +#if !NET +namespace System.Runtime.CompilerServices +{ + public class IsExternalInit { } +} +#endif diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver.csproj b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver.csproj index 893dc349d368..644fdf2e2eac 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver.csproj +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver.csproj @@ -1,13 +1,10 @@  - $(SdkTargetFramework);net472 - $(SdkTargetFramework) + $(SdkTargetFramework) true - - @@ -30,6 +27,7 @@ + diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/WorkloadSdkResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/WorkloadSdkResolver.cs index f373a832868a..804466f85b22 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/WorkloadSdkResolver.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/WorkloadSdkResolver.cs @@ -1,10 +1,15 @@ -using Microsoft.Build.Framework; +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +using Microsoft.Build.Framework; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using Microsoft.NET.Sdk.WorkloadManifestReader; +using System.Collections.Immutable; #if NET using Microsoft.DotNet.Cli; @@ -16,130 +21,55 @@ namespace Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver { + + // This SdkResolver is used by the .NET SDK version of MSBuild. Workload resolution logic which + // is shared with Full Framework / Visual Studio MSBuild is in CachingWorkloadResolver. public class WorkloadSdkResolver : SdkResolver { public override string Name => "Microsoft.DotNet.MSBuildWorkloadSdkResolver"; public override int Priority => 4000; - private bool _enabled; - - private IWorkloadManifestProvider _workloadManifestProvider; - private IWorkloadResolver _workloadResolver; - - -#if NETFRAMEWORK - private readonly NETCoreSdkResolver _sdkResolver; -#endif + private class CachedState + { + public string DotnetRootPath { get; init; } + public string SdkVersion { get; init; } + public CachingWorkloadResolver WorkloadResolver { get; init; } + } - public WorkloadSdkResolver() + public override SdkResult Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory) { - // Put workload resolution behind a feature flag. - _enabled = false; - var envVar = Environment.GetEnvironmentVariable("MSBuildEnableWorkloadResolver"); - if (envVar != null) - { - if (envVar.Equals("true", StringComparison.OrdinalIgnoreCase)) - { - _enabled = true; - } - } + CachedState cachedState = null; - if (!_enabled) + if (resolverContext.State is CachedState resolverContextState) { - string sentinelPath = Path.Combine(Path.GetDirectoryName(typeof(WorkloadSdkResolver).Assembly.Location), "EnableWorkloadResolver.sentinel"); - if (File.Exists(sentinelPath)) - { - _enabled = true; - } + cachedState = resolverContextState; } -#if NETFRAMEWORK - if (_enabled) + + if (cachedState == null) { - _sdkResolver = new NETCoreSdkResolver(); - } -#endif - } - - private void InitializeWorkloadResolver(SdkResolverContext context) - { - var dotnetRootPath = GetDotNetRoot(context); + var dotnetRootPath = GetDotNetRoot(resolverContext); - var sdkDirectory = GetSdkDirectory(context); - // The SDK version is the name of the SDK directory (ie dotnet\sdk\5.0.100) - var sdkVersion = Path.GetFileName(sdkDirectory); + var sdkDirectory = GetSdkDirectory(resolverContext); + // The SDK version is the name of the SDK directory (ie dotnet\sdk\5.0.100) + var sdkVersion = Path.GetFileName(sdkDirectory); - _workloadManifestProvider ??= new SdkDirectoryWorkloadManifestProvider(dotnetRootPath, sdkVersion); - _workloadResolver ??= WorkloadResolver.Create(_workloadManifestProvider, dotnetRootPath, sdkVersion); - } + cachedState = new CachedState() + { + DotnetRootPath = dotnetRootPath, + SdkVersion = sdkVersion, + WorkloadResolver = new CachingWorkloadResolver() + }; - public override SdkResult Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory) - { - if (!_enabled) - { - return null; + resolverContext.State = cachedState; } - InitializeWorkloadResolver(resolverContext); + var result = cachedState.WorkloadResolver.Resolve(sdkReference.Name, cachedState.DotnetRootPath, cachedState.SdkVersion); - if (sdkReference.Name.Equals("Microsoft.NET.SDK.WorkloadAutoImportPropsLocator", StringComparison.OrdinalIgnoreCase)) - { - List autoImportSdkPaths = new List(); - foreach (var sdkPackInfo in _workloadResolver.GetInstalledWorkloadPacksOfKind(WorkloadPackKind.Sdk)) - { - string sdkPackSdkFolder = Path.Combine(sdkPackInfo.Path, "Sdk"); - string autoImportPath = Path.Combine(sdkPackSdkFolder, "AutoImport.props"); - if (File.Exists(autoImportPath)) - { - autoImportSdkPaths.Add(sdkPackSdkFolder); - } - } - // Call Distinct() here because with aliased packs, there may be duplicates of the same path - return factory.IndicateSuccess(autoImportSdkPaths.Distinct(), sdkReference.Version); - } - else if (sdkReference.Name.Equals("Microsoft.NET.SDK.WorkloadManifestTargetsLocator", StringComparison.OrdinalIgnoreCase)) - { - List workloadManifestPaths = new List(); - foreach (var manifestDirectory in _workloadManifestProvider.GetManifestDirectories()) - { - var workloadManifestTargetPath = Path.Combine(manifestDirectory, "WorkloadManifest.targets"); - if (File.Exists(workloadManifestTargetPath)) - { - workloadManifestPaths.Add(manifestDirectory); - } - } - return factory.IndicateSuccess(workloadManifestPaths, sdkReference.Version); - } - else - { - var packInfo = _workloadResolver.TryGetPackInfo(sdkReference.Name); - if (packInfo != null) - { - if (Directory.Exists(packInfo.Path)) - { - return factory.IndicateSuccess(Path.Combine(packInfo.Path, "Sdk"), sdkReference.Version); - } - else - { - var itemsToAdd = new Dictionary(); - itemsToAdd.Add("MissingWorkloadPack", - new SdkResultItem(sdkReference.Name, - metadata: new Dictionary() - { - { "Version", packInfo.Version } - })); - - Dictionary propertiesToAdd = new Dictionary(); - return factory.IndicateSuccess(Enumerable.Empty(), - sdkReference.Version, - propertiesToAdd: propertiesToAdd, - itemsToAdd: itemsToAdd); - } - } - } - return null; + + return result.ToSdkResult(sdkReference, factory); } private string GetSdkDirectory(SdkResolverContext context) @@ -166,3 +96,4 @@ private string GetDotNetRoot(SdkResolverContext context) } } } + diff --git a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAWebApp.cs b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAWebApp.cs index 4d710fe839b2..e6010ea1597e 100644 --- a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAWebApp.cs +++ b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAWebApp.cs @@ -167,7 +167,7 @@ public void It_should_publish_framework_dependent_for_2x(string platformLibrary) [InlineData(true, false)] [InlineData(false, true)] [InlineData(true, true)] - public void It_publishes_with_a_publish_profile(bool? selfContained, bool? useAppHost) + public void PublishWebAppWithPublishProfile(bool? selfContained, bool? useAppHost) { var tfm = "netcoreapp2.2"; var rid = EnvironmentInfo.GetCompatibleRid(tfm); diff --git a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishToClickOnce.cs b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishToClickOnce.cs index f07a3ff59291..d636c843ff16 100644 --- a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishToClickOnce.cs +++ b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishToClickOnce.cs @@ -26,7 +26,7 @@ public GivenThatWeWantToPublishAClickOnceProject(ITestOutputHelper log) : base(l [FullMSBuildOnlyTheory] [InlineData(false)] [InlineData(true)] - public void It_publishes_with_a_publish_profile(bool? publishSingleFile) + public void PublishClickOnceWithPublishProfile(bool? publishSingleFile) { var tfm = "netcoreapp3.1"; var rid = EnvironmentInfo.GetCompatibleRid(tfm);