Skip to content

Commit c8a073c

Browse files
authored
Simplify ProjectFileUtils.AddItem overloads (#7378)
1 parent ab9648d commit c8a073c

9 files changed

Lines changed: 125 additions & 45 deletions

File tree

test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/Commands/RestoreCommandTests.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,6 @@ public async Task Restore_WithPackagesConfigProject_PackageWithVulnerabilities_W
13721372
name: "NuGetAuditSuppress",
13731373
identity: advisoryUrl1,
13741374
framework: NuGetFramework.AnyFramework,
1375-
properties: new Dictionary<string, string>(),
13761375
attributes: new Dictionary<string, string>());
13771376
xmlA.Save(projectA.ProjectPath);
13781377

@@ -1383,7 +1382,6 @@ public async Task Restore_WithPackagesConfigProject_PackageWithVulnerabilities_W
13831382
name: "NuGetAuditSuppress",
13841383
identity: advisoryUrl2,
13851384
framework: NuGetFramework.AnyFramework,
1386-
properties: new Dictionary<string, string>(),
13871385
attributes: new Dictionary<string, string>());
13881386
xmlB.Save(projectB.ProjectPath);
13891387

test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetRestoreCommandTest.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,7 +3654,6 @@ public async void RestoreCommand_WithPackagesConfigProject_PackageWithVulnerabil
36543654
name: "NuGetAuditSuppress",
36553655
identity: advisoryUrl1,
36563656
framework: NuGetFramework.AnyFramework,
3657-
properties: new Dictionary<string, string>(),
36583657
attributes: new Dictionary<string, string>());
36593658
xmlA.Save(projectA.ProjectPath);
36603659

@@ -3665,7 +3664,6 @@ public async void RestoreCommand_WithPackagesConfigProject_PackageWithVulnerabil
36653664
name: "NuGetAuditSuppress",
36663665
identity: advisoryUrl2,
36673666
framework: NuGetFramework.AnyFramework,
3668-
properties: new Dictionary<string, string>(),
36693667
attributes: new Dictionary<string, string>());
36703668
xmlB.Save(projectB.ProjectPath);
36713669

test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreLoggingTests.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,12 @@ public async Task RestoreLogging_VerifyNU1605DowngradeWarningAsync()
5959
ProjectFileUtils.AddItem(doc,
6060
"PackageReference", "z",
6161
NuGetFramework.Parse("netcoreapp1.0"),
62-
new Dictionary<string, string>(),
6362
new Dictionary<string, string>() { { "Version", "1.*" } });
6463

6564
// x *
6665
ProjectFileUtils.AddItem(doc,
6766
"PackageReference", "x",
6867
NuGetFramework.Parse("netcoreapp1.0"),
69-
new Dictionary<string, string>(),
7068
new Dictionary<string, string>() { { "Version", "*" } });
7169

7270
doc.Save(projectA.ProjectPath);

test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreNETCoreTest.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6598,7 +6598,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
65986598
xml,
65996599
"PackageDownload",
66006600
packageX1.Id,
6601-
NuGetFramework.AnyFramework,
6601+
string.Empty,
66026602
props,
66036603
attributes);
66046604

@@ -6795,7 +6795,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
67956795
xml,
67966796
"PackageDownload",
67976797
packageX1.Id,
6798-
NuGetFramework.AnyFramework,
6798+
string.Empty,
67996799
props,
68006800
attributes);
68016801

@@ -7092,7 +7092,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
70927092
xml,
70937093
"FrameworkReference",
70947094
"FrameworkRefY",
7095-
NuGetFramework.AnyFramework,
7095+
string.Empty,
70967096
props,
70977097
attributes);
70987098

@@ -7175,15 +7175,15 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
71757175
xml,
71767176
"FrameworkReference",
71777177
"FrameworkRefY",
7178-
NuGetFramework.AnyFramework,
7178+
string.Empty,
71797179
props,
71807180
attributes);
71817181
attributes.Add("PrivateAssets", "all");
71827182
ProjectFileUtils.AddItem(
71837183
xml,
71847184
"FrameworkReference",
71857185
"FrameworkRefSupressed",
7186-
NuGetFramework.AnyFramework,
7186+
string.Empty,
71877187
props,
71887188
attributes);
71897189

