Skip to content
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

Use PackageDownload in torn builds #41951

Merged
merged 9 commits into from
Jul 12, 2024
Merged

Use PackageDownload in torn builds #41951

merged 9 commits into from
Jul 12, 2024

Conversation

jjonescz
Copy link
Member

@jjonescz jjonescz commented Jul 3, 2024

Resolves #41791.

<Target Name="_AddMicrosoftNetCompilerToolsetFrameworkPackage" Condition="'$(MSBuildRuntimeType)' == 'Full'" BeforeTargets="CollectPackageReferences">
<PropertyGroup Condition="'$(MSBuildRuntimeType)' == 'Full'">
<!-- Automatically opt users into using the toolset package if they are running an MSBuild other than what this SDK was built against.
This is to reduce 'tearing'/depdendency mismatch, but as always users can override this behavior by disabling the hosted compiler flag. -->
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
This is to reduce 'tearing'/depdendency mismatch, but as always users can override this behavior by disabling the hosted compiler flag. -->
This is to reduce 'tearing'/dependency mismatch, but as always users can override this behavior by disabling the hosted compiler flag. -->


<ItemGroup>
<PackageReference Include="Microsoft.Net.Compilers.Toolset.Framework" ExcludeAssets="All" GeneratePathProperty="true" Condition="'$(DotNetBuildSourceOnly)' != 'true'" />
<Content Include="$(PkgMicrosoft_Net_Compilers_Toolset_Framework)\tasks\net472\**\*" PackagePath="%(RecursiveDir)" />
Copy link
Member

Choose a reason for hiding this comment

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

Two follow up items:

  1. Can you also make a change to roslyn which adds some documentation to this package outlining how it is now consumed in the .NET SDK? Essentially a marker that will alert anyone that is trying to change the code in roslyn to what it means in the .NET SDK?
  2. Can you file an issue in roslyn that tracks changing the bootstrap framework CI leg to more closely follow what the .NET SDK is now doing? Essentially set /p:RoslynTargetsPath=...\net472. That will help ensure our test coverage catches any authoring mistakes we make in roslyn.

Copy link
Member Author

Choose a reason for hiding this comment

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

<NETSdkWarning ResourceName="CannotDirectlyReferenceMicrosoftNetCompilersToolsetFramework"
Condition="'@(PackageReference->AnyHaveMetadataValue('Identity', 'Microsoft.Net.Compilers.Toolset.Framework'))' == 'true'" />
<PropertyGroup Condition="'$(BuildWithNetFrameworkHostedCompiler)' == 'true' and '$(OS)' == 'Windows_NT'">
<RoslynTargetsPath>$(NuGetPackageRoot)\Microsoft.Net.Sdk.Compilers.Toolset\$(NETCoreSdkVersion)</RoslynTargetsPath>
Copy link
Member

Choose a reason for hiding this comment

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

The way this is written means that if a customer both

  1. Sets BuildWitHNetFrameworkHostedCompiler or builds in a torn SDK
  2. Sets RoslynTargetsPath

Then we will simply ignore (2).

Is that the behavior that we want here? To me that seems reasonable but I also worry about confusing users if they set both and we are silently overwriting one of them. Should we issue a diagnostic here if both are set?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds reasonable, I've tried adding this warning, but I don't know how to reliably detect whether RoslynTargetsPath is set by the user or it has the default value set by msbuild.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm ... that is a good point. That would probably need a msbuild analyzer. Let's skip this for now, can revisit if it becomes a real problem.

Copy link
Member

Choose a reason for hiding this comment

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

Is RoslynTargetsPath meant to be set by customers? I see a few hundred times across all of GH. This seems like something that should have been a private variable originally.

This is to reduce 'tearing'/depdendency mismatch, but as always users can override this behavior by disabling the hosted compiler flag. -->
<BuildWithNetFrameworkHostedCompiler Condition="'$(BuildWithNetFrameworkHostedCompiler)' == '' and '$(_IsDisjointMSBuildVersion)' == 'true'">true</BuildWithNetFrameworkHostedCompiler>
</PropertyGroup>
<UsingTask TaskName="Microsoft.CodeAnalysis.BuildTasks.CopyRefAssembly" AssemblyFile="$(RoslynTargetsPath)\Microsoft.Build.Tasks.CodeAnalysis.dll" />
Copy link
Member

