Skip to content

Commit 00b81e7

Browse files
authored
Load before/after.{solutionName}.sln.targets for .slnx (#11535)
added test checking that targets from these files are included in the project
1 parent cce4d88 commit 00b81e7

File tree

3 files changed

+53
-10
lines changed

3 files changed

+53
-10
lines changed

src/Build.UnitTests/Construction/SolutionFile_NewParser_Tests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ private static SolutionFile ParseSolutionHelper(string solutionFileContents, boo
144144
}
145145
}
146146

147-
private static string ConvertToSlnx(string slnPath)
147+
internal static string ConvertToSlnx(string slnPath)
148148
{
149149
string slnxPath = slnPath + "x";
150150
ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(slnPath).ShouldNotBeNull();

src/Build.UnitTests/Construction/SolutionProjectGenerator_Tests.cs

+30
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,36 @@ public void SolutionProjectIgnoresDuplicateDefaultTargets(string name)
8383
}
8484
}
8585

86+
/// <summary>
87+
/// Test that targets in before.{sln}.targets and after.{sln}.targets files are included in the project.
88+
/// </summary>
89+
[Theory]
90+
[InlineData("before.MySln.sln.targets", false)]
91+
[InlineData("before.MySln.sln.targets", true)]
92+
[InlineData("after.MySln.sln.targets", false)]
93+
[InlineData("after.MySln.sln.targets", true)]
94+
public void SolutionProjectIncludesBeforeAndAfterTargets(string name, bool convertToSlnx)
95+
{
96+
using (TestEnvironment testEnvironment = TestEnvironment.Create())
97+
{
98+
TransientTestFolder folder = testEnvironment.CreateFolder(createFolder: true);
99+
string solutionFileContents = "Microsoft Visual Studio Solution File, Format Version 12.00";
100+
TransientTestFile sln = testEnvironment.CreateFile(folder, "MySln.sln", solutionFileContents);
101+
string solutionPath = convertToSlnx ? SolutionFile_NewParser_Tests.ConvertToSlnx(sln.Path) : sln.Path;
102+
testEnvironment.CreateFile(folder, name,
103+
"""
104+
<Project>
105+
<Target Name="TestTarget" />
106+
</Project>
107+
""");
108+
ProjectInstance[] instances = SolutionProjectGenerator.Generate(SolutionFile.Parse(solutionPath), null, null, _buildEventContext, CreateMockLoggingService());
109+
instances.ShouldHaveSingleItem();
110+
instances[0].Targets.ShouldContainKey("TestTarget");
111+
MockLogger logger = new MockLogger(output);
112+
instances[0].Build(targets: null, new List<ILogger> { logger }).ShouldBeTrue();
113+
}
114+
}
115+
86116
[Fact]
87117
public void BuildProjectAsTarget()
88118
{

src/Build/Construction/Solution/SolutionProjectGenerator.cs

+22-9
Original file line numberDiff line numberDiff line change
@@ -948,15 +948,7 @@ private ProjectInstance CreateTraversalInstance(string wrapperProjectToolsVersio
948948
// Add our local extensibility points to the project representing the solution
949949
// Imported at the top: before.mysolution.sln.targets
950950
// Imported at the bottom: after.mysolution.sln.targets
951-
string escapedSolutionFile = EscapingUtilities.Escape(Path.GetFileName(_solutionFile.FullPath));
952-
string escapedSolutionDirectory = EscapingUtilities.Escape(_solutionFile.SolutionFileDirectory);
953-
string localFile = Path.Combine(escapedSolutionDirectory, "before." + escapedSolutionFile + ".targets");
954-
ProjectImportElement importBeforeLocal = traversalProject.CreateImportElement(localFile);
955-
importBeforeLocal.Condition = @"exists('" + localFile + "')";
956-
957-
localFile = Path.Combine(escapedSolutionDirectory, "after." + escapedSolutionFile + ".targets");
958-
ProjectImportElement importAfterLocal = traversalProject.CreateImportElement(localFile);
959-
importAfterLocal.Condition = @"exists('" + localFile + "')";
951+
(ProjectImportElement importBeforeLocal, ProjectImportElement importAfterLocal) = CreateBeforeAndAfterSolutionImports(traversalProject);
960952

961953
// Put locals second so they can override globals if they want
962954
traversalProject.PrependChild(importBeforeLocal);
@@ -1025,6 +1017,27 @@ private ProjectInstance CreateTraversalInstance(string wrapperProjectToolsVersio
10251017
return traversalInstance;
10261018
}
10271019

1020+
private (ProjectImportElement ImportBeforeSln, ProjectImportElement ImportAfterSln) CreateBeforeAndAfterSolutionImports(ProjectRootElement traversalProject)
1021+
{
1022+
string escapedSolutionFileName = EscapingUtilities.Escape(Path.GetFileName(_solutionFile.FullPath));
1023+
if (escapedSolutionFileName.EndsWith(".slnx"))
1024+
{
1025+
// We want to load only after.{solutionFileName}.sln.targets for solution files with .slnx extension
1026+
escapedSolutionFileName = escapedSolutionFileName.Substring(0, escapedSolutionFileName.Length - 1);
1027+
}
1028+
1029+
string escapedSolutionDirectory = EscapingUtilities.Escape(_solutionFile.SolutionFileDirectory);
1030+
string localFile = Path.Combine(escapedSolutionDirectory, $"before.{escapedSolutionFileName}.targets");
1031+
ProjectImportElement importBeforeLocal = traversalProject.CreateImportElement(localFile);
1032+
importBeforeLocal.Condition = $"exists('{localFile}')";
1033+
1034+
localFile = Path.Combine(escapedSolutionDirectory, $"after.{escapedSolutionFileName}.targets");
1035+
ProjectImportElement importAfterLocal = traversalProject.CreateImportElement(localFile);
1036+
importAfterLocal.Condition = $"exists('{localFile}')";
1037+
1038+
return (importBeforeLocal, importAfterLocal);
1039+
}
1040+
10281041
private void EmitMetaproject(ProjectRootElement metaproject, string path)
10291042
{
10301043
if (Traits.Instance.EmitSolutionMetaproj)

0 commit comments

Comments
 (0)