@@ -10977,7 +10977,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
1097710977
xml,
1097810978
item,
1097910979
"X",
10980-
NuGetFramework.AnyFramework,
10980+
string.Empty,
1098110981
new Dictionary<string, string>(),
1098210982
attributes);
1098310983

@@ -10987,7 +10987,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
1098710987
xml,
1098810988
item,
1098910989
"X",
10990-
NuGetFramework.AnyFramework,
10990+
string.Empty,
1099110991
new Dictionary<string, string>(),
1099210992
attributes);
1099310993
xml.Save(projectA.ProjectPath);
@@ -11045,7 +11045,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
1104511045
xml,
1104611046
"PackageReference",
1104711047
"X",
11048-
NuGetFramework.AnyFramework,
11048+
string.Empty,
1104911049
new Dictionary<string, string>(),
1105011050
new Dictionary<string, string>());
1105111051
xml.Save(projectA.ProjectPath);
@@ -11268,7 +11268,7 @@ void AddPackageReferenceToProject(SimpleTestProjectContext project)
1126811268
xml,
1126911269
"PackageReference",
1127011270
"D",
11271-
NuGetFramework.AnyFramework,
11271+
string.Empty,
1127211272
new Dictionary<string, string>(),
1127311273
new Dictionary<string, string>());
1127411274

test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetRestoreTests.cs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -116,22 +116,7 @@ public void DotnetRestore_WithAuthorSignedPackage_Succeeds()
116116

117117
_dotnetFixture.CreateDotnetNewProject(pathContext.SolutionRoot, projectName, "classlib -f netstandard2.0", testOutputHelper: _testOutputHelper);
118118

119-
using (var stream = File.Open(projectFile, FileMode.Open, FileAccess.ReadWrite))
120-
{
121-
var xml = XDocument.Load(stream);
122-
123-
var attributes = new Dictionary<string, string>() { { "Version", "1.0.0" } };
124-
125-
ProjectFileUtils.AddItem(
126-
xml,
127-
"PackageReference",
128-
"TestPackage.AuthorSigned",
129-
string.Empty,
130-
new Dictionary<string, string>(),
131-
attributes);
132-
133-
ProjectFileUtils.WriteXmlToFile(xml, stream);
134-
}
119+
ProjectFileUtils.AddItem(projectFile, "PackageReference", "TestPackage.AuthorSigned", string.Empty, new Dictionary<string, string>() { { "Version", "1.0.0" } });
135120

136121
_dotnetFixture.RestoreProjectExpectSuccess(workingDirectory, projectName, testOutputHelper: _testOutputHelper);
137122
}

test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3241,7 +3241,7 @@ public void PackCommand_PackProject_OutputsBuildActionForContentFiles(string ite
32413241
xml,
32423242
itemType,
32433243
"abc.png",
3244-
NuGetFramework.AnyFramework,
3244+
string.Empty,
32453245
properties,
32463246
attributes);
32473247

@@ -4347,7 +4347,7 @@ public void PackCommand_PackLicense_PackBasicLicenseFile(string licenseFileName,
43474347
xml,
43484348
"None",
43494349
licenseFileName,
4350-
NuGetFramework.AnyFramework,
4350+
string.Empty,
43514351
properties,
43524352
attributes);
43534353
ProjectFileUtils.WriteXmlToFile(xml, stream);
@@ -4449,7 +4449,7 @@ public void PackCommand_PackLicense_PackBasicLicenseFile_FileIncorrectCasing()
44494449
xml,
44504450
"None",
44514451
realLicenseFileName,
4452-
NuGetFramework.AnyFramework,
4452+
string.Empty,
44534453
properties,
44544454
attributes);
44554455

@@ -4608,7 +4608,7 @@ public void PackCommand_PackLicense_IncludeLicenseFileWithSnupkg()
46084608
xml,
46094609
"None",
46104610
licenseFileName,
4611-
NuGetFramework.AnyFramework,
4611+
string.Empty,
46124612
properties,
46134613
attributes);
46144614
ProjectFileUtils.WriteXmlToFile(xml, stream);
@@ -4692,7 +4692,7 @@ public void PackCommand_PackLicense_IncludeLicenseFileWithSymbolsNupkg()
46924692
xml,
46934693
"None",
46944694
licenseFileName,
4695-
NuGetFramework.AnyFramework,
4695+
string.Empty,
46964696
properties,
46974697
attributes);
46984698
ProjectFileUtils.WriteXmlToFile(xml, stream);

