Skip to content

Conversation

@sharwell
Copy link
Contributor

This change corrects cases where command line restore operations using
the arcade tools failed to produce the same NuGet restore result that
Visual Studio produces for the same project. This failure led to
unnecessary regeneration of these files each time the IDE was opened or
a command line build was performed, thus leading to reduced productivity
and, in some cases, reduced reliability.

<MSBuild Projects="@(_ProjectToRestore)"
Properties="@(_SolutionBuildProps);__BuildPhase=SolutionRestore;_NETCORE_ENGINEERING_TELEMETRY=Restore;MSBuildRestoreSessionId=$([System.Guid]::NewGuid())"
RemoveProperties="$(_RemoveProps)"
RemoveProperties="$(_RemoveProps);TreatWarningsAsErrors"
Copy link
Contributor Author

@sharwell sharwell Mar 31, 2020

Choose a reason for hiding this comment

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

📝 The TreatWarningsAsErrors property gets put in the dgspec file if it's defined for the restore target. This must not occur on developer machines, because it's not the same behavior that restore operations inside Visual Studio produce.

Copy link
Contributor

Choose a reason for hiding this comment

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

The way you proposed the change won't it affect every kind of build?

Copy link
Member

Choose a reason for hiding this comment

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

Seems like a bug in NuGet. Is there an issue tracking it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way you proposed the change won't it affect every kind of build?

Only the /t:Restore operation ignores warnings as errors. The flag will still get passed everywhere else.

Seems like a bug in NuGet. Is there an issue tracking it?

I have no idea if this a bug or by-design in NuGet.

Copy link
Member

Choose a reason for hiding this comment

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

@nkolev92 Any idea?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nkolev92 The problem occurs for projects with this configuration:

<PropertyGroup Condition="'$(BuildingInsideVisualStudio)' != 'true'">
  <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

This is a de-facto standard approach to warnings in managed code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see.
I'd say this is by design then.
NuGet has coded warnings and respects things like WarningsAsErrors and TreatWarningsAsErrors.

This is a de-facto standard approach to warnings in managed code.

Wasn't familiar with this. A bunch of the dotnet/* projects have warnings as errors on by default, maybe NuGet's handling is one reason why :)

In our sln of 80 projects, restore would go from ~2s, to 9s if we did this.

Copy link
Member

Choose a reason for hiding this comment

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

Will this change end up being disruptive? Any insight into how many builds will suddenly fall over when warnings are now treated as errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is going the other way around. We are forcing TreatWarningsAsErrors to false for /t:Restore.

Copy link
Member

Choose a reason for hiding this comment

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

Ooops, sorry. :)

I'm cool with @JohnTortugo is cool.

@markwilkie
Copy link
Member

cc/ @JohnTortugo

$env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages'
$env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages\'
} else {
$env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages'
Copy link
Member

Choose a reason for hiding this comment

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

This line should be updated as well

Copy link
Member

Choose a reason for hiding this comment

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

As should be the equivalent code in tools.sh

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These lines don't run on the machine with Visual Studio, so it wouldn't cause the problem that this is fixing. If there is a separate issue here, can you be more specific about what the change needs to be?

Copy link
Member

Choose a reason for hiding this comment

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

I understand that you're fixing VS experience, but we should be consistent about whether paths are expected to end with a separator or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is the specific change to make here? And is this going to be \ or /?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed it for now; hopefully it's correct.

# Use local cache on CI to ensure deterministic build,
# use global cache in dev builds to avoid cost of downloading packages.
if ($useGlobalNuGetCache) {
$env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages'
Copy link
Member

Choose a reason for hiding this comment

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

Is this also a NuGet bug? Shouldn't it normalize the paths that it's writing into files?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both ways work. If the separator isn't here, then it gets added to the generated files. The problem is even though the semantics are the same, the change itself produces different hashes and the regeneration occurs.

Copy link
Member

Choose a reason for hiding this comment

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

Right, but if NuGet always normalized the path separator we wouldn't need to make these changes (and most importantly, maintain them). It is entirely non-obvious that not adding the terminating separator makes a difference. On that note, let's add a comment ...

/cc @nkolev92

Copy link
Contributor

@nkolev92 nkolev92 Apr 1, 2020

Choose a reason for hiding this comment

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

We're tracking this in NuGet/Home#7968.
I'll look into it this sprint.

I assume any project would break?

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 so (not really break, but not reuse the restore data). @sharwell could you add a comment to the code with a link to NuGet/Home#7968?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think so (not really break, but not reuse the restore data)

yeah, I guess that's what I meant by break.
Defeat the incremental check when it shouldn't :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a link.

This change corrects cases where command line restore operations using
the arcade tools failed to produce the same NuGet restore result that
Visual Studio produces for the same project. This failure led to
unnecessary regeneration of these files each time the IDE was opened or
a command line build was performed, thus leading to reduced productivity
and, in some cases, reduced reliability.
@sharwell sharwell force-pushed the consistent-generation branch from 82a5e68 to c5eb5d8 Compare April 2, 2020 00:55
@sharwell
Copy link
Contributor Author

sharwell commented Apr 4, 2020

What's the status of this? It's a significant workflow disruption for me in Roslyn.

@tmat
Copy link
Member

tmat commented Apr 4, 2020

@markwilkie This will also need to be ported to 3.x.

@sharwell
Copy link
Contributor Author

sharwell commented Apr 5, 2020

@tmat what's the review and merge policy for this repository?

@tmat
Copy link
Member

tmat commented Apr 6, 2020

@JohnTortugo OK to merge?

@tmat tmat merged commit 6c4dea1 into dotnet:master Apr 6, 2020
@sharwell sharwell deleted the consistent-generation branch April 6, 2020 22:37
@tmat
Copy link
Member

tmat commented Apr 6, 2020

@markwilkie I believe we will need to port this to 3.x.

@markwilkie
Copy link
Member

Should be fine. @sharwell - could you fill out the template please?

Also, if we have the time, it'd be great to let this "bake" before porting.

@sharwell
Copy link
Contributor Author

sharwell commented Apr 6, 2020

I'm not sure what it means to port this or what the template is. Can you provide more information about how this works?

@markwilkie
Copy link
Member

Sure, just click the link above (template) and it should be more clear.

@sharwell
Copy link
Contributor Author

sharwell commented Apr 6, 2020

Description

This change updates the -restore behavior for command line builds in arcade projects to produce the same (binary equal) NuGet dependency outputs that a restore within Visual Studio has. When this occurs, a restore in one tool will cause the other tool to fast-path the restore process (no changes) for improved overall developer efficiency.

Customer Impact

This change improves developer efficiency on projects using Arcade by reducing the number of significant NuGet restore operations that occur during normal workflows.

Regression

No

Risk

This is a low risk change. The primary risk centers around an unknown question of whether an outer MSBuild with warnings treated as errors will elevate a warning produced by an inner build that did not have the flag set. If it does not work as expected, it is possible that what used to be a build error will now be a build warning.

Workarounds

The only current workaround is restricting NuGet to one tool. This means users must choose to work either inside Visual Studio or on the command line. Mixing the two could cause Visual Studio to crash when it tries to apply large changes to the NuGet graph.

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.

5 participants