-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Multi-RID tool packages usability tweaks #49288
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
Conversation
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.
Pull Request Overview
This PR adjusts the packaging mechanism for RID-specific tool packages by migrating from an item‐based to a property‐based usage mode, streamlining package creation for both parent and RID‐specific packages.
- Migrates from using an Item-based RID specification with a Version attribute to a property-based configuration without a version.
- Updates various build targets to correctly trigger and define inner and outer builds, including adjustments to packaging tasks and property conditions.
- Removes legacy code (such as the version handling in tool package resolution and associated unit tests) to simplify the overall tool package design.
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets | Updates PackTool import condition to respect PackAsTool usage. |
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.Common.targets | Adjusts condition to reference the new property ToolPackageRuntimeIdentifiers. |
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets | Refactors packaging targets to differentiate inner and outer builds and update package paths. |
src/Tasks/Microsoft.NET.Build.Tasks/GenerateToolsSettingsFile.cs | Removes version attribute assignment in RID package nodes. |
src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs | Updates package version sourcing for installation and asset file creation. |
src/Cli/dotnet/ToolPackage/ToolConfigurationDeserializer.cs | Eliminates version information when creating PackageIdentity from RID-specific data. |
src/Cli/dotnet/ToolPackage/ToolConfigurationDeserialization/DotNetCliToolRuntimeIdentifierPackage.cs | Removes the Version attribute in favor of property-based configuration. |
(Other files) | Removal of legacy test and resolution files in-line with the new design. |
Comments suppressed due to low confidence (3)
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.Common.targets:57
- Verify that the new property 'ToolPackageRuntimeIdentifiers' is correctly defined and consistently propagated across the targets to avoid mismatches with legacy item names.
<_ToolPackageType Condition="'$(RuntimeIdentifier)' != '' And '$(ToolPackageRuntimeIdentifiers)' != ''">DotnetToolRidPackage</_ToolPackageType>
src/Cli/dotnet/ToolPackage/ToolConfigurationDeserializer.cs:70
- Ensure that all consumers of PackageIdentity are updated to handle a null version, as the version is now inherited from the parent package rather than being stored per RID-specific package.
var ridSpecificPackages = dotNetCliTool.RuntimeIdentifierPackages?.ToDictionary(p => p.RuntimeIdentifier, p => new PackageIdentity(p.Id, null))
src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs:291
- Confirm that the 'packageVersion' variable is correctly assigned before this check, as replacing resolvedPackage.Version could lead to unintended behavior if packageVersion is not properly derived.
if (!IsPackageInstalled(new PackageId(resolvedPackage.Id), packageVersion, packageDownloadDir.Value))
@@ -12,6 +12,5 @@ Copyright (c) .NET Foundation. All rights reserved. | |||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
|
|||
<PropertyGroup> | |||
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackTool</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.
Since I added a PackAsTool
condition to the PackTool.targets imports in Sdk.Common.targets, we can't unconditionally add this anymore. We don't know if PackAsTool
has been set at this point (because we're pre-project-file-contents in the MSBuild evaluation ordering), so this should get pushed to the PackTool.targets instead. It doesn't effect ordering in anyway, so this is safe.
<PublishSelfContained Condition="'$(RuntimeIdentifier)' == ''">false</PublishSelfContained> | ||
<PublishTrimmed Condition="'$(RuntimeIdentifier)' == ''">false</PublishTrimmed> | ||
<PublishReadyToRun Condition="'$(RuntimeIdentifier)' == ''">false</PublishReadyToRun> | ||
<PublishAot Condition="'$(RuntimeIdentifier)' == ''">false</PublishAot> |
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.
Setting these means that if Build
is called accidentally for the RID-less build then things can still mostly work.
<Target Name="PackAsToolSwitchToNoBuild" | ||
BeforeTargets="_IntermediatePack" | ||
Condition=" '$(PackAsTool)' == 'true' And | ||
'@(ToolPackageRuntimeIdentifier)' != '' And | ||
'$(RuntimeIdentifier)' == ''"> | ||
|
||
<!-- If we are building the primary package for a tool with RID-specific packages, we don't include any of the build output in the package, so we don't need to run Build. | ||
We might not be able to build without a RuntimeIdentifier if PublishAOT or SelfContained is set to true, so we skip the build so it doesn't fail. | ||
|
||
We use a task to remove the Build target from GenerateNuspecDependsOn. This is effectively what happens if NoBuild is set, but we can't use the same logic because | ||
we need to look at items (ToolPackageRuntimeIdentifier) to determine if we are building the primary package for a tool with RID-specific packages. So we have to fix | ||
up the dependency list afterwards. | ||
|
||
We also can't use MSBuild property functions for string replacement to remove Build from the list, because MSBuild will escape the semicolons as %3B, and there | ||
doesn't seem to be a way of avoiding that without using a task. | ||
--> | ||
<RemoveTargetFromList TargetList="$(GenerateNuspecDependsOn)" | ||
TargetToRemove="Build"> | ||
<Output TaskParameter="UpdatedTargetList" PropertyName="GenerateNuspecDependsOn" /> | ||
</RemoveTargetFromList> | ||
|
||
</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.
This isn't required anymore because we're preventing the errors that calling Build caused in the Property-sets above.
<Target Name="PackTool" DependsOnTargets="SetPackToolProperties;GenerateToolsSettingsFileFromBuildProperty;PackToPublishDependencyIndirection;_PackToolValidation;PackToolImplementation" Condition=" '$(PackAsTool)' == 'true' "> | ||
<ItemGroup> | ||
<_GeneratedFiles Include="$(_ToolsSettingsFilePath)"/> | ||
<_PublishFilesRaw Condition="'$(RuntimeIdentifier)' != ''" Include="$(PublishDir)/**/*" /> |
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.
We can't rely on ResolvedFilesToPublish
- it's not comprehensive enough. When working with container publish incrementality I found that there are tons of folks that just copy things to the PublishDir and expect that to work. So we have to glob across the publish dir and use that as the source of truth for the package content. The good news is that it makes deriving the Relative and Package paths trivial, so we can removee the entire Task invocation that used to do that.
<ItemGroup> | ||
<TfmSpecificPackageFile Include="@(_GeneratedFiles)"> | ||
<PackagePath>tools/$(_ToolPackShortTargetFrameworkName)/any/%(_GeneratedFiles.RecursiveDir)%(_GeneratedFiles.Filename)%(_GeneratedFiles.Extension)</PackagePath> | ||
<PackagePath>tools/$(_ToolPackShortTargetFrameworkName)/$(_ToolRidPath)/%(_GeneratedFiles.RecursiveDir)%(_GeneratedFiles.Filename)%(_GeneratedFiles.Extension)</PackagePath> |
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.
Request from NuGet here that we maintain the RID in this path if we're doing RID-specific things
@@ -1431,7 +1431,7 @@ Copyright (c) .NET Foundation. All rights reserved. | |||
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.ObsoleteReferences.targets" /> | |||
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.Publish.targets" /> | |||
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.PackStubs.targets" Condition="('$(Language)' == 'C++' and '$(_EnablePackageReferencesInVCProjects)' != 'true')"/> | |||
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.PackTool.targets" /> | |||
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.PackTool.targets" Condition="'$(PackAsTool)' == 'true'" /> |
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.
Adding this conditional means that we can modify things to our heart's content inside the PackTool.targets and not worry about corrupting non-Tool projects' state.
All of the failing tests are around packaging the shims. After my changes the shims are getting the NuGet.Build.Tasks.Pack.targets: <Target Name="_GetTfmSpecificContentForPackage"
DependsOnTargets="$(TargetsForTfmSpecificContentInPackage)"
Returns="@(TfmSpecificPackageFileWithRecursiveDir)">
<!-- The below workaround needs to be done due to msbuild bug https://github.com/Microsoft/msbuild/issues/3121 -->
<ItemGroup>
<TfmSpecificPackageFileWithRecursiveDir Include="@(TfmSpecificPackageFile)">
<NuGetRecursiveDir>%(TfmSpecificPackageFile.RecursiveDir)</NuGetRecursiveDir>
<BuildAction>%(TfmSpecificPackageFile.BuildAction)</BuildAction>
</TfmSpecificPackageFileWithRecursiveDir>
</ItemGroup>
</Target> |
I think I've got it - since NuGet forces the use of RecursiveDir if it's present, we just lean into that and don't try to be quite as precise with our PackagePath setting. I've pushed up a commit with comments and adjustments for that. |
918efb0
to
a17a199
Compare
Alright - this is super close so is probably ok for review now. The only tests failing don't fail locally, and cover a pretty specific scenario: It_uses_customized_PackagedShimOutputRootDirectory. |
@@ -157,7 +157,7 @@ public void It_uses_customized_PackagedShimOutputRootDirectory(bool multiTarget, | |||
|
|||
var packCommand = new PackCommand(Log, helloWorldAsset.TestRoot); | |||
|
|||
packCommand.Execute().Should().Pass(); | |||
packCommand.Execute("-bl:{}").Should().Pass(); |
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.
Is this trying to create a binlog during test execution? As mentioned in our triage, even if it works, you cannot get at the file directly in Helix. We need a proper way to do this.
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.
You can hard code the binlong path in the -bl command, and then dump the binary content into the test output, copy paste it into a file to read it. I like the idea of properly dumping the log from helix, but I don't want to block this PR to do so
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 I've figured it out, but now Helix is busted. In either case I'll be removing this before we merge this PR.
Ok, I have added a test to cover the new multi-packaging feature, and have verified via binlogs locally that the shim output path stuff works. I want helix to try one more time to give me a binlog so I can see what's going on in the CI system, but then I want to skip those tests so we can get the good syntax in for p6. |
<_InnerToolsPublishAot>false</_InnerToolsPublishAot> | ||
<_InnerToolsPublishAot Condition="'$(RuntimeIdentifier)' == '' and '$(PublishAot)' == 'true'">true</_InnerToolsPublishAot> |
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.
We need to know if the inner tools are publishing AOT to know if we're allowed to dispatch to the per-RID inner packs below.
<_PackToolPublishDependency Condition=" '$(_ToolPackageShouldIncludeImplementation)' != '' and '$(GeneratePackageOnBuild)' == 'true' and $(IsPublishable) == 'true' ">$(_PublishNoBuildAlternativeDependsOn)</_PackToolPublishDependency> | ||
|
||
<!-- Trigger RID-specific inner builds if RID-specific mode is enabled--> | ||
<GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);SetDotnetToolPackageType;_CreateRIDSpecificToolPackages</GenerateNuspecDependsOn> |
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.
note that these targets must be called from two different kinds of GenerateNuspec:
- multi-tfm GenerateNuspec (from the crosstargeting targets)
- single-tfm GenerateNuSpec (from the 'normal', single-TFM targets)
@@ -13,6 +13,7 @@ Copyright (c) .NET Foundation. All rights reserved. | |||
|
|||
<Import Project="Microsoft.NET.Sdk.Common.targets"/> | |||
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.Sdk.SourceLink.targets" Condition="'$(SuppressImplicitGitSourceLink)' != 'true'"/> | |||
<Import Project="$(MSBuildThisFileDirectory)Microsoft.NET.PackTool.targets" Condition="'$(PackAsTool)' == 'true'" /> |
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.
Big change here - we need to import the tool targets at the multi-tfm level so that we can ensure that the correct package types get set.
2c15ee9
to
7b701ca
Compare
Ok we're good to go now! The test failures are watch and container timeouts, everything else is good. |
035ba44
to
bbe108a
Compare
… should come from the parent package's verison only
…tead for ease of use
…nges inside them to prevent unintentional modifications
bbe108a
to
75b4ee6
Compare
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets
Show resolved
Hide resolved
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets
Show resolved
Hide resolved
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets
Show resolved
Hide resolved
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets
Show resolved
Hide resolved
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets
Show resolved
Hide resolved
test/Microsoft.NET.ToolPack.Tests/GivenThatWeWantToPackAToolProjectWithPackagedShim.cs
Outdated
Show resolved
Hide resolved
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.
Another PR I wish I had more time to look over but I did what I could with the time we have :) I think using properties vs items is a great improvement and overall the change looks good. Kudos for the clever engineering here...
I've addressed @nagilson's feedback (thanks!) and this should be good to merge now. |
mmmmm yes |
…t actually exists
The only remaining failing test is the completions known issue. Let's merge! |
Known completion test issue. |
This PR:
<ToolPackageRuntimeIdentifier Include="linux-x64" Version="A.B.C" />)
to a property-based usage mode (<ToolPackageRuntimeIdentifier>linux-x64</ToolPackageRuntimeIdentifier>
).Version
from the RID-specific tool package configuration entries (the versions must always be aligned with the 'parent' RID-less package)dotnet pack
triggers the packaging of the 'inner' per-RID packages as well