test/NuGet.Core.FuncTests/Msbuild.Integration.Test/MsbuildRestoreTaskTests.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,7 +1779,6 @@ public async Task MsbuildRestore_WithPackagesConfigProject_PackageWithVulnerabil
17791779
name: "NuGetAuditSuppress",
17801780
identity: advisoryUrl1,
17811781
framework: NuGetFramework.AnyFramework,
1782-
properties: new Dictionary<string, string>(),
17831782
attributes: new Dictionary<string, string>());
17841783
xmlA.Save(projectA.ProjectPath);
17851784

@@ -1790,7 +1789,6 @@ public async Task MsbuildRestore_WithPackagesConfigProject_PackageWithVulnerabil
17901789
name: "NuGetAuditSuppress",
17911790
identity: advisoryUrl2,
17921791
framework: NuGetFramework.AnyFramework,
1793-
properties: new Dictionary<string, string>(),
17941792
attributes: new Dictionary<string, string>());
17951793
xmlB.Save(projectB.ProjectPath);
17961794

test/TestUtilities/Test.Utility/SimpleTestSetup/ProjectFileUtils.cs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,120 @@ public static bool HasCondition(XElement element, string condition)
7373
return StringComparer.OrdinalIgnoreCase.Equals(MSBuildStringUtility.TrimAndGetNullForEmpty(condition), elementCondition);
7474
}
7575

76+
/// <summary>
77+
/// Opens a project file, adds an MSBuild item, and writes it back.
78+
/// This is the simplest method for adding an item to a project file, but it is not the most efficient if you need to add multiple items since it opens and writes the file for each item added.
79+
/// Prefer this method whenever there you only need to do 1 item change.
80+
/// </summary>
81+
/// <param name="projectFilePath">The full path to the project file.</param>
82+
/// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>).</param>
83+
/// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
84+
/// <param name="framework">
85+
/// The short TFM string used to generate a per-TFM condition on the <c>ItemGroup</c>.
86+
/// Pass an empty string to emit the item unconditionally.
87+
/// </param>
88+
/// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
89+
public static void AddItem(string projectFilePath,
90+
string name,
91+
string identity,
92+
string framework,
93+
Dictionary<string, string> attributes)
94+
{
95+
using var stream = File.Open(projectFilePath, FileMode.Open, FileAccess.ReadWrite);
96+
var xml = XDocument.Load(stream);
97+
AddItem(xml, name, identity, framework, attributes);
98+
WriteXmlToFile(xml, stream);
99+
}
100+
101+
/// <summary>
102+
/// Adds a new MSBuild item to the project file inside a new <c>ItemGroup</c>.
103+
/// When <paramref name="framework"/> is a specific framework, a <c>Condition</c> attribute of the form
104+
/// <c>'$(TargetFramework)' == '&lt;tfm&gt;'</c> is added to the <c>ItemGroup</c>; otherwise no condition is emitted.
105+
/// Scenarios:
106+
/// <list type="bullet">
107+
/// <item>Adding a <c>PackageReference</c> item</item>
108+
/// <item>Adding a <c>PackageVersion</c> item</item>
109+
/// <item>Adding a <c>FrameworkReference</c> item</item>
110+
/// <item>Adding a <c>NuGetAuditSuppress</c> item</item>
111+
/// <item>Adding a <c>PrunePackageReference</c> item</item>
112+
/// </list>
113+
/// </summary>
114+
/// <param name="doc">The project XML document to modify.</param>
115+
/// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>, <c>FrameworkReference</c>).</param>
116+
/// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
117+
/// <param name="framework">
118+
/// The target framework used to generate a per-TFM condition on the <c>ItemGroup</c>.
119+
/// Pass <see cref="NuGetFramework.AnyFramework"/> (or any non-specific framework) to emit the item unconditionally.
120+
/// </param>
121+
/// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
76122
public static void AddItem(XDocument doc,
77123
string name,
78124
string identity,
79125
NuGetFramework framework,
80-
Dictionary<string, string> properties,
81126
Dictionary<string, string> attributes)
82127
{
83128
AddItem(doc, name, identity,
84-
framework?.IsSpecificFramework == true ? framework.GetShortFolderName() : string.Empty, properties, attributes);
129+
framework?.IsSpecificFramework == true ? framework.GetShortFolderName() : string.Empty, attributes);
130+
}
131+
132+
/// <summary>
133+
/// Adds a new MSBuild item to the project file inside a new <c>ItemGroup</c>.
134+
/// When <paramref name="framework"/> is a non-empty string, a <c>Condition</c> attribute of the form
135+
/// <c>'$(TargetFramework)' == '&lt;tfm&gt;'</c> is added to the <c>ItemGroup</c>; pass an empty string to emit the item unconditionally.
136+
/// Item metadata is expressed as XML attributes on the item element. For most scenarios this overload is preferred over
137+
/// the one that accepts both <c>properties</c> and <c>attributes</c>.
138+
/// Scenarios:
139+
/// <list type="bullet">
140+
/// <item>Adding a <c>PackageReference</c> item</item>
141+
/// <item>Adding a <c>PackageVersion</c> item</item>
142+
/// <item>Adding a <c>FrameworkReference</c> item</item>
143+
/// <item>Adding a <c>NuGetAuditSuppress</c> item</item>
144+
/// <item>Adding a <c>PrunePackageReference</c> item</item>
145+
/// </list>
146+
/// </summary>
147+
/// <param name="doc">The project XML document to modify.</param>
148+
/// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>, <c>FrameworkReference</c>).</param>
149+
/// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
150+
/// <param name="framework">
151+
/// The short TFM string used to generate a per-TFM condition on the <c>ItemGroup</c> (e.g. <c>"net8.0"</c>).
152+
/// Pass an empty string to emit the item unconditionally.
153+
/// </param>
154+
/// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
155+
public static void AddItem(XDocument doc,
156+
string name,
157+
string identity,
158+
string framework,
159+
Dictionary<string, string> attributes)
160+
{
161+
AddItem(doc, name, identity, framework, properties: [], attributes);
85162
}
86163

