diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs b/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs index 18454a97f15..bb7f6f86505 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks.Console/MSBuildStaticGraphRestore.cs @@ -1083,6 +1083,7 @@ private PackageSpec GetPackageSpec(IMSBuildProject project, IReadOnlyDictionary< restoreMetadata.UsingMicrosoftNETSdk = MSBuildRestoreUtility.GetUsingMicrosoftNETSdk(project.GetProperty("UsingMicrosoftNETSdk")); restoreMetadata.SdkAnalysisLevel = MSBuildRestoreUtility.GetSdkAnalysisLevel(project.GetProperty("SdkAnalysisLevel")); restoreMetadata.UseLegacyDependencyResolver = project.IsPropertyTrue("RestoreUseLegacyDependencyResolver"); + restoreMetadata.RestoreDoNotWriteDependencyGraphSpec = project.IsPropertyTrue("RestoreDoNotWriteDependencyGraphSpec"); return (restoreMetadata, targetFrameworkInfos); diff --git a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets index 55ee77a28ed..b125016e3a0 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets +++ b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets @@ -961,6 +961,7 @@ Copyright (c) .NET Foundation. All rights reserved. $(UsingMicrosoftNETSdk) $(NETCoreSdkVersion) $(RestoreUseLegacyDependencyResolver) + $(RestoreDoNotWriteDependencyGraphSpec) diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs index 13df4d863f0..80ded36043b 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs @@ -344,7 +344,8 @@ public async Task ExecuteAsync(CancellationToken token) restoreTime.Elapsed) { AuditRan = auditRan, - DidDGHashChange = !noOpCacheFileEvaluation + DidDGHashChange = !noOpCacheFileEvaluation, + DoNotWriteDependencyGraphSpec = _request.Project.RestoreMetadata.RestoreDoNotWriteDependencyGraphSpec }; telemetry.TelemetryEvent[UpdatedAssetsFile] = restoreResult._isAssetsFileDirty.Value; diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreResult.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreResult.cs index 8edb5224875..af5e0bafb1c 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreResult.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreResult.cs @@ -92,6 +92,11 @@ public class RestoreResult : IRestoreResult /// internal bool DidDGHashChange { get; init; } + /// + /// If true, the dg spec file should not be written to disk. + /// + internal bool DoNotWriteDependencyGraphSpec { get; init; } + private readonly string _dependencyGraphSpecFilePath; @@ -317,7 +322,7 @@ await FileUtility.ReplaceWithLock( private async Task CommitDgSpecFileAsync(ILogger log, bool toolCommit) { - if (!toolCommit && _dependencyGraphSpecFilePath != null && _dependencyGraphSpec != null && (DidDGHashChange || !File.Exists(_dependencyGraphSpecFilePath))) + if (!toolCommit && !DoNotWriteDependencyGraphSpec && _dependencyGraphSpecFilePath != null && _dependencyGraphSpec != null && (DidDGHashChange || !File.Exists(_dependencyGraphSpecFilePath))) { log.LogVerbose($"Persisting dg to {_dependencyGraphSpecFilePath}"); diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs index 0a87daeed09..dd9aed6ef75 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/MSBuildRestoreUtility.cs @@ -293,6 +293,7 @@ public static PackageSpec GetPackageSpec(IEnumerable items) result.RestoreMetadata.UsingMicrosoftNETSdk = GetUsingMicrosoftNETSdk(specItem.GetProperty("UsingMicrosoftNETSdk")); result.RestoreMetadata.SdkAnalysisLevel = GetSdkAnalysisLevel(specItem.GetProperty("SdkAnalysisLevel")); result.RestoreMetadata.UseLegacyDependencyResolver = IsPropertyTrue(specItem, "RestoreUseLegacyDependencyResolver"); + result.RestoreMetadata.RestoreDoNotWriteDependencyGraphSpec = IsPropertyTrue(specItem, "RestoreDoNotWriteDependencyGraphSpec"); result.RestoreSettings.SdkVersion = GetSdkAnalysisLevel(specItem.GetProperty("NETCoreSdkVersion")); } diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/PackageSpecFactory.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/PackageSpecFactory.cs index d8570d0a0df..1d690ed9de2 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/PackageSpecFactory.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/PackageSpecFactory.cs @@ -182,6 +182,7 @@ private static (ProjectRestoreMetadata? RestoreMetadata, List public bool UseLegacyDependencyResolver { get; set; } + /// + /// Gets or sets a value indicating whether or not the dependency graph spec file should not be written during restore. + /// The default value is . + /// + public bool RestoreDoNotWriteDependencyGraphSpec { get; set; } + public override int GetHashCode() { StringComparer osStringComparer = PathUtility.GetStringComparerBasedOnOS(); @@ -182,6 +188,7 @@ public override int GetHashCode() hashCode.AddObject(UsingMicrosoftNETSdk); hashCode.AddObject(SdkAnalysisLevel); hashCode.AddObject(UseLegacyDependencyResolver); + hashCode.AddObject(RestoreDoNotWriteDependencyGraphSpec); return hashCode.CombinedHash; } @@ -230,7 +237,8 @@ public bool Equals(ProjectRestoreMetadata other) RestoreAuditProperties == other.RestoreAuditProperties && UsingMicrosoftNETSdk == other.UsingMicrosoftNETSdk && EqualityUtility.EqualsWithNullCheck(SdkAnalysisLevel, other.SdkAnalysisLevel) && - UseLegacyDependencyResolver == other.UseLegacyDependencyResolver; + UseLegacyDependencyResolver == other.UseLegacyDependencyResolver && + RestoreDoNotWriteDependencyGraphSpec == other.RestoreDoNotWriteDependencyGraphSpec; } private HashSet GetSources(IList sources) @@ -284,6 +292,7 @@ protected void FillClone(ProjectRestoreMetadata clone) clone.SdkAnalysisLevel = SdkAnalysisLevel; clone.UsingMicrosoftNETSdk = UsingMicrosoftNETSdk; clone.UseLegacyDependencyResolver = UseLegacyDependencyResolver; + clone.RestoreDoNotWriteDependencyGraphSpec = RestoreDoNotWriteDependencyGraphSpec; } } } diff --git a/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt index e627a3f038e..c81731d50ce 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Unshipped.txt @@ -7,3 +7,5 @@ const NuGet.ProjectModel.LockFileFormat.LegacyVersion = 3 -> int ~static NuGet.ProjectModel.PackageSpecOperations.AddOrUpdateDependency(NuGet.ProjectModel.PackageSpec spec, NuGet.Packaging.Core.PackageIdentity identity, System.Collections.Generic.IEnumerable frameworksToAdd) -> void ~NuGet.ProjectModel.PackagesLockFileTarget.TargetAlias.get -> string ~NuGet.ProjectModel.PackagesLockFileTarget.TargetAlias.set -> void +NuGet.ProjectModel.ProjectRestoreMetadata.RestoreDoNotWriteDependencyGraphSpec.get -> bool +NuGet.ProjectModel.ProjectRestoreMetadata.RestoreDoNotWriteDependencyGraphSpec.set -> void diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs index 3ebd86b811e..3348c662ced 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/MSBuildRestoreUtilityTests.cs @@ -4873,6 +4873,52 @@ private IMSBuildItem CreateItems(IDictionary properties) return new MSBuildItem(Guid.NewGuid().ToString(), properties); } + [Theory] + [InlineData("true", true)] + [InlineData("false", false)] + [InlineData(null, false)] + [InlineData("", false)] + public void MSBuildRestoreUtility_GetPackageSpec_RestoreDoNotWriteDependencyGraphSpec( + string propertyValue, + bool expectedValue) + { + using (var workingDir = TestDirectory.Create()) + { + // Arrange + var project1Root = Path.Combine(workingDir, "a"); + var project1Path = Path.Combine(project1Root, "a.csproj"); + + var items = new List>(); + + var properties = new Dictionary() + { + { "Type", "ProjectSpec" }, + { "Version", "2.0.0" }, + { "ProjectName", "a" }, + { "ProjectStyle", "PackageReference" }, + { "ProjectUniqueName", "482C20DE-DFF9-4BD0-B90A-BD3201AA351A" }, + { "ProjectPath", project1Path }, + { "TargetFrameworks", "net46" }, + }; + + if (propertyValue != null) + { + properties["RestoreDoNotWriteDependencyGraphSpec"] = propertyValue; + } + + items.Add(properties); + + var wrappedItems = items.Select(CreateItems).ToList(); + + // Act + var dgSpec = MSBuildRestoreUtility.GetDependencySpec(wrappedItems); + var project1Spec = dgSpec.Projects.Single(); + + // Assert + project1Spec.RestoreMetadata.RestoreDoNotWriteDependencyGraphSpec.Should().Be(expectedValue); + } + } + private Dictionary WithUniqueName(Dictionary item, string uniqueName) { var newItem = new Dictionary(item, StringComparer.OrdinalIgnoreCase); diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreResultTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreResultTests.cs index 245c1d54bbf..0d6ade815af 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreResultTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreResultTests.cs @@ -381,6 +381,57 @@ public async Task CommitAsync_WithExistingDGSpecAndDidDGHashChange_WritesDepende Assert.True(File.Exists(dgSpecPath)); } + [Fact] + public async Task CommitAsync_WhenDoNotWriteDependencyGraphSpecIsTrue_DoesNotWriteDgSpec() + { + // Arrange + using var td = TestDirectory.Create(); + var path = Path.Combine(td, "project.assets.json"); + var cachePath = Path.Combine(td, "project.csproj.nuget.cache"); + var dgSpecPath = Path.Combine(td, "project1.nuget.g.dgspec.json"); + var dgSpec = new DependencyGraphSpec(); + var configJson = @" + { + ""frameworks"": { + ""net45"": { } + } + }"; + + var spec = JsonPackageSpecReader.GetPackageSpec(configJson, "TestProject", Path.Combine(td, "project.csproj")).WithTestRestoreMetadata(); + dgSpec.AddProject(spec); + dgSpec.AddRestore(spec.Name); + + var logger = new TestLogger(); + var result = new RestoreResult( + success: true, + restoreGraphs: null, + compatibilityCheckResults: null, + lockFile: new LockFile(), + previousLockFile: null, + lockFilePath: path, + msbuildFiles: Enumerable.Empty(), + cacheFile: new CacheFile("NotSoRandomString"), + cacheFilePath: cachePath, + packagesLockFilePath: null, + packagesLockFile: null, + dependencyGraphSpecFilePath: dgSpecPath, + dependencyGraphSpec: dgSpec, + projectStyle: ProjectStyle.Unknown, + elapsedTime: TimeSpan.MinValue) + { + DoNotWriteDependencyGraphSpec = true + }; + + // Act + await result.CommitAsync(logger, CancellationToken.None); + + // Assert + Assert.DoesNotContain( + logger.VerboseMessages, + m => m.Contains("Persisting dg")); + Assert.False(File.Exists(dgSpecPath)); + } + [Fact] public void WhenRestoreResult_LogMessagesAreSourcedFromTheAssetsFile() { diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs index 2e9cad4e0e9..1c5adad51b5 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs @@ -170,6 +170,62 @@ public void Write_ReadWriteWarningProperties() VerifyJsonPackageSpecRoundTrip(json); } + [Fact] + public void Write_ReadWrite_RestoreDoNotWriteDependencyGraphSpec_True() + { + // Arrange + var json = @"{ + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""restoreDoNotWriteDependencyGraphSpec"": true, + ""frameworks"": { + ""net45"": { + ""framework"": ""net45"", + ""projectReferences"": {} + } + } + } +}"; + // Act & Assert + VerifyJsonPackageSpecRoundTrip(json); + } + + [Fact] + public void Write_ReadWrite_RestoreDoNotWriteDependencyGraphSpec_DefaultFalse_NotWritten() + { + // Arrange - when RestoreDoNotWriteDependencyGraphSpec is false (default), it should not appear in output + var json = @"{ + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""frameworks"": { + ""net45"": { + ""framework"": ""net45"", + ""projectReferences"": {} + } + } + } +}"; + // Act + var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.csproj"); + + // Assert - default value should be false + spec.RestoreMetadata.RestoreDoNotWriteDependencyGraphSpec.Should().BeFalse(); + + // And it should not appear in the serialized output + var output = GetJsonString(spec); + output.Should().NotContain("restoreDoNotWriteDependencyGraphSpec"); + } + [Fact] public void Write_SerializesMembersAsJson() { diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs index e2d66e09080..7ce84513b98 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ProjectRestoreMetadataTests.cs @@ -833,5 +833,40 @@ private static void AssertHashCode(bool expected, ProjectRestoreMetadata leftSid leftSide.GetHashCode().Should().NotBe(rightSide.GetHashCode()); } } + + [Theory] + [InlineData(true, true, true)] + [InlineData(false, false, true)] + [InlineData(true, false, false)] + [InlineData(false, true, false)] + public void Equals_WithRestoreDoNotWriteDependencyGraphSpec(bool left, bool right, bool expected) + { + var leftSide = new ProjectRestoreMetadata + { + RestoreDoNotWriteDependencyGraphSpec = left + }; + + var rightSide = new ProjectRestoreMetadata + { + RestoreDoNotWriteDependencyGraphSpec = right + }; + + AssertEquality(expected, leftSide, rightSide); + AssertHashCode(expected, leftSide, rightSide); + } + + [Fact] + public void Clone_WithRestoreDoNotWriteDependencyGraphSpec() + { + var original = new ProjectRestoreMetadata + { + RestoreDoNotWriteDependencyGraphSpec = true + }; + + var clone = original.Clone(); + + clone.RestoreDoNotWriteDependencyGraphSpec.Should().Be(true); + AssertEquality(true, original, clone); + } } }