Choose a reason for hiding this comment

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

@rainersigwald should we change common.tasks in msbuild to have a comment that says more less "if you change this lest, you also need to change this file in the .NET SDK"?

Copy link
Member Author

Choose a reason for hiding this comment

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

I have added a note here and to msbuild: dotnet/msbuild#10351

@@ -24,17 +24,15 @@ public void It_restores_Microsoft_Net_Compilers_Toolset_Framework_when_requested
var testAsset = _testAssetsManager
Copy link
Member

Choose a reason for hiding this comment

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

Can't comment on it but then we should change the name of this test now to It_downloads...

@@ -53,28 +51,19 @@ public void It_restores_Microsoft_Net_Compilers_Toolset_Framework_when_MSBuild_i
var testAsset = _testAssetsManager
Copy link
Member

Choose a reason for hiding this comment

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

Same comment about name change

<data name="CannotDirectlyReferenceMicrosoftNetCompilersToolsetFramework" xml:space="preserve">
<value>NETSDK1205: The Microsoft.Net.Compilers.Toolset.Framework package should not be set directly. Set the property 'BuildWithNetFrameworkHostedCompiler' to 'true' instead if you need it.</value>
<comment>{StrBegin="NETSDK1205: "}{Locked="Microsoft.Net.Compilers.Toolset.Framework"}{Locked="BuildWithNetFrameworkHostedCompiler"}</comment>
</data>
Copy link
Member Author

Choose a reason for hiding this comment

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

@marcpopMSFT had a comment in a Teams thread about this - instead of removing this warning, should that be changed to warn customers if they reference the new Microsoft.Net.Sdk.Compilers.Toolset package?

We could do that, but nothing happens when customers reference the new package as it has a non-standard layout. So, a warning seems unnecessary to me.

A related question is what happens when a customer references the Microsoft.Net.Compilers.Toolset.Framework package (which we used to warn about). From local testing, it looks like the compiler from the explicit PackageReference takes precedence over the built-in disjoint detection and the PackageDownload.

Copy link
Member

Choose a reason for hiding this comment

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

We can always remove a warning but adding one is a compat break, so I think I lean toward changing it rather than removing it.

Copy link
Member

Choose a reason for hiding this comment

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

If referencing the old package takes precedents over the packagedownload, do we want to keep the original warning in place? I'm less worried now about the sdk package if referencing it doesn't do anything. CC @baronfel as this is one of those situations where a customer could do bad things to themselves but how much do we want to prevent/warn.

@jaredpar
Copy link
Member

jaredpar commented Jul 9, 2024

Are there any tests where there is a full end to end test of the system that includes a build? Basically want to exercise the entire code path include executing the compiler. Looking through the PR I didn't see you modify any, but it's possible that they could've been added by our earlier work in torn sdks.

@jjonescz
Copy link
Member Author

jjonescz commented Jul 9, 2024

Are there any tests where there is a full end to end test of the system that includes a build?

I don't think there are existing end-to-end tests, I can look into adding one, but perhaps as a follow up PR, I don't know how complicated that will be.

@jaredpar
Copy link
Member

jaredpar commented Jul 9, 2024

I don't think there are existing end-to-end tests, I can look into adding one, but perhaps as a follow up PR, I don't know how complicated that will be.

Fine with it being a follow up PR. I'm not 100% sure if we can do an end-to-end test here or if we have to move that to installer.

@baronfel can you help with some guidance here?

<data name="CannotDirectlyReferenceMicrosoftNetCompilersToolsetFramework" xml:space="preserve">
<value>NETSDK1205: The Microsoft.Net.Compilers.Toolset.Framework package should not be set directly. Set the property 'BuildWithNetFrameworkHostedCompiler' to 'true' instead if you need it.</value>
<comment>{StrBegin="NETSDK1205: "}{Locked="Microsoft.Net.Compilers.Toolset.Framework"}{Locked="BuildWithNetFrameworkHostedCompiler"}</comment>
</data>
Copy link
Member

