Skip to content

Conversation

@baronfel
Copy link
Member

@baronfel baronfel commented Aug 22, 2025

Fixes #50435

The PackTool.targets were modifying critical properties of the tool package project that impacted the way the tool would be published, not just packed.

To fix this, we needed to make sure pathways that are called during 'normal publishing' and 'packaging' could distinguish between the two. This meant

  • making sure that RID-defaulting (UseCurrentRuntimeIdentifier) didn't happen for packaging, only for publishing
  • making sure that some RID specific validation doesn't fire for packaging
  • and in the pack tool targets themselves, making sure that we only override the properties that influence RID-package selection (Publish*, etc) when we're both actively packaging and we know the package is actually not-RID-specific

Almost all of this is super gross, and I believe that the more correct way to structure all of this would be to push more of this overriding into Targets that set Properties less-conditionally and more clearly, but that pathway led to a lot of follow-on changes that were even harder to reason about, and I want to make sure we can get this in for RC2 so folks aren't blocked.

Copilot AI review requested due to automatic review settings August 22, 2025 22:21
@baronfel baronfel requested a review from a team as a code owner August 22, 2025 22:21
@baronfel baronfel changed the base branch from main to release/10.0.1xx August 22, 2025 22:21
@dotnet dotnet deleted a comment from github-actions bot Aug 22, 2025
Copy link
Contributor

Copilot AI left a 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 fixes an issue where PackTool.targets were incorrectly modifying properties that affected tool publishing behavior, not just packaging. The fix restructures the targets to ensure tool-specific modifications only activate during pack operations.

