Skip to content

Commit f4dacba

Browse files
authored
Merge pull request #5207 from Forgind/MSB4132-opt-out
Emit MSB4181 when a task returns false (fails) without logging any errors. Fixes #2036 Permit a task to disable this Fixes #5203
2 parents 0b9b0b9 + db1feb2 commit f4dacba

37 files changed

+366
-65
lines changed

ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ public partial interface IBuildEngine6 : Microsoft.Build.Framework.IBuildEngine,
203203
{
204204
System.Collections.Generic.IReadOnlyDictionary<string, string> GetGlobalProperties();
205205
}
206+
public partial interface IBuildEngine7 : Microsoft.Build.Framework.IBuildEngine, Microsoft.Build.Framework.IBuildEngine2, Microsoft.Build.Framework.IBuildEngine3, Microsoft.Build.Framework.IBuildEngine4, Microsoft.Build.Framework.IBuildEngine5, Microsoft.Build.Framework.IBuildEngine6
207+
{
208+
bool AllowFailureWithoutError { get; set; }
209+
}
206210
public partial interface ICancelableTask : Microsoft.Build.Framework.ITask
207211
{
208212
void Cancel();

ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ public partial interface IBuildEngine6 : Microsoft.Build.Framework.IBuildEngine,
203203
{
204204
System.Collections.Generic.IReadOnlyDictionary<string, string> GetGlobalProperties();
205205
}
206+
public partial interface IBuildEngine7 : Microsoft.Build.Framework.IBuildEngine, Microsoft.Build.Framework.IBuildEngine2, Microsoft.Build.Framework.IBuildEngine3, Microsoft.Build.Framework.IBuildEngine4, Microsoft.Build.Framework.IBuildEngine5, Microsoft.Build.Framework.IBuildEngine6
207+
{
208+
bool AllowFailureWithoutError { get; set; }
209+
}
206210
public partial interface ICancelableTask : Microsoft.Build.Framework.ITask
207211
{
208212
void Cancel();

ref/Microsoft.Build.Utilities.Core/net/Microsoft.Build.Utilities.Core.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ protected Task(System.Resources.ResourceManager taskResources, string helpKeywor
352352
public Microsoft.Build.Framework.IBuildEngine4 BuildEngine4 { get { throw null; } }
353353
public Microsoft.Build.Framework.IBuildEngine5 BuildEngine5 { get { throw null; } }
354354
public Microsoft.Build.Framework.IBuildEngine6 BuildEngine6 { get { throw null; } }
355+
public Microsoft.Build.Framework.IBuildEngine7 BuildEngine7 { get { throw null; } }
355356
protected string HelpKeywordPrefix { get { throw null; } set { } }
356357
public Microsoft.Build.Framework.ITaskHost HostObject { get { throw null; } set { } }
357358
public Microsoft.Build.Utilities.TaskLoggingHelper Log { get { throw null; } }

ref/Microsoft.Build.Utilities.Core/netstandard/Microsoft.Build.Utilities.Core.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ protected Task(System.Resources.ResourceManager taskResources, string helpKeywor
197197
public Microsoft.Build.Framework.IBuildEngine4 BuildEngine4 { get { throw null; } }
198198
public Microsoft.Build.Framework.IBuildEngine5 BuildEngine5 { get { throw null; } }
199199
public Microsoft.Build.Framework.IBuildEngine6 BuildEngine6 { get { throw null; } }
200+
public Microsoft.Build.Framework.IBuildEngine7 BuildEngine7 { get { throw null; } }
200201
protected string HelpKeywordPrefix { get { throw null; } set { } }
201202
public Microsoft.Build.Framework.ITaskHost HostObject { get { throw null; } set { } }
202203
public Microsoft.Build.Utilities.TaskLoggingHelper Log { get { throw null; } }

ref/Microsoft.Build/net/Microsoft.Build.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,7 @@ public partial class BuildParameters
967967
{
968968
public BuildParameters() { }
969969
public BuildParameters(Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
970+
public bool AllowFailureWithoutError { get { throw null; } set { } }
970971
public System.Collections.Generic.IDictionary<string, string> BuildProcessEnvironment { get { throw null; } }
971972
public System.Threading.ThreadPriority BuildThreadPriority { get { throw null; } set { } }
972973
public System.Globalization.CultureInfo Culture { get { throw null; } set { } }

ref/Microsoft.Build/netstandard/Microsoft.Build.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ public partial class BuildParameters
963963
{
964964
public BuildParameters() { }
965965
public BuildParameters(Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
966+
public bool AllowFailureWithoutError { get { throw null; } set { } }
966967
public System.Collections.Generic.IDictionary<string, string> BuildProcessEnvironment { get { throw null; } }
967968
public System.Globalization.CultureInfo Culture { get { throw null; } set { } }
968969
public string DefaultToolsVersion { get { throw null; } set { } }

src/Build.UnitTests/BackEnd/BuildResult_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
using Microsoft.Build.Framework;
1111
using Microsoft.Build.Shared;
1212
using Microsoft.Build.Unittest;
13+
using Shouldly;
1314
using Xunit;
14-
1515
using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem;
1616

1717
namespace Microsoft.Build.UnitTests.BackEnd
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Microsoft.Build.Framework;
5+
using Microsoft.Build.Utilities;
6+
7+
namespace Microsoft.Build.UnitTests
8+
{
9+
public class FailingTask : Task
10+
{
11+
public override bool Execute()
12+
{
13+
BuildEngine.GetType().GetProperty("AllowFailureWithoutError").SetValue(BuildEngine, EnableDefaultFailure);
14+
return false;
15+
}
16+
17+
[Required]
18+
public bool EnableDefaultFailure { get; set; }
19+
}
20+
}

src/Build.UnitTests/BackEnd/LoggingContext_Tests.cs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
using Microsoft.Build.BackEnd;
55
using Microsoft.Build.BackEnd.Logging;
66
using Microsoft.Build.Shared;
7+
using Shouldly;
78
using System;
89
using Xunit;
10+
using Xunit.Abstractions;
911

1012
namespace Microsoft.Build.UnitTests.BackEnd
1113
{
@@ -14,29 +16,36 @@ namespace Microsoft.Build.UnitTests.BackEnd
1416
/// </summary>
1517
public class LoggingContext_Tests
1618
{
19+
private readonly ITestOutputHelper _output;
20+
21+
public LoggingContext_Tests(ITestOutputHelper outputHelper)
22+
{
23+
_output = outputHelper;
24+
}
25+
1726
/// <summary>
1827
/// A few simple tests for NodeLoggingContexts.
1928
/// </summary>
2029
[Fact]
2130
public void CreateValidNodeLoggingContexts()
2231
{
23-
NodeLoggingContext context = new NodeLoggingContext(new MockLoggingService(), 1, true);
24-
Assert.True(context.IsInProcNode);
25-
Assert.True(context.IsValid);
32+
NodeLoggingContext context = new NodeLoggingContext(new MockLoggingService(_output.WriteLine), 1, true);
33+
context.IsInProcNode.ShouldBeTrue();
34+
context.IsValid.ShouldBeTrue();
2635

2736
context.LogBuildFinished(true);
28-
Assert.False(context.IsValid);
37+
context.IsValid.ShouldBeFalse();
2938

30-
Assert.Equal(1, context.BuildEventContext.NodeId);
39+
context.BuildEventContext.NodeId.ShouldBe(1);
3140

32-
NodeLoggingContext context2 = new NodeLoggingContext(new MockLoggingService(), 2, false);
33-
Assert.False(context2.IsInProcNode);
34-
Assert.True(context2.IsValid);
41+
NodeLoggingContext context2 = new NodeLoggingContext(new MockLoggingService(_output.WriteLine), 2, false);
42+
context2.IsInProcNode.ShouldBeFalse();
43+
context2.IsValid.ShouldBeTrue();
3544

3645
context2.LogBuildFinished(true);
37-
Assert.False(context2.IsValid);
46+
context2.IsValid.ShouldBeFalse();
3847

39-
Assert.Equal(2, context2.BuildEventContext.NodeId);
48+
context2.BuildEventContext.NodeId.ShouldBe(2);
4049
}
4150

4251
/// <summary>
@@ -49,9 +58,25 @@ public void InvalidNodeIdOnNodeLoggingContext()
4958
{
5059
Assert.Throws<InternalErrorException>(() =>
5160
{
52-
NodeLoggingContext context = new NodeLoggingContext(new MockLoggingService(), -2, true);
61+
_ = new NodeLoggingContext(new MockLoggingService(), -2, true);
5362
}
5463
);
5564
}
65+
66+
[Fact]
67+
public void HasLoggedErrors()
68+
{
69+
NodeLoggingContext context = new NodeLoggingContext(new MockLoggingService(_output.WriteLine), 1, true);
70+
context.HasLoggedErrors.ShouldBeFalse();
71+
72+
context.LogCommentFromText(Framework.MessageImportance.High, "Test message");
73+
context.HasLoggedErrors.ShouldBeFalse();
74+
75+
context.LogWarningFromText(null, null, null, null, "Test warning");
76+
context.HasLoggedErrors.ShouldBeFalse();
77+
78+
context.LogErrorFromText(null, null, null, null, "Test error");
79+
context.HasLoggedErrors.ShouldBeTrue();
80+
}
5681
}
57-
}
82+
}

src/Build.UnitTests/BackEnd/OnError_Tests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
using System.Xml;
1212
using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
1313
using Xunit;
14+
using System.Reflection;
15+
using Shouldly;
16+
using System.Linq;
1417

1518
namespace Microsoft.Build.UnitTests.BackEnd
1619
{
@@ -559,6 +562,29 @@ public void OutOfOrderOnError()
559562
);
560563
}
561564

565+
[Theory]
566+
[InlineData(false)]
567+
[InlineData(true)]
568+
public void ErrorWhenTaskFailsWithoutLoggingErrorEscapeHatch(bool emitError)
569+
{
570+
MockLogger logger = ObjectModelHelpers.BuildProjectExpectFailure($@"
571+
<Project>
572+
<UsingTask TaskName=""FailingTask"" AssemblyFile=""{Assembly.GetExecutingAssembly().Location}"" />
573+
<Target Name=""MyTarget"">
574+
<FailingTask EnableDefaultFailure=""{emitError}"" />
575+
</Target>
576+
</Project>");
577+
if (emitError)
578+
{
579+
logger.ErrorCount.ShouldBe(1);
580+
logger.Errors.First().Code.ShouldBe("MSB4181");
581+
}
582+
else
583+
{
584+
logger.ErrorCount.ShouldBe(0);
585+
}
586+
}
587+
562588
#region Postbuild
563589
/*
564590
* Method: PostBuildBasic

0 commit comments

Comments
 (0)