Choose a reason for hiding this comment

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

We can always remove a warning but adding one is a compat break, so I think I lean toward changing it rather than removing it.

<NETSdkWarning ResourceName="CannotDirectlyReferenceMicrosoftNetCompilersToolsetFramework"
Condition="'@(PackageReference->AnyHaveMetadataValue('Identity', 'Microsoft.Net.Compilers.Toolset.Framework'))' == 'true'" />
<PropertyGroup Condition="'$(BuildWithNetFrameworkHostedCompiler)' == 'true' and '$(OS)' == 'Windows_NT'">
<RoslynTargetsPath>$(NuGetPackageRoot)\Microsoft.Net.Sdk.Compilers.Toolset\$(NETCoreSdkVersion)</RoslynTargetsPath>
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't NuGet lower-case the package name by default? I guess it won't matter since the only case we care about here is Windows but I'd still do

Suggested change
<RoslynTargetsPath>$(NuGetPackageRoot)\Microsoft.Net.Sdk.Compilers.Toolset\$(NETCoreSdkVersion)</RoslynTargetsPath>
<RoslynTargetsPath>$(NuGetPackageRoot)\microsoft.net.sdk.compilers.toolset\$(NETCoreSdkVersion)</RoslynTargetsPath>


<ItemGroup Condition="'$(BuildWithNetFrameworkHostedCompiler)' == 'true' and '$(OS)' == 'Windows_NT' ">
<PackageReference Include="Microsoft.Net.Compilers.Toolset.Framework" PrivateAssets="all" Version="$(_NetFrameworkHostedCompilersVersion)" IsImplicitlyDefined="true" />
<Target Name="_DownloadMicrosoftNetSdkCompilersToolsetPackage" Condition="'$(_NeedToDownloadMicrosoftNetSdkCompilersToolsetPackage)' == 'true'" BeforeTargets="CollectPackageReferences">
Copy link
Member

Choose a reason for hiding this comment

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

Does this need to be in a target? I think it was before so that the warning could be thrown--is that right @Forgind?

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, makes sense, it probably doesn't need to be in a Target. Currently it looks like we will be re-adding the warning based on #41951 (comment) - but I guess the PackageDownload could still be outside the Target.

@marcpopMSFT
Copy link
Member

marcpopMSFT commented Jul 9, 2024

I don't think there are existing end-to-end tests, I can look into adding one, but perhaps as a follow up PR, I don't know how complicated that will be.

Fine with it being a follow up PR. I'm not 100% sure if we can do an end-to-end test here or if we have to move that to installer.

There's no installer anymore. We do have E2E tests here but @MiYanni is still getting them lined up in the sdk test infrastructure and using the right layout. It might be possible to add a test there but I don't know how you validate as we don't have tight control over the VS version on the images (so you'd be setting the property explicitly but the behavior wouldn't be much different for an E2E test)

@jaredpar
Copy link
Member

jaredpar commented Jul 9, 2024

It might be possible to add a test there but I don't know how you validate as we don't have tight control over the VS version on the images (so you'd be setting the property explicitly but the behavior wouldn't be much different for an E2E test)

I'm less concerned about the VS version and more concerned about basic functionality concerns. My idea for a test is more / less to do the following:

> dotnet new webapp
> msbuild -p:BuildWithNetFrameworkHostedCompiler=true -bl

Then ensure the build succeeded and it downloaded + used the compiler from the downloaded package.

There is a bit of risk in constructing the components of this solution in multiple repos. This test would guard against silly mistakes in roslyn thta break the layout of the package, or build authoring errors that messed up the data flow to use the <PcakageDownload> path.

@jjonescz
Copy link
Member Author

jjonescz commented Jul 9, 2024

Then ensure the build succeeded and it downloaded + used the compiler from the downloaded package.

I think the current tests like It_downloads_Microsoft_Net_Compilers_Toolset_Framework_when_requested verify that. E.g., if the layout broke the build inside the test should fail because the UsingTask would have wrong path. The test also verifies the package is downloaded.

@dsplaisted
Copy link
Member

