Skip to content

Commit

Permalink
Disable floating versions in project level for CPM (#5011)
Browse files Browse the repository at this point in the history
* disable install/update package button for CPM projects in PM UI
  • Loading branch information
martinrrm authored Feb 24, 2023
1 parent 91f6fdb commit 3113357
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,8 @@ public OptionsViewModel Options

public string PackagePath => _searchResultPackage?.PackagePath;

public bool IsCentralPackageManagementEnabled { get; set; }

protected void AddBlockedVersions(List<NuGetVersion> blockedVersions)
{
// add a separator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,14 @@ public bool IsProjectPackageReference
}
}

public bool IsFloatingVersionSupported
{
get
{
return IsProjectPackageReference && !IsCentralPackageManagementEnabled;
}
}

public bool IsInstalledVersionTopLevel => InstalledVersion != null && PackageLevel == PackageLevel.TopLevel;

public override IEnumerable<IProjectContextInfo> GetSelectedProjects(UserAction action)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ private async ValueTask InitializeAsync(PackageManagerModel model, INuGetUILogge
ApplySettings(settings, Settings);
_initialized = true;

await IsCentralPackageManagementEnabledAsync(CancellationToken.None);

NuGetExperimentationService = await ServiceLocator.GetComponentModelServiceAsync<INuGetExperimentationService>();
_isTransitiveDependenciesExperimentEnabled = NuGetExperimentationService.IsExperimentEnabled(ExperimentationConstants.TransitiveDependenciesInPMUI);

Expand Down Expand Up @@ -567,6 +569,19 @@ await RunAndEmitRefreshAsync(async () =>
}
}

private async Task IsCentralPackageManagementEnabledAsync(CancellationToken cancellationToken)
{
if (!Model.IsSolution)
{
await NuGetUIThreadHelper.JoinableTaskFactory.RunAsync(async delegate
{
// Go off the UI thread to perform non-UI operations
await TaskScheduler.Default;
_detailModel.IsCentralPackageManagementEnabled = await Model.Context.Projects.First().IsCentralPackageManagementEnabledAsync(Model.Context.ServiceBroker, cancellationToken);
});
}
}

private async Task<string> GetSettingsKeyAsync(CancellationToken cancellationToken)
{
string key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@
MinHeight="22"
AutomationProperties.Name="{x:Static local:Resources.Label_Version}"
AutomationProperties.LabeledBy="{Binding ElementName=SubscriptionsLabel}"
IsEditable="{Binding IsProjectPackageReference, Converter={StaticResource InverseNullToVisibilityConverter}}"
IsTextSearchEnabled="{Binding IsProjectPackageReference, Converter={StaticResource NotNullOrTrueToBooleanConverter}}"
IsReadOnly="{Binding IsProjectPackageReference, Converter={StaticResource NotNullOrTrueToBooleanConverter}}"
StaysOpenOnEdit="{Binding IsProjectPackageReference, Converter={StaticResource InverseNullToVisibilityConverter}}"
IsEditable="{Binding IsFloatingVersionSupported, Converter={StaticResource InverseNullToVisibilityConverter}}"
IsTextSearchEnabled="{Binding IsFloatingVersionSupported, Converter={StaticResource NotNullOrTrueToBooleanConverter}}"
IsReadOnly="{Binding IsFloatingVersionSupported, Converter={StaticResource NotNullOrTrueToBooleanConverter}}"
StaysOpenOnEdit="{Binding IsFloatingVersionSupported, Converter={StaticResource InverseNullToVisibilityConverter}}"
ItemsSource="{Binding Path=VersionsView}"
Text="{Binding Path=UserInput, Mode=OneWay}"
SelectionChanged="Versions_SelectionChanged"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using NuGet.Frameworks;
using NuGet.Packaging.Core;
using NuGet.VisualStudio.Internal.Contracts;
using NuGet.ProjectManagement.Projects;
using System.Linq;

namespace NuGet.PackageManagement.VisualStudio
{
Expand Down Expand Up @@ -123,6 +125,21 @@ public static async ValueTask<IReadOnlyCollection<NuGetFramework>> GetTargetFram
}
}

public static async ValueTask<bool> IsCentralPackageManagementEnabledAsync(this IProjectContextInfo projectContextInfo,
IServiceBroker serviceBroker,
CancellationToken cancellationToken)
{
Assumes.NotNull(projectContextInfo);
Assumes.NotNull(serviceBroker);

cancellationToken.ThrowIfCancellationRequested();

using (INuGetProjectManagerService projectManager = await GetProjectManagerAsync(serviceBroker, cancellationToken))
{
return await projectManager.IsCentralPackageManagementEnabledAsync(projectContextInfo.ProjectId, cancellationToken);
}
}

