Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<PackageReference Update="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildPackageVersion)" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Update="Microsoft.Win32.Registry" Version="4.7.0" />
<PackageReference Update="MSBuild.ProjectCreation" Version="7.0.4-preview" />
<PackageReference Update="MSBuild.ProjectCreation" Version="7.0.7-preview" />
<PackageReference Update="Shouldly" Version="4.0.3" />
<PackageReference Update="xunit" Version="2.4.1" />
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.3" />
Expand Down
15 changes: 15 additions & 0 deletions src/Traversal.UnitTests/CustomProjectCreatorTemplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ public static class CustomProjectCreatorTemplates
{
private static readonly string ThisAssemblyDirectory = Path.GetDirectoryName(typeof(CustomProjectCreatorTemplates).Assembly.Location);

public static ProjectCreator ProjectWithBuildOutput(
this ProjectCreatorTemplates templates,
string target,
ProjectCollection projectCollection = null,
Action<ProjectCreator> customAction = null)
{
return ProjectCreator.Templates.SdkCsproj(
sdk: String.Empty,
projectCreator: customAction,
projectCollection: projectCollection)
.Target(target, returns: "@(CollectedBuildOutput)")
.TargetItemInclude("CollectedBuildOutput", Path.Combine("bin", "$(MSBuildThisFileName).dll"))
.Target("Clean");
}

public static ProjectCreator TraversalProject(
this ProjectCreatorTemplates templates,
string[] projectReferences = null,
Expand Down
65 changes: 21 additions & 44 deletions src/Traversal.UnitTests/TraversalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,57 +19,34 @@ namespace Microsoft.Build.Traversal.UnitTests
public class TraversalTests : MSBuildSdkTestBase
{
[Theory]
[InlineData(null)]
[InlineData("Build")]
[InlineData("Rebuild")]
[InlineData("GetTargetPath")]
public void CollectsProjectReferenceBuildTargetOutputs(string target)
{
string[] projects = new[]
{
GetSkeletonCSProjWithTargetOutputs(@"A\A"),
GetSkeletonCSProjWithTargetOutputs(@"B\B"),
}.Select(i => i.FullPath).ToArray();

var subTraversalProject = ProjectCreator
.Templates
.TraversalProject(projects, path: GetTempFile(@"dirs\dirs.proj"))
.Save();

ProjectCreator
.Create(path: GetTempFile("root.proj"))
.Target("BuildTraversalProject")
.Task(
"MSBuild",
parameters: new Dictionary<string, string>
{
["Projects"] = subTraversalProject.FullPath,
["Targets"] = "Restore",
["Properties"] = $"MSBuildRestoreSessionId={Guid.NewGuid():N}",
})
.Task(
"MSBuild",
parameters: new Dictionary<string, string>
ProjectCreator traversalProject = ProjectCreator.Templates.TraversalProject(
projectReferences: new string[]
{
["Projects"] = subTraversalProject.FullPath,
["Targets"] = target,
ProjectCreator.Templates.ProjectWithBuildOutput(target)
.Save(GetTempFile(Path.Combine("A", "A.csproj"))),
ProjectCreator.Templates.ProjectWithBuildOutput(target)
.Save(GetTempFile(Path.Combine("B", "B.csproj"))),
})
.TaskOutputItem("TargetOutputs", "CollectedOutputs")
.TaskMessage("%(CollectedOutputs.Identity)", MessageImportance.High)
.Save()
.TryBuild("BuildTraversalProject", out bool _, out BuildOutput buildOutput);
.Property("SkipResolvePackageAssets", bool.TrueString)
.Target("ResolvePackageAssets")
.Save(GetTempFile("dirs.proj"))
.TryBuild(target, out bool result, out BuildOutput buildOutput, out IDictionary<string, TargetResult> targetOutputs);

buildOutput.Messages.High.ShouldContain("A.dll", buildOutput.GetConsoleLog());
buildOutput.Messages.High.ShouldContain("B.dll", buildOutput.GetConsoleLog());
result.ShouldBeTrue(buildOutput.GetConsoleLog());

ProjectCreator GetSkeletonCSProjWithTargetOutputs(string projectName)
{
return ProjectCreator.Templates.SdkCsproj(path: GetTempFile($"{projectName}.csproj"), sdk: string.Empty)
.Target("Build", returns: "@(TestReturnItem)")
.TargetItemGroup()
.TargetItemInclude("TestReturnItem", "$(MSBuildThisFileName).dll")
.Target("Clean")
.Save();
}
targetOutputs.ShouldContainKey(target, buildOutput.GetConsoleLog());

targetOutputs[target].Items.Select(i => i.ItemSpec).ShouldBe(
new[]
{
Path.Combine("bin", "A.dll"),
Path.Combine("bin", "B.dll"),
},
buildOutput.GetConsoleLog());
}

[Fact]
Expand Down
23 changes: 19 additions & 4 deletions src/Traversal/Sdk/Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@

<PublishDependsOn Condition="'$(NoBuild)' == 'true'">
</PublishDependsOn>

<GetTargetPathDependsOn></GetTargetPathDependsOn>
</PropertyGroup>

<ItemGroup Condition=" '$(TraversalTranslateProjectFileItems)' != 'false' ">
Expand Down Expand Up @@ -236,10 +238,23 @@
ContinueOnError="$([MSBuild]::ValueOrDefault('$(PublishContinueOnError)', '$(ContinueOnError)'))" />
</Target>

<!--
Traversal projects do not build an assembly so dependent projects shouldn't get a path to the target. Override the GetTargetPath to do nothing.
-->
<Target Name="GetTargetPath" />
<Target Name="GetTargetPath"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ViktorHofer I think GetTargetPath isn't available for a multi targeting build. So if one of the project references is multing-targeting (e.g, <TargetFrameworks>net9.0;net10</TargetFrameworks>), this would fail because the project doesn't have the target defined. What should be the right behavior here?

DependsOnTargets="$(GetTargetPathDependsOn)"
Returns="@(CollectedBuildOutput)">
<MSBuild Projects="@(ProjectReference)"
Condition="'%(ProjectReference.Build)' != 'false'"
Targets="GetTargetPath"
BuildInParallel="$([MSBuild]::ValueOrDefault('%(ProjectReference.BuildInParallel)', '$(BuildInParallel)'))"
SkipNonexistentProjects="$(SkipNonexistentProjects)"
SkipNonexistentTargets="$(SkipNonexistentTargets)"
StopOnFirstFailure="$(StopOnFirstFailure)"
Properties="%(ProjectReference.SetConfiguration); %(ProjectReference.SetPlatform); %(ProjectReference.SetTargetFramework)"
ContinueOnError="$(ContinueOnError)">
<Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
</MSBuild>
</Target>

<Target Name="GetTargetPathWithTargetPlatformMoniker" />

<!--
Traversal projects do not build anything and should not check for invalid configuration/platform.
Expand Down