From 0005863761c2e516a9a8da8140bd6bc73cad28d1 Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Mon, 20 Nov 2023 12:22:38 -0800 Subject: [PATCH] Revert "Revert "Add option to enable floating versions in CPM (#5440)" (#5513)" This reverts commit d52a50a2a48a49a4faabc7160b4d805db4eb0961. --- .../Projects/LegacyPackageReferenceProject.cs | 1 + .../VSNominationUtilities.cs | 5 + .../VsSolutionRestoreService.cs | 1 + .../MSBuildStaticGraphRestore.cs | 19 +-- .../NuGet.Build.Tasks/NuGet.targets | 1 + .../Utility/MSBuildAPIUtility.cs | 12 +- .../PublicAPI/net472/PublicAPI.Unshipped.txt | 1 + .../netcoreapp5.0/PublicAPI.Unshipped.txt | 1 + .../netstandard2.0/PublicAPI.Unshipped.txt | 1 + .../RestoreCommand/RestoreCommand.cs | 13 +- .../Utility/MSBuildRestoreUtility.cs | 25 ++- .../Projects/ProjectBuildProperties.cs | 1 + .../PublicAPI.Unshipped.txt | 1 + .../JsonPackageSpecReader.cs | 6 + .../NuGet.ProjectModel/PackageSpecWriter.cs | 1 + .../ProjectRestoreMetadata.cs | 8 + .../PublicAPI.Unshipped.txt | 2 + .../VsSolutionRestoreServiceTests.cs | 55 ++++++- .../MSBuildStaticGraphRestoreTests.cs | 6 +- .../MSBuildRestoreUtilityTests.cs | 148 +++++++++++++++++- .../RestoreCommandTests.cs | 55 ++++--- .../JsonPackageSpecReaderTests.cs | 42 +++++ .../PackageSpecTests.cs | 106 +++++++++++-- .../ProjectRestoreMetadataTests.cs | 107 +++++++++++++ 24 files changed, 543 insertions(+), 75 deletions(-) diff --git a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/LegacyPackageReferenceProject.cs b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/LegacyPackageReferenceProject.cs index 56785249633..c9c9cdc6eac 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/LegacyPackageReferenceProject.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/LegacyPackageReferenceProject.cs @@ -459,6 +459,7 @@ private async Task GetPackageSpecAsync(ISettings settings) MSBuildStringUtility.IsTrue(GetPropertySafe(_vsProjectAdapter.BuildProperties, ProjectBuildProperties.RestoreLockedMode))), CentralPackageVersionsEnabled = isCpvmEnabled, CentralPackageVersionOverrideDisabled = GetPropertySafe(_vsProjectAdapter.BuildProperties, ProjectBuildProperties.CentralPackageVersionOverrideEnabled).EqualsFalse(), + CentralPackageFloatingVersionsEnabled = MSBuildStringUtility.IsTrue(GetPropertySafe(_vsProjectAdapter.BuildProperties, ProjectBuildProperties.CentralPackageFloatingVersionsEnabled)), CentralPackageTransitivePinningEnabled = MSBuildStringUtility.IsTrue(GetPropertySafe(_vsProjectAdapter.BuildProperties, ProjectBuildProperties.CentralPackageTransitivePinningEnabled)), RestoreAuditProperties = auditProperties, } diff --git a/src/NuGet.Clients/NuGet.SolutionRestoreManager/VSNominationUtilities.cs b/src/NuGet.Clients/NuGet.SolutionRestoreManager/VSNominationUtilities.cs index 12e1696b70e..a85e3e13107 100644 --- a/src/NuGet.Clients/NuGet.SolutionRestoreManager/VSNominationUtilities.cs +++ b/src/NuGet.Clients/NuGet.SolutionRestoreManager/VSNominationUtilities.cs @@ -297,6 +297,11 @@ internal static bool IsCentralPackageVersionOverrideDisabled(IEnumerable tfms) return GetSingleNonEvaluatedPropertyOrNull(tfms, ProjectBuildProperties.CentralPackageVersionOverrideEnabled, (value) => value.EqualsFalse()); } + internal static bool IsCentralPackageFloatingVersionsEnabled(IEnumerable tfms) + { + return GetSingleNonEvaluatedPropertyOrNull(tfms, ProjectBuildProperties.CentralPackageFloatingVersionsEnabled, MSBuildStringUtility.IsTrue); + } + internal static bool IsCentralPackageTransitivePinningEnabled(IEnumerable tfms) { return GetSingleNonEvaluatedPropertyOrNull(tfms, ProjectBuildProperties.CentralPackageTransitivePinningEnabled, MSBuildStringUtility.IsTrue); diff --git a/src/NuGet.Clients/NuGet.SolutionRestoreManager/VsSolutionRestoreService.cs b/src/NuGet.Clients/NuGet.SolutionRestoreManager/VsSolutionRestoreService.cs index e7a4b2ef986..9e88b925ea8 100644 --- a/src/NuGet.Clients/NuGet.SolutionRestoreManager/VsSolutionRestoreService.cs +++ b/src/NuGet.Clients/NuGet.SolutionRestoreManager/VsSolutionRestoreService.cs @@ -348,6 +348,7 @@ internal static PackageSpec ToPackageSpec(ProjectNames projectNames, IEnumerable CacheFilePath = NoOpRestoreUtilities.GetProjectCacheFilePath(cacheRoot: outputPath), RestoreLockProperties = VSNominationUtilities.GetRestoreLockProperties(TargetFrameworks), CentralPackageVersionsEnabled = cpvmEnabled, + CentralPackageFloatingVersionsEnabled = VSNominationUtilities.IsCentralPackageFloatingVersionsEnabled(TargetFrameworks), CentralPackageVersionOverrideDisabled = VSNominationUtilities.IsCentralPackageVersionOverrideDisabled(TargetFrameworks), CentralPackageTransitivePinningEnabled = VSNominationUtilities.IsCentralPackageTransitivePinningEnabled(TargetFrameworks), RestoreAuditProperties = VSNominationUtilities.GetRestoreAuditProperties(TargetFrameworks), diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs b/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs index d7d4864b86d..86d7bb4c63a 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs @@ -808,7 +808,7 @@ private PackageSpec GetPackageSpec(IMSBuildProject project, IReadOnlyDictionary< ProjectStyle? projectStyleOrNull = BuildTasksUtility.GetProjectRestoreStyleFromProjectProperty(project.GetProperty("RestoreProjectStyle")); - (bool isCentralPackageManagementEnabled, bool isCentralPackageVersionOverrideDisabled, bool isCentralPackageTransitivePinningEnabled) = GetCentralPackageManagementSettings(project, projectStyleOrNull); + (bool isCentralPackageManagementEnabled, bool isCentralPackageVersionOverrideDisabled, bool isCentralPackageTransitivePinningEnabled, bool isCentralPackageFloatingVersionsEnabled) = MSBuildRestoreUtility.GetCentralPackageManagementSettings(project, projectStyleOrNull); RestoreAuditProperties auditProperties = MSBuildRestoreUtility.GetRestoreAuditProperties(project); @@ -854,6 +854,7 @@ private PackageSpec GetPackageSpec(IMSBuildProject project, IReadOnlyDictionary< SkipContentFileWrite = IsLegacyProject(project), ValidateRuntimeAssets = project.IsPropertyTrue("ValidateRuntimeIdentifierCompatibility"), CentralPackageVersionsEnabled = isCentralPackageManagementEnabled && projectStyle == ProjectStyle.PackageReference, + CentralPackageFloatingVersionsEnabled = isCentralPackageFloatingVersionsEnabled, CentralPackageVersionOverrideDisabled = isCentralPackageVersionOverrideDisabled, CentralPackageTransitivePinningEnabled = isCentralPackageTransitivePinningEnabled, RestoreAuditProperties = auditProperties @@ -1027,22 +1028,6 @@ private ICollection LoadProjects(IEnumerable - /// Determines the current settings for central package management for the specified project. - /// - /// The to get the central package management settings for. - /// The of the specified project. Specify when the project does not define a restore style. - /// A containing values indicating whether or not central package management is enabled and if the ability to override a package version is disabled. - internal static (bool IsEnabled, bool IsVersionOverrideDisabled, bool IsCentralPackageTransitivePinningEnabled) GetCentralPackageManagementSettings(IMSBuildProject project, ProjectStyle? projectStyle) - { - if (!projectStyle.HasValue || (projectStyle.Value == ProjectStyle.PackageReference)) - { - return (project.IsPropertyTrue("_CentralPackageVersionsEnabled"), project.IsPropertyFalse("CentralPackageVersionOverrideEnabled"), project.IsPropertyTrue("CentralPackageTransitivePinningEnabled")); - } - - return (false, false, false); - } - /// /// Returns the list of distinct items with the name. /// Two items are equal if they have the same . diff --git a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets index 80fb43ff32d..d676d1bdabc 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets +++ b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets @@ -862,6 +862,7 @@ Copyright (c) .NET Foundation. All rights reserved. $(NuGetLockFilePath) $(RestoreLockedMode) <_CentralPackageVersionsEnabled>$(_CentralPackageVersionsEnabled) + $(CentralPackageFloatingVersionsEnabled) $(CentralPackageVersionOverrideEnabled) $(CentralPackageTransitivePinningEnabled) $(NuGetAudit) diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/MSBuildAPIUtility.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/MSBuildAPIUtility.cs index 2a10257e255..167d6311cc1 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/MSBuildAPIUtility.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/MSBuildAPIUtility.cs @@ -164,11 +164,15 @@ public bool AreCentralVersionRequirementsSatisfied(PackageReferenceArgs packageR packageReferenceArgs.Logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Error_CentralPackageVersions_MissingPackageVersion, string.Join(";", packageReferencedDependenciesWithoutCentralVersionDefined.Select(d => d.Name)))); return false; } - var floatingVersionDependencies = packageSpec.TargetFrameworks.SelectMany(tfm => tfm.CentralPackageVersions.Values).Where(cpv => cpv.VersionRange.IsFloating); - if (floatingVersionDependencies.Any()) + + if (!packageSpec.RestoreMetadata.CentralPackageFloatingVersionsEnabled) { - packageReferenceArgs.Logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Error_CentralPackageVersions_FloatingVersionsAreNotAllowed)); - return false; + var floatingVersionDependencies = packageSpec.TargetFrameworks.SelectMany(tfm => tfm.CentralPackageVersions.Values).Where(cpv => cpv.VersionRange.IsFloating); + if (floatingVersionDependencies.Any()) + { + packageReferenceArgs.Logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Error_CentralPackageVersions_FloatingVersionsAreNotAllowed)); + return false; + } } // PackageVersion should not be defined outside the project file. diff --git a/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt index ca5893e1cfb..82fe4a703ca 100644 --- a/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ #nullable enable +~static NuGet.Commands.MSBuildRestoreUtility.GetCentralPackageManagementSettings(NuGet.Commands.IMSBuildItem projectSpecItem, NuGet.ProjectModel.ProjectStyle? projectStyle) -> (bool IsEnabled, bool IsVersionOverrideDisabled, bool IsCentralPackageTransitivePinningEnabled, bool isCentralPackageFloatingVersionsEnabled) ~static NuGet.Commands.MSBuildRestoreUtility.GetMessageForUnsupportedProject(string path) -> NuGet.Common.RestoreLogMessage diff --git a/src/NuGet.Core/NuGet.Commands/PublicAPI/netcoreapp5.0/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Commands/PublicAPI/netcoreapp5.0/PublicAPI.Unshipped.txt index ca5893e1cfb..82fe4a703ca 100644 --- a/src/NuGet.Core/NuGet.Commands/PublicAPI/netcoreapp5.0/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Commands/PublicAPI/netcoreapp5.0/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ #nullable enable +~static NuGet.Commands.MSBuildRestoreUtility.GetCentralPackageManagementSettings(NuGet.Commands.IMSBuildItem projectSpecItem, NuGet.ProjectModel.ProjectStyle? projectStyle) -> (bool IsEnabled, bool IsVersionOverrideDisabled, bool IsCentralPackageTransitivePinningEnabled, bool isCentralPackageFloatingVersionsEnabled) ~static NuGet.Commands.MSBuildRestoreUtility.GetMessageForUnsupportedProject(string path) -> NuGet.Common.RestoreLogMessage diff --git a/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index ca5893e1cfb..82fe4a703ca 100644 --- a/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ #nullable enable +~static NuGet.Commands.MSBuildRestoreUtility.GetCentralPackageManagementSettings(NuGet.Commands.IMSBuildItem projectSpecItem, NuGet.ProjectModel.ProjectStyle? projectStyle) -> (bool IsEnabled, bool IsVersionOverrideDisabled, bool IsCentralPackageTransitivePinningEnabled, bool isCentralPackageFloatingVersionsEnabled) ~static NuGet.Commands.MSBuildRestoreUtility.GetMessageForUnsupportedProject(string path) -> NuGet.Common.RestoreLogMessage diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs index e37679d9563..0f8088157af 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs @@ -598,12 +598,17 @@ private async Task AreCentralVersionRequirementsSatisfiedAsync(RestoreRequ await _logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1010, string.Format(CultureInfo.CurrentCulture, Strings.Error_CentralPackageVersions_MissingPackageVersion, string.Join(";", packageReferencedDependenciesWithoutCentralVersionDefined.Select(d => d.Name))))); return false; } - var floatingVersionDependencies = _request.Project.TargetFrameworks.SelectMany(tfm => tfm.CentralPackageVersions.Values).Where(cpv => cpv.VersionRange.IsFloating); - if (floatingVersionDependencies.Any()) + + if (!restoreRequest.Project.RestoreMetadata.CentralPackageFloatingVersionsEnabled) { - await _logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1011, Strings.Error_CentralPackageVersions_FloatingVersionsAreNotAllowed)); - return false; + var floatingVersionDependencies = _request.Project.TargetFrameworks.SelectMany(tfm => tfm.CentralPackageVersions.Values).Where(cpv => cpv.VersionRange.IsFloating); + if (floatingVersionDependencies.Any()) + { + await _logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1011, Strings.Error_CentralPackageVersions_FloatingVersionsAreNotAllowed)); + return false; + } } + return true; } diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs index 30a6f1778c3..94b6e4a20be 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs @@ -161,7 +161,7 @@ public static PackageSpec GetPackageSpec(IEnumerable items) { ProjectStyle restoreType = GetProjectStyle(specItem); - (bool isCentralPackageManagementEnabled, bool isCentralPackageVersionOverrideDisabled, bool isCentralPackageTransitivePinningEnabled) = GetCentralPackageManagementSettings(specItem, restoreType); + (bool isCentralPackageManagementEnabled, bool isCentralPackageVersionOverrideDisabled, bool isCentralPackageTransitivePinningEnabled, bool isCentralPackageFloatingVersionsEnabled) = GetCentralPackageManagementSettings(specItem, restoreType); // Get base spec if (restoreType == ProjectStyle.ProjectJson) @@ -296,6 +296,7 @@ public static PackageSpec GetPackageSpec(IEnumerable items) result.RestoreMetadata.CentralPackageVersionsEnabled = isCentralPackageManagementEnabled; result.RestoreMetadata.CentralPackageVersionOverrideDisabled = isCentralPackageVersionOverrideDisabled; + result.RestoreMetadata.CentralPackageFloatingVersionsEnabled = isCentralPackageFloatingVersionsEnabled; result.RestoreMetadata.CentralPackageTransitivePinningEnabled = isCentralPackageTransitivePinningEnabled; } @@ -966,7 +967,7 @@ private static string FixSourcePath(string s, string prefixWithoutSlashes, strin return s; } - private static bool IsPropertyFalse(IMSBuildItem item, string propertyName, bool defaultValue = false) + internal static bool IsPropertyFalse(IMSBuildItem item, string propertyName, bool defaultValue = false) { string value = item.GetProperty(propertyName); @@ -978,7 +979,7 @@ private static bool IsPropertyFalse(IMSBuildItem item, string propertyName, bool return string.Equals(value, bool.FalseString, StringComparison.OrdinalIgnoreCase); } - private static bool IsPropertyTrue(IMSBuildItem item, string propertyName, bool defaultValue = false) + internal static bool IsPropertyTrue(IMSBuildItem item, string propertyName, bool defaultValue = false) { string value = item.GetProperty(propertyName); @@ -1064,11 +1065,23 @@ private static ProjectStyle GetProjectStyle(IMSBuildItem projectSpecItem) return restoreType; } - internal static (bool IsEnabled, bool IsVersionOverrideDisabled, bool IsCentralPackageTransitivePinningEnabled) GetCentralPackageManagementSettings(IMSBuildItem projectSpecItem, ProjectStyle projectStyle) + /// + /// Determines the current settings for central package management for the specified project. + /// + /// The to get the central package management settings from. + /// The of the specified project. Specify when the project does not define a restore style. + /// A containing values indicating whether or not central package management is enabled, if the ability to override a package version + public static (bool IsEnabled, bool IsVersionOverrideDisabled, bool IsCentralPackageTransitivePinningEnabled, bool isCentralPackageFloatingVersionsEnabled) GetCentralPackageManagementSettings(IMSBuildItem projectSpecItem, ProjectStyle? projectStyle) { - return (IsPropertyTrue(projectSpecItem, "_CentralPackageVersionsEnabled") && projectStyle == ProjectStyle.PackageReference, + if (!projectStyle.HasValue || (projectStyle.Value == ProjectStyle.PackageReference)) + { + return (IsPropertyTrue(projectSpecItem, "_CentralPackageVersionsEnabled") && projectStyle == ProjectStyle.PackageReference, IsPropertyFalse(projectSpecItem, "CentralPackageVersionOverrideEnabled"), - IsPropertyTrue(projectSpecItem, "CentralPackageTransitivePinningEnabled")); + IsPropertyTrue(projectSpecItem, "CentralPackageTransitivePinningEnabled"), + IsPropertyTrue(projectSpecItem, "CentralPackageFloatingVersionsEnabled")); + } + + return (false, false, false, false); } private static void AddCentralPackageVersions(PackageSpec spec, IEnumerable items) diff --git a/src/NuGet.Core/NuGet.PackageManagement/Projects/ProjectBuildProperties.cs b/src/NuGet.Core/NuGet.PackageManagement/Projects/ProjectBuildProperties.cs index de1ed51755c..f34ca265699 100644 --- a/src/NuGet.Core/NuGet.PackageManagement/Projects/ProjectBuildProperties.cs +++ b/src/NuGet.Core/NuGet.PackageManagement/Projects/ProjectBuildProperties.cs @@ -59,5 +59,6 @@ public static class ProjectBuildProperties public const string NuGetAudit = nameof(NuGetAudit); public const string NuGetAuditLevel = nameof(NuGetAuditLevel); public const string NuGetAuditMode = nameof(NuGetAuditMode); + public const string CentralPackageFloatingVersionsEnabled = nameof(CentralPackageFloatingVersionsEnabled); } } diff --git a/src/NuGet.Core/NuGet.PackageManagement/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.PackageManagement/PublicAPI.Unshipped.txt index 7dc5c58110b..d54721e6855 100644 --- a/src/NuGet.Core/NuGet.PackageManagement/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.PackageManagement/PublicAPI.Unshipped.txt @@ -1 +1,2 @@ #nullable enable +~const NuGet.ProjectManagement.ProjectBuildProperties.CentralPackageFloatingVersionsEnabled = "CentralPackageFloatingVersionsEnabled" -> string diff --git a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs index 0a97ed258c0..a9333dc5274 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs @@ -902,6 +902,7 @@ private static void ReadMappings(JsonTextReader jsonReader, string mappingKey, I private static void ReadMSBuildMetadata(JsonTextReader jsonReader, PackageSpec packageSpec) { var centralPackageVersionsManagementEnabled = false; + var centralPackageFloatingVersionsEnabled = false; var centralPackageVersionOverrideDisabled = false; var CentralPackageTransitivePinningEnabled = false; List configFilePaths = null; @@ -935,6 +936,10 @@ private static void ReadMSBuildMetadata(JsonTextReader jsonReader, PackageSpec p centralPackageVersionsManagementEnabled = ReadNextTokenAsBoolOrFalse(jsonReader, packageSpec.FilePath); break; + case "centralPackageFloatingVersionsEnabled": + centralPackageFloatingVersionsEnabled = ReadNextTokenAsBoolOrFalse(jsonReader, packageSpec.FilePath); + break; + case "centralPackageVersionOverrideDisabled": centralPackageVersionOverrideDisabled = ReadNextTokenAsBoolOrFalse(jsonReader, packageSpec.FilePath); break; @@ -1131,6 +1136,7 @@ private static void ReadMSBuildMetadata(JsonTextReader jsonReader, PackageSpec p } msbuildMetadata.CentralPackageVersionsEnabled = centralPackageVersionsManagementEnabled; + msbuildMetadata.CentralPackageFloatingVersionsEnabled = centralPackageFloatingVersionsEnabled; msbuildMetadata.CentralPackageVersionOverrideDisabled = centralPackageVersionOverrideDisabled; msbuildMetadata.CentralPackageTransitivePinningEnabled = CentralPackageTransitivePinningEnabled; msbuildMetadata.RestoreAuditProperties = auditProperties; diff --git a/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs b/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs index 59cb9bcb186..f6ea0149cbd 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs @@ -176,6 +176,7 @@ private static void WriteMetadataBooleans(IObjectWriter writer, ProjectRestoreMe SetValueIfTrue(writer, "validateRuntimeAssets", msbuildMetadata.ValidateRuntimeAssets); SetValueIfTrue(writer, "skipContentFileWrite", msbuildMetadata.SkipContentFileWrite); SetValueIfTrue(writer, "centralPackageVersionsManagementEnabled", msbuildMetadata.CentralPackageVersionsEnabled); + SetValueIfTrue(writer, "centralPackageFloatingVersionsEnabled", msbuildMetadata.CentralPackageFloatingVersionsEnabled); SetValueIfTrue(writer, "centralPackageVersionOverrideDisabled", msbuildMetadata.CentralPackageVersionOverrideDisabled); SetValueIfTrue(writer, "CentralPackageTransitivePinningEnabled", msbuildMetadata.CentralPackageTransitivePinningEnabled); } diff --git a/src/NuGet.Core/NuGet.ProjectModel/ProjectRestoreMetadata.cs b/src/NuGet.Core/NuGet.ProjectModel/ProjectRestoreMetadata.cs index f450ea44af3..13e7973810f 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/ProjectRestoreMetadata.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/ProjectRestoreMetadata.cs @@ -123,6 +123,11 @@ public class ProjectRestoreMetadata : IEquatable /// public bool CentralPackageVersionOverrideDisabled { get; set; } + /// + /// Gets or sets a value indicating whether or not floating versions are allowed when using central package management (CPM). + /// + public bool CentralPackageFloatingVersionsEnabled { get; set; } + public bool CentralPackageTransitivePinningEnabled { get; set; } public RestoreAuditProperties RestoreAuditProperties { get; set; } @@ -153,6 +158,7 @@ public override int GetHashCode() hashCode.AddObject(ProjectWideWarningProperties); hashCode.AddObject(RestoreLockProperties); hashCode.AddObject(CentralPackageVersionsEnabled); + hashCode.AddObject(CentralPackageFloatingVersionsEnabled); hashCode.AddObject(CentralPackageVersionOverrideDisabled); hashCode.AddObject(CentralPackageTransitivePinningEnabled); hashCode.AddObject(RestoreAuditProperties); @@ -198,6 +204,7 @@ public bool Equals(ProjectRestoreMetadata other) EqualityUtility.EqualsWithNullCheck(ProjectWideWarningProperties, other.ProjectWideWarningProperties) && EqualityUtility.EqualsWithNullCheck(RestoreLockProperties, other.RestoreLockProperties) && EqualityUtility.EqualsWithNullCheck(CentralPackageVersionsEnabled, other.CentralPackageVersionsEnabled) && + EqualityUtility.EqualsWithNullCheck(CentralPackageFloatingVersionsEnabled, other.CentralPackageFloatingVersionsEnabled) && EqualityUtility.EqualsWithNullCheck(CentralPackageVersionOverrideDisabled, other.CentralPackageVersionOverrideDisabled) && EqualityUtility.EqualsWithNullCheck(CentralPackageTransitivePinningEnabled, other.CentralPackageTransitivePinningEnabled) && RestoreAuditProperties == other.RestoreAuditProperties; @@ -233,6 +240,7 @@ protected void FillClone(ProjectRestoreMetadata clone) clone.ProjectWideWarningProperties = ProjectWideWarningProperties?.Clone(); clone.RestoreLockProperties = RestoreLockProperties?.Clone(); clone.CentralPackageVersionsEnabled = CentralPackageVersionsEnabled; + clone.CentralPackageFloatingVersionsEnabled = CentralPackageFloatingVersionsEnabled; clone.CentralPackageVersionOverrideDisabled = CentralPackageVersionOverrideDisabled; clone.CentralPackageTransitivePinningEnabled = CentralPackageTransitivePinningEnabled; clone.RestoreAuditProperties = RestoreAuditProperties?.Clone(); diff --git a/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt index 7dc5c58110b..8cdb954084d 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt @@ -1 +1,3 @@ #nullable enable +NuGet.ProjectModel.ProjectRestoreMetadata.CentralPackageFloatingVersionsEnabled.get -> bool +NuGet.ProjectModel.ProjectRestoreMetadata.CentralPackageFloatingVersionsEnabled.set -> void diff --git a/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/VsSolutionRestoreServiceTests.cs b/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/VsSolutionRestoreServiceTests.cs index 0f862e570e4..b43f0952505 100644 --- a/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/VsSolutionRestoreServiceTests.cs +++ b/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/VsSolutionRestoreServiceTests.cs @@ -1967,7 +1967,7 @@ public async Task NominateProjectAsync_CancelledToken_ThrowsOperationCanceledExc public void ToPackageSpec_CentralVersions_AreAddedToThePackageSpecIfCPVMIsEnabled() { // Arrange - ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "prjectC", Guid.NewGuid().ToString()); + ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "projectC", Guid.NewGuid().ToString()); var emptyReferenceItems = Array.Empty(); var targetFrameworks = new VsTargetFrameworkInfo3[] { new VsTargetFrameworkInfo3( @@ -2009,7 +2009,7 @@ public void ToPackageSpec_CentralVersions_AreAddedToThePackageSpecIfCPVMIsEnable public void ToPackageSpec_CentralVersions_CPVMIsEnabled_NoPackageVersions() { // Arrange - ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "prjectC", Guid.NewGuid().ToString()); + ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "projectC", Guid.NewGuid().ToString()); var emptyReferenceItems = Array.Empty(); var targetFrameworks = new VsTargetFrameworkInfo3[] { new VsTargetFrameworkInfo3( @@ -2042,7 +2042,7 @@ public void ToPackageSpec_CentralVersions_CPVMIsEnabled_NoPackageVersions() public void ToPackageSpec_CentralVersions_AreNotAddedToThePackageSpecIfCPVMIsNotEnabled(string packRefVersion, string managePackageVersionsCentrally) { // Arrange - ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "prjectC", Guid.NewGuid().ToString()); + ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "projectC", Guid.NewGuid().ToString()); var emptyReferenceItems = Array.Empty(); var packageReferenceProperties = packRefVersion == null ? new VsReferenceProperties() : @@ -2090,7 +2090,7 @@ public void ToPackageSpec_CentralVersions_AreNotAddedToThePackageSpecIfCPVMIsNot public void ToPackageSpec_CentralVersionOverride_CanBeDisabled(string isCentralPackageVersionOverrideEnabled, bool expected) { // Arrange - ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "prjectC", Guid.NewGuid().ToString()); + ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "projectC", Guid.NewGuid().ToString()); var emptyReferenceItems = Array.Empty(); var targetFrameworks = new VsTargetFrameworkInfo3[] { new VsTargetFrameworkInfo3( @@ -2151,7 +2151,7 @@ public void ToPackageSpec_CentralVersionOverride_CanBeDisabled(string isCentralP public void ToPackageSpec_TransitiveDependencyPinning_CanBeEnabled(string CentralPackageTransitivePinningEnabled, bool expected) { // Arrange - ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "prjectC", Guid.NewGuid().ToString()); + ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "projectC", Guid.NewGuid().ToString()); var emptyReferenceItems = Array.Empty(); var targetFrameworks = new VsTargetFrameworkInfo3[] { new VsTargetFrameworkInfo3( @@ -2183,6 +2183,49 @@ public void ToPackageSpec_TransitiveDependencyPinning_CanBeEnabled(string Centra } } + [Theory] + [InlineData(null, false)] + [InlineData("", false)] + [InlineData(" ", false)] + [InlineData("invalid", false)] + [InlineData("false", false)] + [InlineData("true", true)] + [InlineData(" true ", true)] + public void ToPackageSpec_CentralPackageFloatingVersions_CanBeEnabled(string centralPackageFloatingVersionsEnabled, bool expected) + { + // Arrange + ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "projectC", Guid.NewGuid().ToString()); + var emptyReferenceItems = Array.Empty(); + + var targetFrameworks = new VsTargetFrameworkInfo3[] { new VsTargetFrameworkInfo3( + targetFrameworkMoniker: CommonFrameworks.NetStandard20.ToString(), + packageReferences: new[] { new VsReferenceItem("foo", new VsReferenceProperties()) }, + projectReferences: emptyReferenceItems, + packageDownloads: emptyReferenceItems, + frameworkReferences: emptyReferenceItems, + projectProperties: ProjectRestoreInfoBuilder.GetTargetFrameworkProperties(CommonFrameworks.NetStandard20).Concat(new VsProjectProperty[] + { + new VsProjectProperty(ProjectBuildProperties.ManagePackageVersionsCentrally, "true"), + new VsProjectProperty(ProjectBuildProperties.CentralPackageFloatingVersionsEnabled, centralPackageFloatingVersionsEnabled), + }), + centralPackageVersions: Array.Empty()) + }; + + // Act + PackageSpec result = VsSolutionRestoreService.ToPackageSpec(projectName, targetFrameworks, CommonFrameworks.NetStandard20.ToString(), string.Empty); + + // Assert + + if (expected) + { + Assert.True(result.RestoreMetadata.CentralPackageFloatingVersionsEnabled); + } + else + { + Assert.False(result.RestoreMetadata.CentralPackageFloatingVersionsEnabled); + } + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -2233,7 +2276,7 @@ await CaptureNominateResultAsync(projectFullPath, builder.ProjectRestoreInfo2) : public void ToPackageSpec_TargetFrameworkWithAlias_DefinesAliasCorrectly() { // Arrange - ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "prjectC", Guid.NewGuid().ToString()); + ProjectNames projectName = new ProjectNames(@"f:\project\project.csproj", "project", "project.csproj", "projectC", Guid.NewGuid().ToString()); var emptyReferenceItems = Array.Empty(); var packageReferenceProperties = new VsReferenceProperties(); diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/MSBuildStaticGraphRestoreTests.cs b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/MSBuildStaticGraphRestoreTests.cs index 04138ac9d73..216d92feba2 100644 --- a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/MSBuildStaticGraphRestoreTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/MSBuildStaticGraphRestoreTests.cs @@ -762,7 +762,7 @@ public void IsCentralVersionsManagementEnabled_OnlyPackageReferenceWithProjectCP }); // Act - var result = MSBuildStaticGraphRestore.GetCentralPackageManagementSettings(project, projectStyle).IsEnabled; + var result = MSBuildRestoreUtility.GetCentralPackageManagementSettings(project, projectStyle).IsEnabled; // Assert Assert.Equal(expected, result); @@ -786,7 +786,7 @@ public void IsCentralVersionOverrideEnabled_OnlyPackageReferenceWithProjectCPVME }); // Act - var result = MSBuildStaticGraphRestore.GetCentralPackageManagementSettings(project, ProjectStyle.PackageReference).IsVersionOverrideDisabled; + var result = MSBuildRestoreUtility.GetCentralPackageManagementSettings(project, ProjectStyle.PackageReference).IsVersionOverrideDisabled; // Assert Assert.Equal(disabled, result); @@ -810,7 +810,7 @@ public void TransitiveDependencyPinning_CanBeEnabled(string value, bool enabled) }); // Act - var result = MSBuildStaticGraphRestore.GetCentralPackageManagementSettings(project, ProjectStyle.PackageReference).IsCentralPackageTransitivePinningEnabled; + var result = MSBuildRestoreUtility.GetCentralPackageManagementSettings(project, ProjectStyle.PackageReference).IsCentralPackageTransitivePinningEnabled; // Assert Assert.Equal(enabled, result); diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs index 245e378ffa4..ded8c289e22 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs @@ -3725,11 +3725,9 @@ public void MSBuildRestoreUtility_GetPackageSpec_CPVM_EnabledLegacyProjectsMerge [Theory] [InlineData(null, false)] [InlineData("", false)] - [InlineData(" ", false)] [InlineData("true", false)] [InlineData("invalid", false)] [InlineData("false", true)] - [InlineData(" false ", true)] public void MSBuildRestoreUtility_GetPackageSpec_CPVM_VersionOverrideCanBeDisabled(string isCentralPackageVersionOverrideEnabled, bool disabled) { var projectName = "alegacycpvm"; @@ -3829,6 +3827,111 @@ public void MSBuildRestoreUtility_GetPackageSpec_CPVM_VersionOverrideCanBeDisabl } } + [Theory] + [InlineData(null, false)] + [InlineData(" ", false)] + [InlineData("false", false)] + [InlineData("invalid", false)] + [InlineData("true", true)] + public void MSBuildRestoreUtility_GetPackageSpec_CPVM_FloatingVersionsCanBeEnabled(string isCentralPackageFloatingVersionsEnabled, bool enabled) + { + var projectName = "alegacycpvm"; + using (var workingDir = TestDirectory.Create()) + { + // Arrange + var projectUniqueName = "482C20DE-DFF9-4BD0-B90A-BD3201AA351A"; + var project1Root = Path.Combine(workingDir, projectName); + var project1Path = Path.Combine(project1Root, $"{projectName}.csproj"); + + var items = new List>(); + + items.Add(new Dictionary() + { + { "Type", "ProjectSpec" }, + { "ProjectName", projectName }, + { "ProjectStyle", "PackageReference" }, + { "ProjectUniqueName", projectUniqueName }, + { "ProjectPath", project1Path }, + { "_CentralPackageVersionsEnabled", "true"}, + { "CentralPackageFloatingVersionsEnabled", isCentralPackageFloatingVersionsEnabled } + }); + + items.Add(new Dictionary() + { + { "Type", "TargetFrameworkInformation" }, + { "AssetTargetFallback", "" }, + { "PackageTargetFallback", "" }, + { "ProjectUniqueName", projectUniqueName }, + { "TargetFramework", "net472" }, + { "TargetFrameworkIdentifier", ".NETFramework" }, + { "TargetFrameworkVersion", "v4.7.2" }, + { "TargetFrameworkMoniker", ".NETFramework,Version=v4.7.2" }, + { "TargetPlatformIdentifier", "" }, + { "TargetPlatformMoniker", "" }, + { "TargetPlatformVersion", "" }, + }); + + // Package reference + // No TargetFrameworks metadata + items.Add(new Dictionary() + { + { "Type", "Dependency" }, + { "ProjectUniqueName", projectUniqueName }, + { "Id", "x" }, + { "IncludeAssets", "build;compile" }, + { "CrossTargeting", "true" }, + }); + + + // Central Version for the package above and another one for a package y + items.Add(new Dictionary() + { + { "Type", "CentralPackageVersion" }, + { "ProjectUniqueName", projectUniqueName }, + { "Id", "x" }, + { "VersionRange", "1.0.0" }, + }); + items.Add(new Dictionary() + { + { "Type", "CentralPackageVersion" }, + { "ProjectUniqueName", projectUniqueName }, + { "Id", "y" }, + { "VersionRange", "2.0.0" }, + }); + + var wrappedItems = items.Select(CreateItems).ToList(); + + // Act + var dgSpec = MSBuildRestoreUtility.GetDependencySpec(wrappedItems); + var project1Spec = dgSpec.Projects.Single(e => e.Name == projectName); + + // Assert + Assert.Equal(1, project1Spec.TargetFrameworks.Count()); + Assert.Equal(1, project1Spec.TargetFrameworks.First().Dependencies.Count); + Assert.Equal(2, project1Spec.TargetFrameworks.First().CentralPackageVersions.Count); + + Assert.Equal("[1.0.0, )", project1Spec.TargetFrameworks.First().Dependencies[0].LibraryRange.VersionRange.ToNormalizedString()); + Assert.Equal(LibraryIncludeFlags.Compile | LibraryIncludeFlags.Build, project1Spec.TargetFrameworks.First().Dependencies[0].IncludeType); + + Assert.Equal("x", project1Spec.TargetFrameworks.First().CentralPackageVersions["x"].Name); + Assert.Equal("[1.0.0, )", project1Spec.TargetFrameworks.First().CentralPackageVersions["x"].VersionRange.ToNormalizedString()); + + Assert.Equal("y", project1Spec.TargetFrameworks.First().CentralPackageVersions["y"].Name); + Assert.Equal("[2.0.0, )", project1Spec.TargetFrameworks.First().CentralPackageVersions["y"].VersionRange.ToNormalizedString()); + + Assert.True(project1Spec.RestoreMetadata.CentralPackageVersionsEnabled); + + if (enabled) + { + Assert.True(project1Spec.RestoreMetadata.CentralPackageFloatingVersionsEnabled); + } + else + { + Assert.False(project1Spec.RestoreMetadata.CentralPackageFloatingVersionsEnabled); + } + } + } + [Theory] [InlineData(ProjectStyle.DotnetCliTool)] [InlineData(ProjectStyle.DotnetToolReference)] @@ -4594,6 +4697,47 @@ public void MSBuildRestoreUtility_GetPackageSpec_SingleTargetingFrameworkWithPro } } + [Theory] + [InlineData(null, false)] + [InlineData("", false)] + [InlineData(" ", false)] + [InlineData("false", false)] + [InlineData("invalid", false)] + [InlineData("true", true)] + [InlineData(" true ", true)] + public void IsPropertyTrue_ReturnsExpectedValue(string value, bool expected) + { + const string propertyName = "Property1"; + + MSBuildItem item = new("Item1", new Dictionary(StringComparer.OrdinalIgnoreCase) + { + [propertyName] = value + }); + + MSBuildRestoreUtility.IsPropertyTrue(item, propertyName).Should().Be(expected); + } + + [Theory] + [InlineData(null, false)] + [InlineData("", false)] + [InlineData(" ", false)] + [InlineData("false", true)] + [InlineData(" false ", true)] + [InlineData("invalid", false)] + [InlineData("true", false)] + [InlineData(" true ", false)] + public void IsPropertyFalse_ReturnsExpectedValue(string value, bool expected) + { + const string propertyName = "Property1"; + + MSBuildItem item = new("Item1", new Dictionary(StringComparer.OrdinalIgnoreCase) + { + [propertyName] = value + }); + + MSBuildRestoreUtility.IsPropertyFalse(item, propertyName).Should().Be(expected); + } + private static IDictionary CreateProject(string root, string uniqueName) { var project1Path = Path.Combine(root, "a.csproj"); diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests/RestoreCommandTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests/RestoreCommandTests.cs index 977c6391156..38e723d5b52 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests/RestoreCommandTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests/RestoreCommandTests.cs @@ -1984,12 +1984,21 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( } } - [Fact] - public async Task RestoreCommand_CentralVersion_ErrorWhenFloatingCentralVersions() + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task RestoreCommand_CentralVersion_ErrorWhenFloatingCentralVersions(bool enabled) { // Arrange using (var pathContext = new SimpleTestPathContext()) { + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + pathContext.PackageSource, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext("foo", "1.0.0")); + + using var context = new SourceCacheContext(); + var projectName = "TestProject"; var projectPath = Path.Combine(pathContext.SolutionRoot, projectName); var outputPath = Path.Combine(projectPath, "obj"); @@ -2005,23 +2014,27 @@ public async Task RestoreCommand_CentralVersion_ErrorWhenFloatingCentralVersions new List() { packageRefDependecyFoo }, new List() { centralVersionFoo }); - var packageSpec = new PackageSpec(new List() { tfi }); - packageSpec.RestoreMetadata = new ProjectRestoreMetadata() + var packageSpec = new PackageSpec(new List() { tfi }) { - ProjectUniqueName = projectName, - CentralPackageVersionsEnabled = true, - ProjectStyle = ProjectStyle.PackageReference, - OutputPath = outputPath, + FilePath = projectPath, + Name = projectName, + RestoreMetadata = new ProjectRestoreMetadata() + { + ProjectUniqueName = projectName, + CentralPackageVersionsEnabled = true, + CentralPackageFloatingVersionsEnabled = enabled, + ProjectStyle = ProjectStyle.PackageReference, + OutputPath = outputPath, + } }; - packageSpec.FilePath = projectPath; var dgspec = new DependencyGraphSpec(); dgspec.AddProject(packageSpec); - var sources = new List(); + var sources = new List { new PackageSource(pathContext.PackageSource) }; var logger = new TestLogger(); - var request = new TestRestoreRequest(dgspec.GetProjectSpec(projectName), sources, "", logger) + var request = new TestRestoreRequest(packageSpec, sources, "", logger) { LockFilePath = Path.Combine(projectPath, "project.assets.json"), ProjectStyle = ProjectStyle.PackageReference @@ -2032,13 +2045,19 @@ public async Task RestoreCommand_CentralVersion_ErrorWhenFloatingCentralVersions var result = await restoreCommand.ExecuteAsync(); // Assert - Assert.False(result.Success); - Assert.Equal(1, logger.ErrorMessages.Count); - logger.ErrorMessages.TryDequeue(out var errorMessage); - Assert.True(errorMessage.Contains("Centrally defined floating package versions are not allowed.")); - var messagesForNU1011 = result.LockFile.LogMessages.Where(m => m.Code == NuGetLogCode.NU1011); - Assert.Equal(1, messagesForNU1011.Count()); - + if (enabled) + { + Assert.True(result.Success); + } + else + { + Assert.False(result.Success); + Assert.Equal(1, logger.ErrorMessages.Count); + logger.ErrorMessages.TryDequeue(out var errorMessage); + Assert.True(errorMessage.Contains("Centrally defined floating package versions are not allowed.")); + var messagesForNU1011 = result.LockFile.LogMessages.Where(m => m.Code == NuGetLogCode.NU1011); + Assert.Equal(1, messagesForNU1011.Count()); + } } } diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs index 14e73f00898..4a3ce43ddc0 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs @@ -2996,6 +2996,48 @@ public void GetPackageSpec_WhenCentralPackageVersionsManagementEnabledValueIsVal Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageVersionsEnabled); } + [Theory] + [InlineData(null, false)] + [InlineData(true, true)] + [InlineData(false, false)] + public void GetPackageSpec_WhenCentralPackageFloatingVersionsEnabledValueIsValid_ReturnsCentralPackageFloatingVersionsEnabled( + bool? value, + bool expectedValue) + { + var json = $"{{\"restore\":{{\"centralPackageFloatingVersionsEnabled\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; + PackageSpec packageSpec = GetPackageSpec(json); + + Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageFloatingVersionsEnabled); + } + + [Theory] + [InlineData(null, false)] + [InlineData(true, true)] + [InlineData(false, false)] + public void GetPackageSpec_WhenCentralPackageVersionOverrideDisabledValueIsValid_ReturnsCentralPackageVersionOverrideDisabled( + bool? value, + bool expectedValue) + { + var json = $"{{\"restore\":{{\"centralPackageVersionOverrideDisabled\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; + PackageSpec packageSpec = GetPackageSpec(json); + + Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageVersionOverrideDisabled); + } + + [Theory] + [InlineData(null, false)] + [InlineData(true, true)] + [InlineData(false, false)] + public void GetPackageSpec_WhenCentralPackageTransitivePinningEnabledValueIsValid_ReturnsCentralPackageTransitivePinningEnabled( + bool? value, + bool expectedValue) + { + var json = $"{{\"restore\":{{\"CentralPackageTransitivePinningEnabled\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; + PackageSpec packageSpec = GetPackageSpec(json); + + Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageTransitivePinningEnabled); + } + [Fact] public void GetPackageSpec_WhenSourcesValueIsEmptyObject_ReturnsEmptySources() { diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs index 85368671ba2..30d5a1ad86f 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs @@ -109,7 +109,7 @@ public void PackOptionsCloneTest() Assert.NotEqual(originalPackOptions, clone); Assert.Equal(originalPackageName, clone.PackageType[0].Name); - // Set Up again + // Arrange again originalPackOptions.Mappings.Add("randomString", files); // Act again @@ -229,7 +229,7 @@ public static RuntimeGraph CreateRuntimeGraph() //[InlineData("ModifyRestoreSettings", true)] = Not really included in the equals and hash code comparisons public void PackageSpecCloneTest(string methodName, bool validateJson) { - // Set up + // Arrange var packageSpec = CreatePackageSpec(); var clonedPackageSpec = packageSpec.Clone(); @@ -407,7 +407,7 @@ private static ProjectRestoreMetadataFrameworkInfo CreateProjectRestoreMetadataF [Fact] public void ProjectRestoreMetadataCloneTest() { - // Set up + // Arrange var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); // Act @@ -421,7 +421,7 @@ public void ProjectRestoreMetadataCloneTest() [Fact] public void ProjectRestoreMetadataCloneChangeSourcesTest() { - // Set up + // Arrange var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); // Preconditions @@ -437,10 +437,86 @@ public void ProjectRestoreMetadataCloneChangeSourcesTest() Assert.Equal(1, happyClone.Sources.Count); } + [Fact] + public void ProjectRestoreMetadataCloneChangeCentralPackageVersionsEnabledTest() + { + // Arrange + var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); + + // Preconditions + var happyClone = originalProjectRestoreMetadata.Clone(); + Assert.Equal(originalProjectRestoreMetadata, happyClone); + Assert.False(object.ReferenceEquals(originalProjectRestoreMetadata, happyClone)); + + // Act + originalProjectRestoreMetadata.CentralPackageVersionsEnabled = !originalProjectRestoreMetadata.CentralPackageVersionsEnabled; + + // Assert + Assert.NotEqual(originalProjectRestoreMetadata, happyClone); + Assert.Equal(originalProjectRestoreMetadata.CentralPackageVersionsEnabled, !happyClone.CentralPackageVersionsEnabled); + } + + [Fact] + public void ProjectRestoreMetadataCloneChangeCentralPackageFloatingVersionsEnabledTest() + { + // Arrange + var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); + + // Preconditions + var happyClone = originalProjectRestoreMetadata.Clone(); + Assert.Equal(originalProjectRestoreMetadata, happyClone); + Assert.False(object.ReferenceEquals(originalProjectRestoreMetadata, happyClone)); + + // Act + originalProjectRestoreMetadata.CentralPackageFloatingVersionsEnabled = !originalProjectRestoreMetadata.CentralPackageFloatingVersionsEnabled; + + // Assert + Assert.NotEqual(originalProjectRestoreMetadata, happyClone); + Assert.Equal(originalProjectRestoreMetadata.CentralPackageFloatingVersionsEnabled, !happyClone.CentralPackageFloatingVersionsEnabled); + } + + [Fact] + public void ProjectRestoreMetadataCloneChangeCentralPackageVersionOverrideDisabledTest() + { + // Arrange + var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); + + // Preconditions + var happyClone = originalProjectRestoreMetadata.Clone(); + Assert.Equal(originalProjectRestoreMetadata, happyClone); + Assert.False(object.ReferenceEquals(originalProjectRestoreMetadata, happyClone)); + + // Act + originalProjectRestoreMetadata.CentralPackageVersionOverrideDisabled = !originalProjectRestoreMetadata.CentralPackageVersionOverrideDisabled; + + // Assert + Assert.NotEqual(originalProjectRestoreMetadata, happyClone); + Assert.Equal(originalProjectRestoreMetadata.CentralPackageVersionOverrideDisabled, !happyClone.CentralPackageVersionOverrideDisabled); + } + + [Fact] + public void ProjectRestoreMetadataCloneChangeCentralPackageTransitivePinningEnabledTest() + { + // Arrange + var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); + + // Preconditions + var happyClone = originalProjectRestoreMetadata.Clone(); + Assert.Equal(originalProjectRestoreMetadata, happyClone); + Assert.False(object.ReferenceEquals(originalProjectRestoreMetadata, happyClone)); + + // Act + originalProjectRestoreMetadata.CentralPackageTransitivePinningEnabled = !originalProjectRestoreMetadata.CentralPackageTransitivePinningEnabled; + + // Assert + Assert.NotEqual(originalProjectRestoreMetadata, happyClone); + Assert.Equal(originalProjectRestoreMetadata.CentralPackageTransitivePinningEnabled, !happyClone.CentralPackageTransitivePinningEnabled); + } + [Fact] public void ProjectRestoreMetadataCloneChangeFallbackFoldersTest() { - // Set up + // Arrange var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); // Preconditions @@ -459,7 +535,7 @@ public void ProjectRestoreMetadataCloneChangeFallbackFoldersTest() [Fact] public void ProjectRestoreMetadataCloneChangeConfigFilePathsTest() { - // Set up + // Arrange var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); // Preconditions @@ -478,7 +554,7 @@ public void ProjectRestoreMetadataCloneChangeConfigFilePathsTest() [Fact] public void ProjectRestoreMetadataCloneChangeOriginalTargetFrameworksTest() { - // Set up + // Arrange var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); // Preconditions @@ -497,7 +573,7 @@ public void ProjectRestoreMetadataCloneChangeOriginalTargetFrameworksTest() [Fact] public void ProjectRestoreMetadataCloneChangeFilesTest() { - // Set up + // Arrange var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); // Preconditions @@ -516,7 +592,7 @@ public void ProjectRestoreMetadataCloneChangeFilesTest() [Fact] public void ProjectRestoreMetadataCloneChangeProjectWideWarningPropertiesTest() { - // Set up + // Arrange var originalProjectRestoreMetadata = CreateProjectRestoreMetadata(); // Preconditions @@ -525,7 +601,7 @@ public void ProjectRestoreMetadataCloneChangeProjectWideWarningPropertiesTest() Assert.False(object.ReferenceEquals(originalProjectRestoreMetadata, happyClone)); // Act - originalProjectRestoreMetadata.ProjectWideWarningProperties.AllWarningsAsErrors = false; ; + originalProjectRestoreMetadata.ProjectWideWarningProperties.AllWarningsAsErrors = false; // Assert Assert.NotEqual(originalProjectRestoreMetadata, happyClone); @@ -535,7 +611,7 @@ public void ProjectRestoreMetadataCloneChangeProjectWideWarningPropertiesTest() [Fact] public void ProjectRestoreMetadataFileCloneTest() { - // Set up + // Arrange var originalProjectRestoreMetadataFile = new ProjectRestoreMetadataFile("packagePath", "absolutePath"); // Act @@ -579,7 +655,7 @@ public void ProjectRestoreMetadataFrameworkInfoCloneTest() [Fact] public void ProjectRestoreReferenceCloneTest() { - // Set up + // Arrange var originalProjectRestoreReference = new ProjectRestoreReference(); originalProjectRestoreReference.ProjectPath = "Path"; originalProjectRestoreReference.ProjectUniqueName = "ProjectUniqueName"; @@ -605,7 +681,7 @@ private ProjectRestoreSettings CreateProjectRestoreSettings() [Fact] public void ProjectRestoreSettingsCloneTest() { - // Set up + // Arrange var originalProjectRestoreSettings = CreateProjectRestoreSettings(); // Act @@ -649,7 +725,7 @@ internal static TargetFrameworkInformation CreateTargetFrameworkInformation(stri [Fact] public void TargetFrameworkInformationCloneTest() { - // Set up + // Arrange var originalTargetFrameworkInformation = CreateTargetFrameworkInformation(); // Act @@ -731,7 +807,7 @@ public void TargetFrameworkInformationCloneTest() [Fact] public void WarningPropertiesCloneTest() { - // Set up + // Arrange var allWarningsAsErrors = false; var noWarn = new HashSet() { NuGetLogCode.NU1000, NuGetLogCode.NU1500 }; var warningsAsErrors = new HashSet() { NuGetLogCode.NU1001, NuGetLogCode.NU1501 }; diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs index 4a4fc66b8f0..e2d66e09080 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs @@ -329,6 +329,60 @@ public void Equals_WithCentralPackageVersionsEnabled(bool left, bool right, bool AssertEquality(expected, leftSide, rightSide); } + [Theory] + [InlineData(true, true, true)] + [InlineData(true, false, false)] + [InlineData(false, true, false)] + [InlineData(false, false, true)] + public void Equals_WithCentralPackageFloatingVersionsEnabled(bool left, bool right, bool expected) + { + var leftSide = new ProjectRestoreMetadata + { + CentralPackageFloatingVersionsEnabled = left + }; + var rightSide = new ProjectRestoreMetadata + { + CentralPackageFloatingVersionsEnabled = right + }; + AssertEquality(expected, leftSide, rightSide); + } + + [Theory] + [InlineData(true, true, true)] + [InlineData(true, false, false)] + [InlineData(false, true, false)] + [InlineData(false, false, true)] + public void Equals_WithCentralPackageVersionOverrideDisabled(bool left, bool right, bool expected) + { + var leftSide = new ProjectRestoreMetadata + { + CentralPackageVersionOverrideDisabled = left + }; + var rightSide = new ProjectRestoreMetadata + { + CentralPackageVersionOverrideDisabled = right + }; + AssertEquality(expected, leftSide, rightSide); + } + + [Theory] + [InlineData(true, true, true)] + [InlineData(true, false, false)] + [InlineData(false, true, false)] + [InlineData(false, false, true)] + public void Equals_WithCentralPackageTransitivePinningEnabled(bool left, bool right, bool expected) + { + var leftSide = new ProjectRestoreMetadata + { + CentralPackageTransitivePinningEnabled = left + }; + var rightSide = new ProjectRestoreMetadata + { + CentralPackageTransitivePinningEnabled = right + }; + AssertEquality(expected, leftSide, rightSide); + } + [Theory] [InlineData(true, true, true)] [InlineData(true, false, false)] @@ -574,6 +628,41 @@ public void HashCode_WithValidateRuntimeAssets(bool left, bool right, bool expec AssertHashCode(expected, leftSide, rightSide); } + [Theory] + [InlineData(true, true, true)] + [InlineData(true, false, false)] + [InlineData(false, true, false)] + [InlineData(false, false, true)] + public void HashCode_WithCentralPackageVersionOverrideDisabled(bool left, bool right, bool expected) + { + var leftSide = new ProjectRestoreMetadata + { + CentralPackageVersionOverrideDisabled = left + }; + var rightSide = new ProjectRestoreMetadata + { + CentralPackageVersionOverrideDisabled = right + }; + AssertHashCode(expected, leftSide, rightSide); + } + [Theory] + [InlineData(true, true, true)] + [InlineData(true, false, false)] + [InlineData(false, true, false)] + [InlineData(false, false, true)] + public void HashCode_WithCentralPackageTransitivePinningEnabled(bool left, bool right, bool expected) + { + var leftSide = new ProjectRestoreMetadata + { + CentralPackageTransitivePinningEnabled = left + }; + var rightSide = new ProjectRestoreMetadata + { + CentralPackageTransitivePinningEnabled = right + }; + AssertHashCode(expected, leftSide, rightSide); + } + [Theory] [InlineData(true, true, true)] [InlineData(true, false, false)] @@ -592,6 +681,24 @@ public void HashCode_WithCentralPackageVersionsEnabled(bool left, bool right, bo AssertHashCode(expected, leftSide, rightSide); } + [Theory] + [InlineData(true, true, true)] + [InlineData(true, false, false)] + [InlineData(false, true, false)] + [InlineData(false, false, true)] + public void HashCode_WithCentralPackageFloatingVersionsEnabled(bool left, bool right, bool expected) + { + var leftSide = new ProjectRestoreMetadata + { + CentralPackageFloatingVersionsEnabled = left + }; + var rightSide = new ProjectRestoreMetadata + { + CentralPackageFloatingVersionsEnabled = right + }; + AssertHashCode(expected, leftSide, rightSide); + } + [Theory] [InlineData(true, true, true)] [InlineData(true, false, false)]