public static async ValueTask<IProjectMetadataContextInfo> GetMetadataAsync(
this IProjectContextInfo projectContextInfo,
IServiceBroker serviceBroker,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,30 @@ public async ValueTask<IReadOnlyCollection<NuGetFramework>> GetTargetFrameworksA
return targetFrameworks;
}

public async ValueTask<bool> IsCentralPackageManagementEnabledAsync(string projectId, CancellationToken cancellationToken)
{
Assumes.NotNullOrEmpty(projectId);

cancellationToken.ThrowIfCancellationRequested();

NuGetProject? project = await SolutionUtility.GetNuGetProjectAsync(
_sharedState.SolutionManager,
projectId,
cancellationToken);

Assumes.NotNull(project);

if (project is BuildIntegratedNuGetProject buildIntegratedProject)
{
var dgcContext = new DependencyGraphCacheContext();
IReadOnlyList<ProjectModel.PackageSpec>? packageSpecs = await buildIntegratedProject.GetPackageSpecsAsync(dgcContext);

return packageSpecs.Any(spec => spec.RestoreMetadata.CentralPackageVersionsEnabled);
}

return false;
}

public async ValueTask<IProjectMetadataContextInfo> GetMetadataAsync(string projectId, CancellationToken cancellationToken)
{
Assumes.NotNullOrEmpty(projectId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ ValueTask<IReadOnlyCollection<PackageDependencyInfo>> GetInstalledPackagesDepend
string projectId,
bool includeUnresolved,
CancellationToken cancellationToken);
ValueTask<bool> IsCentralPackageManagementEnabledAsync(string projectId, CancellationToken cancellationToken);
ValueTask<IProjectMetadataContextInfo> GetMetadataAsync(string projectId, CancellationToken cancellationToken);
ValueTask<IProjectContextInfo> GetProjectAsync(string projectId, CancellationToken cancellationToken);
ValueTask<IReadOnlyCollection<IProjectContextInfo>> GetProjectsAsync(CancellationToken cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#nullable enable
NuGet.VisualStudio.Internal.Contracts.INuGetProjectManagerService.IsCentralPackageManagementEnabledAsync(string! projectId, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<bool>
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,54 @@ private async Task GetPackageFoldersAsync_LegacyProjectWithFallbackFolder_Return
Assert.Equal(2, folders.Count);
}

[Theory]
[InlineData(true)]
[InlineData(false)]
private async Task GetCentralPackageVersionsManagmentEnabled_SucceedsAsync(bool isCentralPackageVersionsEnabled)
{
string projectName = Guid.NewGuid().ToString();
string projectId = projectName;
var projectSystemCache = new ProjectSystemCache();
IVsProjectAdapter projectAdapter = Mock.Of<IVsProjectAdapter>();

using var pathContext = new SimpleTestPathContext();
Initialize();

// Prepare: Create project
string projectFullPath = Path.Combine(pathContext.SolutionRoot, projectName, $"{projectName}.csproj");

CpsPackageReferenceProject prProject = CreateCpsPackageReferenceProject(projectName, projectFullPath, projectSystemCache);

ProjectNames projectNames = GetTestProjectNames(projectFullPath, projectName);
string referenceSpec = $@"
{{
""frameworks"":
{{
""net6.0"":
{{
""dependencies"":
{{
}}
}}
}}
}}";
PackageSpec packageSpec = JsonPackageSpecReader.GetPackageSpec(referenceSpec, projectName, projectFullPath).WithTestRestoreMetadata();
packageSpec.RestoreMetadata.CentralPackageVersionsEnabled = isCentralPackageVersionsEnabled;

// Restore info
DependencyGraphSpec projectRestoreInfo = ProjectTestHelpers.GetDGSpecFromPackageSpecs(packageSpec);
projectSystemCache.AddProjectRestoreInfo(projectNames, projectRestoreInfo, new List<IAssetsLogMessage>());
projectSystemCache.AddProject(projectNames, projectAdapter, prProject).Should().BeTrue();

_solutionManager.NuGetProjects.Add(prProject);

// Act
bool isCentralPackageManagmentEnabled = await _projectManager.IsCentralPackageManagementEnabledAsync(projectId, CancellationToken.None);

// Assert
Assert.Equal(isCentralPackageVersionsEnabled, isCentralPackageManagmentEnabled);
}

[Fact]
private async Task GetPackageFoldersAsync_CpsProjectWithFallbackFolder_ReturnsPackageFoldersAsync()
{
Expand Down

0 comments on commit 3113357

Please sign in to comment.