dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.21k stars 1.35k forks source link

Generalize "Primary output(s)" detection for TerminalLogger #9608

Open rainersigwald opened 8 months ago

rainersigwald commented 8 months ago

Currently, TL scans through high-priority messages looking for -> to determine what the "primary output" of a given project is in order to render the "project succeeded" message with the path of and a link to that output.

https://github.com/dotnet/msbuild/blob/69a76bb6d3068af5e655e15cf0d290d44cf77672/src/MSBuild/TerminalLogger/TerminalLogger.cs#L554-L556

This is clunky and a structured approach would be cleaner. In addition, the currently-logged message isn't always the "right" output, and it'd be nice if it was more customizable by individual projects (see also https://github.com/dotnet/msbuild/issues/8370#issuecomment-1873016590).

I can think of a couple of ways to do this:

  1. augment ProjectFinishedEventArgs to have an optional list of critical outputs, derived from an item that can be manipulated during the build.
  2. Create a new special target to return that and special-case that target's TargetFinished event in the logger.

The former is more complex and we'd have to be mindful of the perf cost of the item lookup at project-finished time, but it's more flexible in the case of multiple invocations of the same project instance (for instance, build and publish the same project in separate invocations). A target would get single-instanced.

baronfel commented 7 months ago

@rainersigwald silly thought - should we try to use the Outputs from the directly-requested Task(s)? Is that good enough? What would that look like for existing commonly-requested targets?

rainersigwald commented 7 months ago

Not silly at all. Right now that would require:

  1. Listen to ProjectStartedEventArgs for TargetNames
  2. Listen to TargetFinishedEventArgs for those specific TargetNames
  3. Look at TargetOutputs for the targets we care about

We'd have to filter the lists from 1 because in normal execution there are different calls to a project with different entry points ("get list of TFs"/build/"get random other outputs") only some of which are really relevant to the user.

baronfel commented 5 months ago

Current requests for this include

nohwnd commented 5 months ago

Our usage here would be for run attachments, such as TRX, code coverage or process dumps. There can be 0, 1 or multiple files per project.

baronfel commented 4 months ago

Another use case for this might be the Quickbuild cache plugin - when that triggers projects don't appear like they are built at all. with this feature the plugin could report the cached results on behalf of the projects that were not actually built.

baronfel commented 1 week ago

We should consider special-casing output detection for Pack for .NET 9 as well. When packaging, a message like the following is emitted:

Successfully created package 'E:\Code\FsAutoComplete\src\FsAutoComplete\bin\Release\fsautocomplete.0.74.0.nupkg'.

(NOTE: this message will be localized). In addition, the GenerateNuspec Target has outputs in the form of the NuGetPackOutput Item type:

image

If the target to build for a project was Pack and NuGetPackOutput is available, we could use that to get a structured view of the package to treat as the output.

The logged Message doesn't provide a Code so we can't look for it structurally: https://github.com/NuGet/NuGet.Client/blob/f929a0f74b92c3593521a4556d41d6f96528fb24/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs#L202C37-L204