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

ToolTasks Don't Log MSB4181 When Terminated #6968

Merged
merged 5 commits into from
Oct 31, 2021

Conversation

benvillalobos
Copy link
Member

@benvillalobos benvillalobos commented Oct 15, 2021

Fixes #5508

Context

Originally seen with the Exec and csc tasks. When any tooltask is terminated early, it would simply return false. This goes against our "rule" that ToolTasks should return !Log.HasLoggedErrors.

Changes Made

ToolTasks return !Log.HasLoggedErrors when cancelled.

Testing

Updated two tests that expected Exec to fail when it timed out (timing out follows the same behavior that cancelling does).

Also tested locally by cancelling a build of this repo. See the diff when cancelling msbuild msbuild.dev.slnf

Before

image

after

image

Notes

I intentionally didn't change every return false codepath to keep this fix contained. We can tackle other issues with ToolTask as they arise.

@@ -1522,7 +1522,7 @@ public override bool Execute()
// Raise a comment event to notify that the process completed
if (_terminatedTool)
{
return false;
return !Log.HasLoggedErrors;
Copy link
Member

Choose a reason for hiding this comment

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

This definitely solves the problem but I'm not sure it's conceptually right: the task was cancelled before completion, so shouldn't it return false as in I did not succeed?

Is the "was cancellation requested" state available at the time when we check failure/has-logged-error and log the new message?

Copy link
Member Author

Choose a reason for hiding this comment

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

Is the "was cancellation requested" state available at the time when we check failure/has-logged-error and log the new message?

This is the code that logs the warning
https://github.com/dotnet/msbuild/blob/main/src/Utilities/ToolTask.cs#L939-L949

Can a task be cancelled outside of the user's control? That's not something I considered when writing this.

It really depends how we want to view this task. I see a tooltask being (manually) cancelled as "I didn't fail, so as long as I didn't log an error I'm good"

Copy link
Member

Choose a reason for hiding this comment

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

I was thinking more like wrapping a if (!_cancellationToken.IsCancellationRequested) around the actual error message here:

IBuildEngine be = host.TaskInstance.BuildEngine;
if (taskReturned && !taskResult && !taskLoggingContext.HasLoggedErrors && (be is TaskHost th ? th.BuildRequestsSucceeded : false) && (be is IBuildEngine7 be7 ? !be7.AllowFailureWithoutError : true))
{
if (_continueOnError == ContinueOnError.WarnAndContinue)
{
taskLoggingContext.LogWarning(null,
new BuildEventFileInfo(_targetChildInstance.Location),
"TaskReturnedFalseButDidNotLogError",
_taskNode.Name);
taskLoggingContext.LogComment(MessageImportance.Normal, "ErrorConvertedIntoWarning");
}
else
{
taskLoggingContext.LogError(new BuildEventFileInfo(_targetChildInstance.Location),
"TaskReturnedFalseButDidNotLogError",
_taskNode.Name);
}
}

(but I didn't validate that that actually worked).

My mental model for a task is "return true: everything completed satisfactorily. return false: something somewhere went wrong". But it's a bit ambiguous.

Copy link
Member Author

Choose a reason for hiding this comment

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

My mental model for a task is "return true: everything completed satisfactorily. return false: something somewhere went wrong". But it's a bit ambiguous.

I'm a bit confused here. The RemoveDir change is a good example. It used to return true only if all the directories were successfully deleted. That PR is pushing for having it return true even if some directories weren't deleted, so long as we didn't log an error. which is somewhere in the middle of "return true: everything completed satisfactorily. return false: something somewhere went wrong"

I like your suggested solution better though since it's less break-y, so I'll give that a shot.

Copy link
Member Author

Choose a reason for hiding this comment

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

Your idea works 🚀 and avoids a fundamental change to all tooltasks. Not exactly sure how to test this though, my local test runs a sleep.exe that wouldn't exist in a unit test. Any ideas?

Copy link
Member

Choose a reason for hiding this comment

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

We have a helper for that, try something like:

public void CancelledBuild()
{
Console.WriteLine("Starting CancelledBuild test that is known to hang.");
string contents = CleanupFileContents(@"
<Project xmlns='msbuildnamespace' ToolsVersion='msbuilddefaulttoolsversion'>
<Target Name='test'>
<Exec Command='" + Helpers.GetSleepCommand(TimeSpan.FromSeconds(60)) + @"'/>
<Message Text='[errormessage]'/>
</Target>
</Project>
");

@@ -949,7 +949,7 @@ private async Task<WorkUnitResult> ExecuteInstantiatedTask(ITaskExecutionHost ta

taskLoggingContext.LogComment(MessageImportance.Normal, "ErrorConvertedIntoWarning");
}
else
else if (!(_cancellationToken.CanBeCanceled && _cancellationToken.IsCancellationRequested))
Copy link
Member

Choose a reason for hiding this comment

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

Is the right place for this here or in the big ugly chained if above this level?

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 was hoping to avoid making that chain worse, but you're right. A WarnAndContinue Exec task would log MSB4181 as a warning if it was cancelled.

@benvillalobos benvillalobos changed the title ToolTasks Return !HasLoggedErrors When Terminated ToolTasks Don't Log MSB4181 When Terminated Oct 19, 2021
Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

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

These comments . . . 🧑🏻‍🍳💋🤌🏻

(but . . . is there a test we can add for this?)

@rainersigwald rainersigwald added this to the MSBuild 17.1 milestone Oct 25, 2021
@Forgind Forgind added the merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now. label Oct 25, 2021
@rokonec rokonec merged commit 45a5073 into dotnet:main Oct 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ToolTasks Can Log MSB4181 When Cancelled
4 participants