Skip to content

Commit 1ea4e35

Browse files
authored
[AndroidToolTask] Log tool output as error (#229)
Context: #208 Updates AndroidToolTask to capture all standard output from the tool and log it as an error if the task fails.
1 parent c8a5b5b commit 1ea4e35

File tree

4 files changed

+76
-9
lines changed

4 files changed

+76
-9
lines changed

src/Microsoft.Android.Build.BaseTasks/AndroidToolTask.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
using System;
44
using System.IO;
5+
using System.Text;
6+
using Microsoft.Build.Framework;
57
using Microsoft.Build.Utilities;
68

79
namespace Microsoft.Android.Build.Tasks
@@ -12,6 +14,8 @@ public abstract class AndroidToolTask : ToolTask
1214

1315
protected string WorkingDirectory { get; private set; }
1416

17+
StringBuilder toolOutput = new StringBuilder ();
18+
1519
public AndroidToolTask ()
1620
{
1721
WorkingDirectory = Directory.GetCurrentDirectory();
@@ -20,13 +24,24 @@ public AndroidToolTask ()
2024
public override bool Execute ()
2125
{
2226
try {
23-
return RunTask ();
27+
bool taskResult = RunTask ();
28+
if (!taskResult && !string.IsNullOrEmpty (toolOutput.ToString ())) {
29+
Log.LogUnhandledToolError (TaskPrefix, toolOutput.ToString ().Trim ());
30+
}
31+
toolOutput.Clear ();
32+
return taskResult;
2433
} catch (Exception ex) {
2534
Log.LogUnhandledException (TaskPrefix, ex);
2635
return false;
2736
}
2837
}
2938

39+
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
40+
{
41+
base.LogEventsFromTextOutput (singleLine, messageImportance);
42+
toolOutput.AppendLine (singleLine);
43+
}
44+
3045
// Most ToolTask's do not override Execute and
3146
// just expect the base to be called
3247
public virtual bool RunTask () => base.Execute ();

src/Microsoft.Android.Build.BaseTasks/UnhandledExceptionLogger.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,10 @@ static void LogUnhandledException (Action<string,string> logCodedError, string p
8585
else
8686
logCodedError (prefix + "7000", ex.ToString ());
8787
}
88+
89+
public static void LogUnhandledToolError (this TaskLoggingHelper log, string prefix, string toolOutput)
90+
{
91+
log.LogCodedError ($"XA{prefix}0000", toolOutput);
92+
}
8893
}
8994
}

tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidToolTaskTests.cs

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
using System.IO;
22
using System.Collections.Generic;
3-
using System.Threading.Tasks;
43
using Microsoft.Android.Build.BaseTasks.Tests.Utilities;
54
using Microsoft.Android.Build.Tasks;
65
using NUnit.Framework;
76
using Microsoft.Build.Framework;
8-
using Xamarin.Build;
7+
using NUnit.Framework.Internal;
8+
using System.Linq;
99

