[Draft] Support Microsoft.Build.Traversal projects in dotnet test (MTP)#55297
Open
Evangelink wants to merge 3 commits into
Open
[Draft] Support Microsoft.Build.Traversal projects in dotnet test (MTP)#55297Evangelink wants to merge 3 commits into
Evangelink wants to merge 3 commits into
Conversation
Unblocks traversal (dirs.proj) support for 'dotnet test' with Microsoft.Testing.Platform (issue #51316). Three coordinated changes mirror how solutions are handled - the traversal project is a container that forwards to its ProjectReference items: - CLI evaluation: special-case the 'IsTraversal' MSBuild property in SolutionAndProjectUtility.GetProjectProperties. When a project is a traversal project, expand it into its resolved ProjectReference items and evaluate each recursively (so nested traversal projects work). - CLI arg parsing: recognize any '*proj' extension (not just .csproj/.vbproj/.fsproj) as a positional project in MSBuildUtility.GetPositionalArguments, matching ValidateProjectOrSolutionPath. Without this, 'dotnet test dirs.proj' leaked 'dirs.proj' to the test host as an invalid argument (MTP exit code 5). - Targets: the _MTPBuild target now forwards to @(ProjectReference) when IsTraversal is true, so the referenced test projects actually build. Adds a TraversalTestProjects test asset and RunTraversalProject_ShouldRunReferencedTestProjects test.
|
Azure Pipelines: Successfully started running 1 pipeline(s). 2 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
…ata for traversal - De-duplicate referenced projects across the entire traversal graph (not just within a single traversal file) by threading a visited-set through the recursion. This prevents a project referenced by multiple traversal projects (a diamond) from being tested twice and guards against reference cycles. - Honor per-reference Configuration/Platform metadata on ProjectReference items, falling back to the values inherited from the traversal project. - Add a nested/diamond test asset (TraversalTestProjectsNested) and RunNestedTraversalProjectWithDiamond_ShouldRunSharedProjectOnce. The test apps drop a unique marker file per launch so the test deterministically asserts the shared project runs exactly once and the leaf-only project (reachable solely via nested traversal) also runs once.
Member
Author
|
@baronfel given there is no ETA or news for when transversal APIs will be available, I went ahead with doing some "hacks" as a simplified version which should give us a first support for |
|
Azure Pipelines: Successfully started running 1 pipeline(s). 2 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
There was a problem hiding this comment.
Pull request overview
Adds draft traversal-project (Microsoft.Build.Traversal / dirs.proj) support to dotnet test when using Microsoft.Testing.Platform by expanding traversal containers into their referenced projects for evaluation and ensuring referenced projects get built.
Changes:
- Teach MTP project evaluation to detect traversal projects and recursively expand their
ProjectReferencegraph (with de-dup/cycle-guard). - Update argument parsing to treat any
*projfile as a positional project so it isn’t forwarded to the test host. - Add MTP traversal test assets + tests, and update
_MTPBuildto forward to@(ProjectReference)for traversal projects.
Show a summary per file
| File | Description |
|---|---|
| src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs | Detects traversal projects and recursively evaluates referenced projects (incl. de-dup). |
| src/Cli/dotnet/Commands/Test/MTP/MSBuildUtility.cs | Broadens positional project detection to any extension ending in proj. |
| src/Cli/dotnet/Commands/Test/CliConstants.cs | Adds MSBuild property/item names used for traversal support. |
| src/Layout/redist/MSBuildImports/Current/Microsoft.Common.targets/ImportAfter/Microsoft.TestPlatform.ImportAfter.targets | For traversal projects, forwards _MTPBuild to referenced projects. |
| test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs | Adds tests covering traversal execution, nesting, and diamond de-dup. |
| test/TestAssets/TestProjects/TraversalTestProjects/global.json | Configures test assets to use Microsoft.Testing.Platform runner. |
| test/TestAssets/TestProjects/TraversalTestProjects/dirs.proj | Simple traversal project referencing two MTP test apps. |
| test/TestAssets/TestProjects/TraversalTestProjects/TestProject/TestProject.csproj | MTP “test app” project used by traversal asset. |
| test/TestAssets/TestProjects/TraversalTestProjects/TestProject/Program.cs | Minimal dummy MTP adapter app for traversal tests. |
| test/TestAssets/TestProjects/TraversalTestProjects/OtherTestProject/OtherTestProject.csproj | Second MTP “test app” project used by traversal asset. |
| test/TestAssets/TestProjects/TraversalTestProjects/OtherTestProject/Program.cs | Minimal dummy MTP adapter app for traversal tests. |
| test/TestAssets/TestProjects/TraversalTestProjectsNested/global.json | Configures nested traversal assets to use Microsoft.Testing.Platform runner. |
| test/TestAssets/TestProjects/TraversalTestProjectsNested/dirs.proj | Top-level traversal with nested traversal and a diamond reference. |
| test/TestAssets/TestProjects/TraversalTestProjectsNested/sub/dirs.proj | Nested traversal referencing shared + leaf MTP projects. |
| test/TestAssets/TestProjects/TraversalTestProjectsNested/SharedTestProject/SharedTestProject.csproj | Shared MTP “test app” used to validate diamond de-dup. |
| test/TestAssets/TestProjects/TraversalTestProjectsNested/SharedTestProject/Program.cs | Drops marker files to deterministically count runs for de-dup validation. |
| test/TestAssets/TestProjects/TraversalTestProjectsNested/LeafTestProject/LeafTestProject.csproj | Leaf-only MTP “test app” reachable only through nested traversal. |
| test/TestAssets/TestProjects/TraversalTestProjectsNested/LeafTestProject/Program.cs | Drops marker files to deterministically count runs for recursion validation. |
Copilot's findings
- Files reviewed: 18/18 changed files
- Comments generated: 3
…targets metadata forwarding Addresses three Copilot review comments on #55297: - Resolve ProjectReference 'FullPath' relative to the traversal project directory via Path.GetFullPath(fullPath, projectDirectory) instead of the process working directory. - Include Configuration/Platform in the traversal de-duplication key so the same project referenced with different Configuration/Platform is tested for each distinct combination, while true diamonds (same combination) are still de-duplicated. Introduces GetTraversalVisitKey and keys the traversal project's own visited entry the same way. - _MTPBuild now forwards per-reference Configuration/Platform metadata as global properties, consistent with the evaluation logic. Property assignments are precomputed in an ItemGroup so empty metadata never emits 'Configuration=' (which would clear the inherited global property); empty segments in Properties are ignored by MSBuild.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Draft / proof-of-concept that unblocks traversal project (
dirs.proj) support fordotnet testwith Microsoft.Testing.Platform. Fixes the scenario in #51316.The approach treats a
Microsoft.Build.Traversalproject as a container that forwards to itsProjectReferenceitems — the same mental model as a solution.Root cause
Two independent problems both had to be fixed (a third surfaced while testing):
_MTPBuildtarget (Microsoft.TestPlatform.ImportAfter.targets) only builds$(MSBuildProjectFullPath)whenIsTestingPlatformApplication == true. A traversal project is not an MTP app, so nothing (including its referenced test projects) was built..projwas not a recognized positional project extension, sodotnet test dirs.projleakeddirs.projto the test host as an invalid argument (MTP exit code5).Changes
SolutionAndProjectUtility.csIsTraversalproperty. When a project is a traversal project, expand it into its resolvedProjectReferenceitems and evaluate each recursively (nested traversal). De-duplicates across the whole traversal graph (diamond references / cycle guard) via a threaded visited-set, and honors per-referenceConfiguration/Platformmetadata (falling back to inherited values).MSBuildUtility.cs*projextension as a positional project (mirrorsValidateProjectOrSolutionPath), so the traversal path isn't forwarded to the test host as an argument.CliConstants.csIsTraversal/ProjectReferencenames.Microsoft.TestPlatform.ImportAfter.targets_MTPBuildnow forwards_MTPBuildto@(ProjectReference)whenIsTraversal == true, so the referenced test projects actually build.TraversalTestProjects/+ testdirs.proj+ two MTP apps) andRunTraversalProject_ShouldRunReferencedTestProjects.TraversalTestProjectsNested/+ testRunNestedTraversalProjectWithDiamond_ShouldRunSharedProjectOnce. Test apps drop a unique marker file per launch so the test deterministically asserts the shared (diamond) project runs exactly once and the leaf-only project (reachable solely via nested traversal) also runs — proving recursion + de-dup.Validation
Notes / open questions for reviewers
ProjectReferenceitems from evaluation are sufficient, and MSBuild already expands globs/conditions during evaluation. A cleaner long-term design would want a public traversal API to get the effective project set (analogous toSolutionFile.ProjectsInOrder) rather than relying on rawProjectReferenceitems — similar in spirit to the existingProjectShouldBuildUnsafeAccessorworkaround used for solutions (see MSBuild should publish a library that helps tools interact with Solution files and other container-ish project types msbuild#12711).Configuration/Platform; the P2PSet*/AdditionalPropertiesforms are not yet parsed (theSet*form uses aName=Valuestring that would need parsing)._MTPBuildforwarding is intentionally minimal for this draft (no explicitBuildInParallel/property forwarding). The cross-targeting_MTPBuildvariant is left unchanged since traversal projects are not cross-targeting.Closes #51316 (once finalized).