164+
/// <summary>
165+
/// Adds a new MSBuild item to the project file inside a new <c>ItemGroup</c>.
166+
/// When <paramref name="framework"/> is a non-empty string, a <c>Condition</c> attribute of the form
167+
/// <c>'$(TargetFramework)' == '&lt;tfm&gt;'</c> is added to the <c>ItemGroup</c>; pass an empty string to emit the item unconditionally.
168+
/// This overload accepts both <paramref name="attributes"/> (written as XML attributes on the item element) and
169+
/// <paramref name="properties"/> (written as child XML elements). While MSBuild evaluates both equivalently as item metadata,
170+
/// prefer the overload that only takes <paramref name="attributes"/> for new call sites — it is more concise and matches
171+
/// the SDK-style project convention of expressing metadata as attributes.
172+
/// Use this overload only when a caller must distinguish between attribute-style and element-style metadata.
173+
/// <list type="bullet">
174+
/// <item>Adding a <c>PackageReference</c> item</item>
175+
/// <item>Adding a <c>PackageVersion</c> item</item>
176+
/// <item>Adding a <c>FrameworkReference</c> item</item>
177+
/// <item>Adding a <c>NuGetAuditSuppress</c> item</item>
178+
/// <item>Adding a <c>PrunePackageReference</c> item</item>
179+
/// </list>
180+
/// </summary>
181+
/// <param name="doc">The project XML document to modify.</param>
182+
/// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>, <c>FrameworkReference</c>).</param>
183+
/// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
184+
/// <param name="framework">
185+
/// The short TFM string used to generate a per-TFM condition on the <c>ItemGroup</c> (e.g. <c>"net8.0"</c>).
186+
/// Pass an empty string to emit the item unconditionally.
187+
/// </param>
188+
/// <param name="properties">Child XML elements to add under the item element (e.g. <c>&lt;Version&gt;1.0.0&lt;/Version&gt;</c>).</param>
189+
/// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
87190
public static void AddItem(XDocument doc,
88191
string name,
89192
string identity,

0 commit comments

Comments
 (0)