Key changes:

  • Moves tool-specific property modifications from global scope to pack-specific targets
  • Adds _IsPacking property to PackCommand and related test framework classes
  • Updates file-based program support to include dotnet pack functionality

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets Restructures targets to move property modifications into pack-specific scope
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.RuntimeIdentifierInference.targets Removes PackAsTool condition from runtime identifier inference
src/Cli/dotnet/Commands/Pack/PackCommand.cs Adds file-based program support and refactors command creation
test/Microsoft.NET.TestFramework/Commands/*.cs Adds _IsPacking and _IsPublishing properties to test commands
test/dotnet.Tests/CommandTests/Run/RunFileTests.cs Adds comprehensive tests for pack functionality with file-based programs
test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAToolProject.cs Adds regression test for normal publish behavior
eng/Version.Details.xml Updates Microsoft.Testing.Platform and MSTest package versions

Comment on lines +95 to +101
<_PackToolPublishDependency Condition=" $(_ToolPackageShouldIncludeImplementation) and '$(GeneratePackageOnBuild)' != 'true' and $(IsPublishable) == 'true' ">Publish</_PackToolPublishDependency>
<!-- BUT builds that GeneratePackageOnBuild can't directly rely on Publish since Publish would trigger Build, causing an infinite loop. -->
<!-- To get around this, we try a bit of a workaround: since we can't set NoBuild=true and call Publish that way, we instead trigger all of the
dependencies of the no-build Publish Target, _PublishNoBuildAlternative -->
<_PackToolPublishDependency Condition=" '$(_ToolPackageShouldIncludeImplementation)' != '' and '$(GeneratePackageOnBuild)' == 'true' and $(IsPublishable) == 'true' ">$(_PublishNoBuildAlternativeDependsOn)</_PackToolPublishDependency>
<_PackToolPublishDependency Condition=" $(_ToolPackageShouldIncludeImplementation) and '$(GeneratePackageOnBuild)' == 'true' and $(IsPublishable) == 'true' ">$(_PublishNoBuildAlternativeDependsOn)</_PackToolPublishDependency>
<!-- No implementation required? Then don't call either target. -->
<_PackToolPublishDependency Condition="!$(_ToolPackageShouldIncludeImplementation)"></_PackToolPublishDependency>
Copy link
Member Author

@baronfel baronfel Aug 29, 2025

Choose a reason for hiding this comment

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

these three sets were actually a big part of the problem - they were incorrectly checking _ToolPackageShouldIncludeImplementation in a way that caused even top-level non-implementation packages to call Publish - which then causes the negative impacts observed by properties like PublishAot, etc. The final clause here explicitly makes sure that we end up calling no Publish-related Target if we don't need a tool implementation.

<PreferNativeArm64 Condition="'$(PreferNativeArm64)'==''">false</PreferNativeArm64>
<SignAssembly Condition="'$(SignAssembly)'==''">false</SignAssembly>
<DelaySign Condition="'$(DelaySign)'==''">false</DelaySign>
<!-- TODO: should we set _IsPacking=true on the NuGet Pack targets when they hook up the 'generate package on build' stuff -->
Copy link
Member Author

Choose a reason for hiding this comment

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

@dsplaisted / @zivkan I think this is potentially a thing that we should dig into.

Here's the relevant part of the Pack Targets:

  <Target Name="_PackAsBuildAfterTarget"
          AfterTargets="Build"
          Condition="'$(GeneratePackageOnBuild)' == 'true' AND '$(IsInnerBuild)' != 'true'"
          DependsOnTargets="Pack">
  </Target>

  <Target Name="_CleanPackageFiles"
          DependsOnTargets="_GetOutputItemsFromPack"
          AfterTargets="Clean"
          Condition="'$(GeneratePackageOnBuild)' == 'true' AND '$(IsInnerBuild)' != 'true'">
    <ItemGroup>
      <_PackageFilesToDelete Include="@(_OutputPackItems)"/>
    </ItemGroup>
    <Delete Files="@(_PackageFilesToDelete)"/>
  </Target>

It sucks to keep propagating _IsPacking, but I think we might need to. Ideally sometime after the build runs but before the 'hook' NuGet _PackAsBuildAfterTarget ties into the Pack DependsOnTargets?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think we can successfully set _IsPacking in these targets, as there are evaluation-time properties in Microsoft.NET.PackTool.targets that depend on the _IsPacking value.

@baronfel baronfel marked this pull request as ready for review August 29, 2025 03:11
@baronfel baronfel force-pushed the make-packtool-targets-light-up-only-on-pack branch from 8695a37 to 630278d Compare August 29, 2025 03:11
@baronfel baronfel force-pushed the make-packtool-targets-light-up-only-on-pack branch from 630278d to ad63e78 Compare September 3, 2025 22:49
@baronfel
Copy link
Member Author

baronfel commented Sep 5, 2025

per @dsplaisted the three remaining test failures are actually related to PrunePackageReferences and the way we construct some SDK layout stuff, not this PR. I'd be ok with merging this as a result.

@dsplaisted
Copy link
Member

The test errors should be fixed by #50661.

@baronfel
Copy link
Member Author

baronfel commented Sep 6, 2025

@dsplaisted it's finally ready!

@baronfel baronfel enabled auto-merge (squash) September 6, 2025 20:13
@baronfel baronfel changed the title Make packtool targets light up only on pack Ensure that tool packages can still publish normally with dotnet publish. Sep 9, 2025
Copy link
Member

@dsplaisted dsplaisted left a comment

Choose a reason for hiding this comment

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

Looks good, and not as complicated as I had feared.

I think it would be good to get rid of all the HELIX_WORKITEM_UPLOAD_ROOT ibnlog-gathering code from the tests.

Comment on lines +80 to +85
<PublishSelfContained Condition="!$(_IsRidSpecific) and !$(_IsImplicitRestore) and $(_IsPacking)">false</PublishSelfContained>
<SelfContained Condition="!$(_IsRidSpecific) and !$(_IsImplicitRestore) and $(_IsPacking)">false</SelfContained>
<PublishTrimmed Condition="!$(_IsRidSpecific) and !$(_IsImplicitRestore) and $(_IsPacking)">false</PublishTrimmed>
<PublishReadyToRun Condition="!$(_IsRidSpecific) and !$(_IsImplicitRestore) and $(_IsPacking)">false</PublishReadyToRun>
<PublishSingleFile Condition="!$(_IsRidSpecific) and !$(_IsImplicitRestore) and $(_IsPacking)">false</PublishSingleFile>
<PublishAot Condition="!$(_IsRidSpecific) and !$(_IsImplicitRestore) and $(_IsPacking)">false</PublishAot>
Copy link
Member

Choose a reason for hiding this comment

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

The same condition is repeated here for a bunch of properties. Would it make sense to put these in a separate PropertyGroup with the condition just once on the PropertyGroup?

And if we do that it might make sense to avoid creating our own _IsImplicitRestore property or forcing _IsPacking to have a value if it's not set.


<!-- inner builds and non-RID-specific outer builds need publish content-->
<_PackToolPublishDependency Condition=" '$(_ToolPackageShouldIncludeImplementation)' != '' and '$(GeneratePackageOnBuild)' != 'true' and $(IsPublishable) == 'true' ">Publish</_PackToolPublishDependency>
<_PackToolPublishDependency Condition=" $(_ToolPackageShouldIncludeImplementation) and '$(GeneratePackageOnBuild)' != 'true' and $(IsPublishable) == 'true' ">Publish</_PackToolPublishDependency>
Copy link
Member

Choose a reason for hiding this comment

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

I can't comment the exact line since you didn't change it here, but would it make sense to change this:

    <_ToolPackageShouldIncludeImplementation Condition=" '$(_ToolPackageShouldIncludeImplementation)' == '' And '$(PackAsTool)' == 'true' And
                                                  ('$(_UserSpecifiedToolPackageRids)' == ''
                                                     or '$(RuntimeIdentifier)' != '')">true</_ToolPackageShouldIncludeImplementation>

to this?

    <_ToolPackageShouldIncludeImplementation Condition=" '$(_ToolPackageShouldIncludeImplementation)' == '' And '$(PackAsTool)' == 'true' And
                                                  ('$(_HasRIDSpecificTools)' != 'true'
                                                     or '$(RuntimeIdentifier)' != '')">true</_ToolPackageShouldIncludeImplementation>

Basically use the derived _HasRIDSpecificTools property. I think the result would be the same and this would be a bit easier to understand.

<PreferNativeArm64 Condition="'$(PreferNativeArm64)'==''">false</PreferNativeArm64>
<SignAssembly Condition="'$(SignAssembly)'==''">false</SignAssembly>
<DelaySign Condition="'$(DelaySign)'==''">false</DelaySign>
<!-- TODO: should we set _IsPacking=true on the NuGet Pack targets when they hook up the 'generate package on build' stuff -->
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we can successfully set _IsPacking in these targets, as there are evaluation-time properties in Microsoft.NET.PackTool.targets that depend on the _IsPacking value.

Comment on lines +32 to +34
var binlogDestPath = Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT") is { } ciOutputRoot && Environment.GetEnvironmentVariable("HELIX_WORKITEM_ID") is { } helixGuid ?
Path.Combine(ciOutputRoot, "binlog", helixGuid, $"{nameof(It_cleans_the_project_successfully_with_static_graph_and_isolation)}.binlog") :
"./msbuild.binlog";
Copy link
Member

Choose a reason for hiding this comment

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

I think this can be removed in favor of the logic that's now built in to TestCommand.

@baronfel baronfel merged commit 5b0a505 into dotnet:release/10.0.1xx Sep 16, 2025
27 checks passed
@baronfel baronfel deleted the make-packtool-targets-light-up-only-on-pack branch September 16, 2025 23:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AOT publish doesn't work if PackAsTool is set (a regression)

3 participants