Expose import tree as MSBuildImportedProject items#13681
Expose import tree as MSBuildImportedProject items#13681drewnoakes wants to merge 5 commits intodotnet:mainfrom
Conversation
When the MSBuild property `MSBuildProvideImportedProjects` is set to `true`, the engine synthesizes `MSBuildImportedProject` items from the import closure during ProjectInstance construction. Each item's identity is the full path of the imported project file, with metadata: - `ImportingProjectPath` — the file that contains the `<Import>` element - `Sdk` — the SDK name if this was an SDK-resolved import ```xml <PropertyGroup> <MSBuildProvideImportedProjects>true</MSBuildProvideImportedProjects> </PropertyGroup> <Target Name="ShowImports"> <Message Text="%(MSBuildImportedProject.Identity) imported by %(MSBuildImportedProject.ImportingProjectPath)" /> </Target> ``` Items are regular MSBuild items, so they naturally serialize to out-of-proc worker nodes and are available to any target or task. No new API surface is required. Projects that don't set the property pay zero cost. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
80ba8d1 to
90ef9fe
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in mechanism (MSBuildProvideImportedProjects=true) to expose the evaluated import closure as regular MSBuild items (MSBuildImportedProject) on ProjectInstance, enabling targets/tasks to query the import graph without introducing new public API.
Changes:
- Introduces a new internal constant for the opt-in property name (
MSBuildProvideImportedProjects). - Synthesizes
MSBuildImportedProjectitems from the evaluated import closure duringProjectInstanceconstruction, includingImportingProjectPathandSdkmetadata. - Adds unit tests validating item creation behavior, metadata, and target visibility.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/Framework/Constants.cs | Adds an internal constant for the opt-in property name. |
| src/Build/Instance/ProjectInstance.cs | Creates MSBuildImportedProject items from the import closure when opted in. |
| src/Build.UnitTests/Instance/ProjectInstance_ImportedProjectItems_Tests.cs | New tests validating opt-in behavior and metadata for standard and SDK imports. |
Design-Level Observations
Note 🔒 Integrity filter blocked 1 itemThe following item were blocked because they don't meet the GitHub integrity level.
To allow these resources, lower tools:
github:
min-integrity: approved # merged | approved | unapproved | none
|
There was a problem hiding this comment.
| # | Dimension | Verdict |
|---|---|---|
| 3 | Performance & Allocation Awareness | 🟡 1 MODERATE |
| 18 | Documentation Accuracy | 🟡 1 NIT |
| 22 | Correctness & Edge Cases | 🟡 2 (1 MAJOR, 1 MODERATE) |
✅ 21/24 dimensions clean.
- Correctness — unescaped path passed to
includeEscapedparameter; paths with%chars will be corrupted - Correctness — potential NRE if
SdkResult.SdkReferenceis null - Performance — per-iteration array allocation in import closure loop
- Documentation — constant XML doc says "during evaluation" but occurs during
ProjectInstancecreation
Note
🔒 Integrity filter blocked 1 item
The following item were blocked because they don't meet the GitHub integrity level.
- #13681
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneGenerated by Expert Code Review (on open) for issue #13681 · ● 26.1M
90ef9fe to
6c88efa
Compare
- Use EscapedFullPath for include and ImportingProjectPath metadata - Use EscapingUtilities.Escape(FullPath) for definingFileEscaped - Add null-conditional on SdkReference (SdkResult?.SdkReference?.Name) - Reuse metadata list with Clear() instead of allocating per iteration - Early-continue for root project (clarity) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix doc comment: 'during evaluation' -> 'during ProjectInstance creation' - Add test verifying MSBuildProvideImportedProjects works as a global property Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Document MSBuildProvideImportedProjects property and MSBuildImportedProject items in Built-in-Properties.md - Add MSBuildProvideImportedProjects property to Microsoft.Build.CommonTypes.xsd for tooling completion and documentation - Add MSBuildImportedProject item type with ImportingProjectPath and Sdk metadata to Microsoft.Build.CommonTypes.xsd Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6c88efa to
e5985a5
Compare
|
|
||
| _importPathsIncludingDuplicates = importPathsIncludingDuplicates; | ||
| ImportPathsIncludingDuplicates = importPathsIncludingDuplicates.AsReadOnly(); | ||
|
|
There was a problem hiding this comment.
I would prefer to make this a separate helper method instead, if we would keep this code here.
| metadata ??= []; | ||
| metadata.Clear(); | ||
|
|
||
| metadata.Add(new("ImportingProjectPath", import.ImportingElement.ContainingProject.EscapedFullPath)); |
There was a problem hiding this comment.
Let's make the constants for item and metadata names as well.
There was a problem hiding this comment.
I'm not convinced this is the right place for the code. From the conversation with @rainersigwald, my understanding was that we'd place this in the evaluation stage: at the start of the items pass, after the property evaluation pass. This change runs after evaluation, during ProjectInstance construction, which means the synthesized items only appear on ProjectInstance, not on Project. I am not entirely sure how important this distinction is for your use case, but I can imagine there being cases (edge or otherwise) where it could make a difference.
Replaces #13680
When the MSBuild property
MSBuildProvideImportedProjectsis set totrue, the engine synthesizesMSBuildImportedProjectitems from the import closure during ProjectInstance construction.Each item's identity is the full path of the imported project file, with metadata:
ImportingProjectPath— the file that contains the<Import>elementSdk— the SDK name if this was an SDK-resolved importItems are regular MSBuild items, so they naturally serialize to out-of-proc worker nodes and are available to any target or task. No new API surface is required. Projects that don't set the property pay zero cost.