-
Notifications
You must be signed in to change notification settings - Fork 830
Fix early/unconditional execution of PackageFSharpDesignTimeTools target #18929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
✅ No release notes required |
Co-authored-by: T-Gro <[email protected]>
…tion guide Co-authored-by: T-Gro <[email protected]>
Added comprehensive end-to-end tests in commit 9388b94. Created |
…to-end tests Co-authored-by: T-Gro <[email protected]>
Co-authored-by: T-Gro <[email protected]>
tests/EndToEndBuildTests/DesignTimeProviderPackaging/TestDesignTimeProviderPackaging.cmd
Show resolved
Hide resolved
…s job Co-authored-by: T-Gro <[email protected]>
<_FSharpDesignTimeProviderPackage Include="@(PackageReference)" Condition="'%(PackageReference.IsFSharpDesignTimeProvider)' == 'true'" /> | ||
</ItemGroup> | ||
<PropertyGroup Condition=" '@(_FSharpDesignTimeProviderProject)' != '' or '@(_FSharpDesignTimeProviderPackage)' != '' "> | ||
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackageFSharpDesignTimeTools</TargetsForTfmSpecificContentInPackage> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if a project has BOTH IsFSharpDesignTimeProvider=true (10 lines above) and also references.
Then its TargetsForTfmSpecificContentInPackage would be duplicate entries.
Avoid this.
This entire target can be IMO skipped if IsFSharpDesignTimeProvider=true, since that one already settles the Targets addition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit 387c51a by adding Condition=" '$(IsFSharpDesignTimeProvider)' != 'true' "
to the _CheckForDesignTimeProviderReferences
target. Now the target only runs when IsFSharpDesignTimeProvider is not already true, preventing duplicate entries in TargetsForTfmSpecificContentInPackage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's too late to set this property inside a target.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even when that target has BeforeTargets="GenerateNuspec;Pack"
?
I think earlier it would be problematic to asses all the ProjectReference
and PackageReference
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where its used if I did not miss a different place:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot :
Heads up:
MSBuild target scheduling is determined at graph construction time.
You must set TargetsForTfmSpecificContentInPackage
via <PropertyGroup>
+ <ItemGroup>
at the file/import level, NOT inside a target.
If you use a target (like _CheckForDesignTimeProviderReferences
) to mutate this property, it’s too late—the graph is already built.
Retrieve reference metadata and gate addition like this (outside any target):
<ItemGroup>
<_FSharpDesignTimeProviderProject Include="@(ProjectReference)" Condition="'%(ProjectReference.IsFSharpDesignTimeProvider)' == 'true'" />
<_FSharpDesignTimeProviderPackage Include="@(PackageReference)" Condition="'%(PackageReference.IsFSharpDesignTimeProvider)' == 'true'" />
</ItemGroup>
<PropertyGroup Condition=" '$(IsFSharpDesignTimeProvider)' == 'true' or '@(_FSharpDesignTimeProviderProject)' != '' or '@(_FSharpDesignTimeProviderPackage)' != '' ">
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackageFSharpDesignTimeTools</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
Never inside a target.
This ensures correct scheduling and fixes early/side-effect execution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand the issue - setting the property inside a target is too late. However, the exact syntax you provided results in MSB4099: "A reference to an item list... is not allowed in this condition" because MSBuild evaluates PropertyGroups before ItemGroups.
Is there a special MSBuild feature or technique that allows referencing items in property conditions during evaluation? Or should I use a different approach like a custom MSBuild task or property function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot :
Current mechanism is CLEARLY wrong and incomplete, it does not check refs at all.
Go back to trying to set TargetsForTfmSpecificContentInPackage based on references collected via a custom target, I want to at least see what it does.
(as in, how msbuild reacts to the source behind a DependsOn
expression getting updated)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added back the target-based reference checking approach in commit c0c6e5a to test MSBuild's behavior. The implementation now has:
- Direct property check at evaluation time (for
IsFSharpDesignTimeProvider='true'
) - Target
_CheckForDesignTimeProviderReferences
that checks ProjectReference/PackageReference and updates the property
Testing shows the target DOES update the property when explicitly called via DependsOnTargets
. The property is visible to downstream targets. However, whether this works correctly with Pack's target scheduling needs validation - the property update happens during execution, not graph construction.
… direct and reference providers exist Co-authored-by: T-Gro <[email protected]>
tests/EndToEndBuildTests/DesignTimeProviderPackaging/TestDesignTimeProviderPackaging.cmd
Show resolved
Hide resolved
Co-authored-by: T-Gro <[email protected]>
…t in target Per T-Gro's feedback, MSBuild target scheduling happens during graph construction, so TargetsForTfmSpecificContentInPackage must be set in PropertyGroup at file/import level, NOT inside a target. Changed from target-based approach to evaluation-time PropertyGroup that only checks the direct IsFSharpDesignTimeProvider property. This ensures the property is set before target graph construction. Note: Checking ProjectReference/PackageReference metadata is not feasible at evaluation time due to MSBuild's evaluation order (PropertyGroups before ItemGroups), so only direct property check is supported. Co-authored-by: T-Gro <[email protected]>
Per T-Gro's request, adding back the target-based approach to check ProjectReference/PackageReference metadata and update TargetsForTfmSpecificContentInPackage. This is experimental to observe how MSBuild reacts when a property (that's part of a DependsOn expression) gets updated during target execution. The implementation now includes: 1. Direct property check at evaluation time (when IsFSharpDesignTimeProvider='true') 2. Target _CheckForDesignTimeProviderReferences that runs before Pack/GenerateNuspec - Collects ProjectReference/PackageReference with IsFSharpDesignTimeProvider='true' - Updates TargetsForTfmSpecificContentInPackage if any found Testing shows the property IS updated and visible to downstream targets when called via DependsOnTargets. Whether this works with Pack's actual target scheduling needs validation since the property update happens during execution phase, not graph construction phase. Co-authored-by: T-Gro <[email protected]>
Fixed the early/unconditional execution of the PackageFSharpDesignTimeTools target that was causing:
PackageFSharpDesignTimeTools
target interacts unpredictably with the rest of the build. #18924: Early inclusion caused premature reference resolution → binding redirect + app.config deletion issues--no-build
#12320: dotnet pack --no-build could trigger unintended build target participation (NETSDK1085 risk)Implementation
Hybrid Dual-Phase Approach (Experimental): The target is now conditionally added to
$(TargetsForTfmSpecificContentInPackage)
using two mechanisms:Status: The implementation includes both approaches to test MSBuild's behavior:
Clean Target Structure:
DependsOnTargets="_GetFrameworkAssemblyReferences"
toAfterTargets="ResolveReferences"
<CallTarget Targets="_GetFrameworkAssemblyReferences" Condition="'@(ReferencePath)' == ''" />
as first thing in target to ensure references are available when neededComprehensive End-to-End Tests with CI Integration and Issue Repro
Added
tests/EndToEndBuildTests/DesignTimeProviderPackaging/
with:EndToEndBuildTests
job inazure-pipelines-PR.yml
and will run automatically in PR buildsTesting Verified
IsFSharpDesignTimeProvider="true"
: Target included at evaluation timepack --no-build
succeeds without NETSDK1085The fix maintains backward compatibility while preventing the early execution issues that caused problems with packaging workflows. The implementation uses a hybrid approach to test both evaluation-time and execution-time property setting mechanisms.
Note: The target-based reference checking is experimental to observe MSBuild's behavior when properties are updated during execution phase versus graph construction phase.
This pull request was created as a result of the following prompt from Copilot chat.
This pull request was created as a result of the following prompt from Copilot chat.
This pull request was created as a result of the following prompt from Copilot chat.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.