1010
namespace Microsoft.Android.Build.BaseTasks.Tests
1111
{
1212
[TestFixture]
1313
public class AndroidToolTaskTests
1414
{
15-
public class MyAndroidTask : AndroidTask {
15+
List<BuildErrorEventArgs> errors;
16+
List<BuildWarningEventArgs> warnings;
17+
List<BuildMessageEventArgs> messages;
18+
MockBuildEngine engine;
19+
20+
public class MyAndroidTask : AndroidTask
21+
{
1622
public override string TaskPrefix {get;} = "MAT";
1723
public string Key { get; set; }
1824
public string Value { get; set; }
@@ -25,7 +31,8 @@ public override bool RunTask ()
2531
}
2632
}
2733

28-
public class MyOtherAndroidTask : AndroidTask {
34+
public class MyOtherAndroidTask : AndroidTask
35+
{
2936
public override string TaskPrefix {get;} = "MOAT";
3037
public string Key { get; set; }
3138
public bool ProjectSpecific { get; set; } = false;
@@ -40,15 +47,31 @@ public override bool RunTask ()
4047
}
4148
}
4249

50+
public class DotnetToolOutputTestTask : AndroidToolTask
51+
{
52+
public override string TaskPrefix {get;} = "DTOT";
53+
protected override string ToolName => "dotnet";
54+
protected override string GenerateFullPathToTool () => ToolExe;
55+
public string CommandLineArgs { get; set; } = "--info";
56+
protected override string GenerateCommandLineCommands () => CommandLineArgs;
57+
}
58+
59+
[SetUp]
60+
public void TestSetup()
61+
{
62+
errors = new List<BuildErrorEventArgs> ();
63+
warnings = new List<BuildWarningEventArgs> ();
64+
messages = new List<BuildMessageEventArgs> ();
65+
engine = new MockBuildEngine (TestContext.Out, errors, warnings, messages);
66+
}
67+
4368
[Test]
4469
[TestCase (true, true, true)]
4570
[TestCase (false, false, true)]
4671
[TestCase (true, false, false)]
4772
[TestCase (false, true, false)]
4873
public void TestRegisterTaskObjectCanRetrieveCorrectItem (bool projectSpecificA, bool projectSpecificB, bool expectedResult)
4974
{
50-
var engine = new MockBuildEngine (TestContext.Out) {
51-
};
5275
var task = new MyAndroidTask () {
5376
BuildEngine = engine,
5477
Key = "Foo",
@@ -72,8 +95,6 @@ public void TestRegisterTaskObjectCanRetrieveCorrectItem (bool projectSpecificA,
7295
[TestCase (false, true, false)]
7396
public void TestRegisterTaskObjectFailsWhenDirectoryChanges (bool projectSpecificA, bool projectSpecificB, bool expectedResult)
7497
{
75-
var engine = new MockBuildEngine (TestContext.Out) {
76-
};
7798
MyAndroidTask task;
7899
var currentDir = Directory.GetCurrentDirectory ();
79100
Directory.SetCurrentDirectory (Path.Combine (currentDir, ".."));
@@ -96,5 +117,30 @@ public void TestRegisterTaskObjectFailsWhenDirectoryChanges (bool projectSpecifi
96117
task2.Execute ();
97118
Assert.AreEqual (expectedResult, string.Compare (task2.Value, task.Value, ignoreCase: true) == 0);
98119
}
120+
121+
[Test]
122+
[TestCase ("invalidcommand", false, "You intended to execute a .NET program, but dotnet-invalidcommand does not exist.")]
123+
[TestCase ("--info", true, "")]
124+
public void FailedAndroidToolTaskShouldLogOutputAsError (string args, bool expectedResult, string expectedErrorText)
125+
{
126+
var task = new DotnetToolOutputTestTask () {
127+
BuildEngine = engine,
128+
CommandLineArgs = args,
129+
};
130+
var taskSucceeded = task.Execute ();
131+
Assert.AreEqual (expectedResult, taskSucceeded, "Task execution did not return expected value.");
132+
133+
if (taskSucceeded) {
134+
Assert.IsEmpty (errors, "Successful task should not have any errors.");
135+
} else {
136+
Assert.IsNotEmpty (errors, "Task expected to fail should have errors.");
137+
Assert.AreEqual ("MSB6006", errors [0].Code,
138+
$"Expected error code MSB6006 but got {errors [0].Code}");
139+
Assert.AreEqual ("XADTOT0000", errors [1].Code,
140+
$"Expected error code XADTOT0000 but got {errors [1].Code}");
141+
Assert.IsTrue (errors.Any (e => e.Message.Contains (expectedErrorText)),
142+
"Task expected to fail should contain expected error text.");
143+
}
144+
}
99145
}
100146
}

tests/Microsoft.Android.Build.BaseTasks-Tests/Microsoft.Android.Build.BaseTasks-Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<IsPackable>false</IsPackable>
1010
<OutputPath>$(TestOutputFullPath)</OutputPath>
1111
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
12+
<RollForward>Major</RollForward>
1213
</PropertyGroup>
1314

1415
<Import Project="..\..\src\Microsoft.Android.Build.BaseTasks\MSBuildReferences.projitems" />

0 commit comments

Comments
 (0)