> msbuild -p:BuildWithNetFrameworkHostedCompiler=true -bl

This is pretty easy to do, something like:

new BuildCommand(testAsset)
    .Execute("-p:BuildWithNetFrameworkHostedCompiler=true")
    .Should()
    .Pass();
> dotnet new webapp

You can do this too, though most of our tests construct the project themselves or use checked-in assets. It's a question of whether you want to depend on the template and have the test use the latest version of the template (and potentially break because of changes to it).

@jaredpar
Copy link
Member

jaredpar commented Jul 9, 2024

It's a question of whether you want to depend on the template and have the test use the latest version of the template (and potentially break because of changes to it).

That's exactly what we want. This feature is about "can we build latest" so want it to ebb and flow with how the product evolves.

This is pretty easy to do, something like:

Can that capture the binary log too?

@dsplaisted
Copy link
Member

Can that capture the binary log too?

You can add -bl as a parameter, which helps when debugging locally, but I don't think we have an easy way hooked up to let you access a binlog that a test creates when running in CI.

<NETSdkWarning ResourceName="CannotDirectlyReferenceMicrosoftNetCompilersToolsetFramework"
Condition="'@(PackageReference->AnyHaveMetadataValue('Identity', 'Microsoft.Net.Compilers.Toolset.Framework'))' == 'true'" />
<PropertyGroup Condition="'$(BuildWithNetFrameworkHostedCompiler)' == 'true' and '$(OS)' == 'Windows_NT'">
<RoslynTargetsPath>$(NuGetPackageRoot)\microsoft.net.sdk.compilers.toolset\$(NETCoreSdkVersion)</RoslynTargetsPath>
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 for PackageDownload, GeneratePathProperty is automatically set to true. Any reason not to use the property NuGet generates for the package?

Also, what happens during the restore phase when the package hasn't been downloaded yet. Is it OK for restore if this points to a non-existent path?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think for PackageDownload, GeneratePathProperty is automatically set to true. Any reason not to use the property NuGet generates for the package?

I think the property is not available for PackageDownload: NuGet/Home#8476

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, what happens during the restore phase when the package hasn't been downloaded yet. Is it OK for restore if this points to a non-existent path?

I think yes, the compiler shouldn't be used during or before restore, right?
Also setting the path after restoring doesn't seem to have any effect, I guess the UsingTask is considered sooner and cannot be overwritten?

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, what happens during the restore phase when the package hasn't been downloaded yet. Is it OK for restore if this points to a non-existent path?

Looks like you were right, that is a problem in Visual Studio: #42238

@marcpopMSFT
Copy link
Member

Can that capture the binary log too?

You can add -bl as a parameter, which helps when debugging locally, but I don't think we have an easy way hooked up to let you access a binlog that a test creates when running in CI.

May I suggest using -getItem: or -getProperty? That would let you pull values out of the binlog if you needed them if there was something in an item or property you were looking for.

@jaredpar
Copy link
Member

jaredpar commented Jul 9, 2024

That would let you pull values out of the binlog if you needed them if there was something in an item or property you were looking for.

There are two key items we are looking for:

  1. Did the compilation succeed?
  2. Which compiler was used?

Those are really easy to get out of the binlog if we have access to it.

@marcpopMSFT
Copy link
Member

My point is that we don't have CLI libraries for automating binlog consumption. My recommendation is to do a build per Daniel above and check that it passed and then do a build with the getProperty or getItem flag to get the version of the compiler without having to process a binlog at all.

@jjonescz
Copy link
Member Author

jjonescz commented Jul 10, 2024

May I suggest using -getItem: or -getProperty?

I don't know what item or property to get to determine the used compiler assembly path. We could get the RoslynTargetsPath property but that doesn't guarantee it ends up being the DLL used. I think I can instead just assert the path is in the standard output which contains the full command line executed.

@jjonescz jjonescz merged commit 25cdd7a into dotnet:main Jul 12, 2024
37 checks passed
@jjonescz jjonescz deleted the tearing branch July 12, 2024 06:59
@MiYanni MiYanni mentioned this pull request Jul 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Infrastructure untriaged Request triage from a team member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using SDK compiler in torn builds
7 participants