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

Improve error messages when project hasn't been restored for the right target framework or runtime identifier #1262

Merged

Conversation

dsplaisted
Copy link
Member

Fixes #648

Changes error from:

Assets file 'C:\git\dotnet-sdk\bin\repro\WrongFramework\obj\project.assets.json' doesn't have a target for '.NETFramework,Version=v4.6.1/win7-x86'. Ensure you have restored this project for TargetFramework='net461' and RuntimeIdentifier='win7-x86'.

To either this (if RuntimeIdentifier is empty):

Assets file 'C:\git\dotnet-sdk\bin\repro\WrongFramework\obj\project.assets.json' doesn't have a target for '.NETCoreApp,Version=v1.1'. Ensure you have included 'netcoreapp1.1' in the TargetFrameworks for your project.

Or this (if there is a RuntimeIdentifier):

Assets file 'C:\git\dotnet-sdk\bin\repro\WrongFramework\obj\project.assets.json' doesn't have a target for '.NETFramework,Version=v4.6.1/win7-x86'. Ensure you have included 'net461' in the TargetFrameworks for your project. You may also need to include 'win7-x86' in your project's RuntimeIdentifiers.

This PR also adds an explicit check in the RunResolvePackageDependencies target that the right target exists in the assets file. Previously, it was happening incidentally in the GenerateBuildRuntimeConfigurationFiles target, which runs after the compiler is called. So the error would likely either not be noticed among all the compile errors, or after #1257 wouldn't be generated at all.

@dsplaisted dsplaisted requested review from eerhardt and nguerrera May 27, 2017 03:12
if (!string.IsNullOrEmpty(runtime))
{
message += " " + string.Format(Strings.AssetsFileMissingRuntimeIdentifier, runtime);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We should avoid concatenating messages like this. It makes translation more difficult. It's better to duplicate the fragments to give translators maximum flexibility. I see we have a similar pattern in conflict resolution, but that should be fixed as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

At a minimum, if we think duplication is worth avoiding, the concatenation should be done by passing in one fragment into the next via format placeholder. Translators may want to reorder things.

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've switched to duplication over concatanation.


The RuntimeIdentifier isn't used to select references to pass to the compiler, so we don't include
it here. -->
<CheckForTargetInAssetsFile
Copy link
Contributor

Choose a reason for hiding this comment

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

Where do we check for the case where the assets file simply doesn't exist?

Copy link
Member Author

Choose a reason for hiding this comment

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

It will happen the first time a task tries to load the targets file (which will be this task).

wrong framework, we'd end up finding no references to pass to the compiler, and we'd get a ton of
compile errors.

The RuntimeIdentifier isn't used to select references to pass to the compiler, so we don't include
Copy link
Member

Choose a reason for hiding this comment

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

When do we verify that the RID has been restored? Or is the existing error behavior good enough?

<CheckForTargetInAssetsFile
AssetsFilePath="$(ProjectAssetsFile)"
TargetFrameworkMoniker="$(TargetFrameworkMoniker)"
RuntimeIdentifier="" />
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to have a RuntimeIdentifier parameter that is never used?

Copy link
Member Author

Choose a reason for hiding this comment

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

Originally I was passing the RuntimeIdentifier parameter here. However, that caused the It_passes_ridless_target_to_compiler test to fail. I didn't see an obvious way to keep the test coverage except to not check the RID before the compiler is called.

The GenerateBuildRuntimeConfigurationFiles will check that the right RID has been restored.

I'm not entirely sure whether we should just check everything up-front and remove the It_passes_ridless_target_to_compiler test, or whether there's a better way to get the same coverage.

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 we should come up with another way to test than to expect that we can pass an invalid rid if we're only compiling. It's not a vaild use case and it would make sense for the check here to be more defensive.

Options:

  1. A package that causes compilation to fail iff you use its rid-ful assets.
  2. Use GetValues to check ReferencePath is as we expect heading in to Csc.

Copy link
Member

Choose a reason for hiding this comment

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

/cc @natidea - Looks like he wrote that test originally. @natidea - any ideas/thoughts/opinions?

Copy link
Contributor

Choose a reason for hiding this comment

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

IIRC there often isn't a discernable difference between the values coming from the RIDfull and RIDless targets, which is why I wrote the test this way. It is just some packages that could cause this problem (e.g the one in NuGet/Home#4207, and even that one won't repro anymore because NuGet fixed the underlying bug in NuGet/NuGet.Client#1103). But if you can construct a perverse package that contains bogus entries in the RIDfull targets after restore, then Option 1 is a good replacement for this test.

It is probably OK to temporarily skip the test since my fix and the NuGet fix make this scenario very unlikely.

@dsplaisted
Copy link
Member Author

This will also fix #540

@dsplaisted
Copy link
Member Author

This will also fix #324

@dsplaisted
Copy link
Member Author

@eerhardt @nguerrera @natidea OK, I've gone back to checking the RuntimeIdentifier up-front together with the other checks in the assets file. I've rewritten the It_passes_ridless_target_to_compiler test to use a valid RID but remove everything under the RID-specific targets in the assets file after restore but before build, to verify that building doesn't depend on any of those assets.

@dsplaisted
Copy link
Member Author

@dotnet-bot test Windows_NT_FullFramework Release

1 similar comment
@dsplaisted
Copy link
Member Author

@dotnet-bot test Windows_NT_FullFramework Release

@dsplaisted
Copy link
Member Author

@dotnet-bot test Windows_NT_FullFramework Debug

@dsplaisted
Copy link
Member Author

@MattGertz for approval

Customer scenario

Trying to build or publish when the project hasn't been restored, or when it hasn't been restored for the right targets. Previously, there was no explicit check for this before the compiler was called, so you would get a bunch of compile errors and possibly an error that told you what was really wrong. This change checks for the right targets in the assets file up front so you will get a single actionable error message.

Bugs this fixes:

#648, #540, #324

Workarounds, if any

Sift through hundreds or thousands of error messages.

Risk

Low. This moves a check that happened incidentally after the compile was finished to explicitly happen beforehand.

Performance impact

Low. This is an additional task, but the contents of the lock file are cached between tasks in the same build, so it will still only be loaded once.

Is this a regression from a previous update?

No

Root cause analysis:

We weren't explicitly checking for an error condition, and were relying on the fact that something later on would incidentally fail.

How was the bug found?

Dogfooding

@dsplaisted
Copy link
Member Author

@dotnet-bot test Windows_NT_FullFramework Release

@dsplaisted dsplaisted merged commit 5735f0e into dotnet:release/2.0.0 May 31, 2017
@dsplaisted dsplaisted deleted the 648-better-errors-with-bad-tfm branch May 31, 2017 20:23
mmitche pushed a commit to mmitche/sdk that referenced this pull request Jun 5, 2020
…209.1 (dotnet#1262)

- Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.20109.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants