Skip to content
This repository was archived by the owner on Jul 13, 2026. It is now read-only.

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

4 files changed

Lines changed: 76 additions & 9 deletions

File tree

‎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
usingSystem;
44
usingSystem.IO;
5+
usingSystem.Text;
6+
usingMicrosoft.Build.Framework;
57
usingMicrosoft.Build.Utilities;
68

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

1315
protectedstringWorkingDirectory{get;privateset;}
1416

17+
StringBuildertoolOutput=newStringBuilder();
18+
1519
publicAndroidToolTask()
1620
{
1721
WorkingDirectory=Directory.GetCurrentDirectory();
@@ -20,13 +24,24 @@ public AndroidToolTask ()
2024
publicoverrideboolExecute()
2125
{
2226
try{
23-
returnRunTask();
27+
booltaskResult=RunTask();
28+
if(!taskResult&&!string.IsNullOrEmpty(toolOutput.ToString())){
29+
Log.LogUnhandledToolError(TaskPrefix,toolOutput.ToString().Trim());
30+
}
31+
toolOutput.Clear();
32+
returntaskResult;
2433
}catch(Exceptionex){
2534
Log.LogUnhandledException(TaskPrefix,ex);
2635
returnfalse;
2736
}
2837
}
2938

39+
protectedoverridevoidLogEventsFromTextOutput(stringsingleLine,MessageImportancemessageImportance)
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
publicvirtualboolRunTask()=>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+
publicstaticvoidLogUnhandledToolError(thisTaskLoggingHelperlog,stringprefix,stringtoolOutput)
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
usingSystem.IO;
22
usingSystem.Collections.Generic;
3-
usingSystem.Threading.Tasks;
43
usingMicrosoft.Android.Build.BaseTasks.Tests.Utilities;
54
usingMicrosoft.Android.Build.Tasks;
65
usingNUnit.Framework;
76
usingMicrosoft.Build.Framework;
8-
usingXamarin.Build;
7+
usingNUnit.Framework.Internal;
8+
usingSystem.Linq;
99

1010
namespaceMicrosoft.Android.Build.BaseTasks.Tests
1111
{
1212
[TestFixture]
1313
publicclassAndroidToolTaskTests
1414
{
15-
publicclassMyAndroidTask:AndroidTask{
15+
List<BuildErrorEventArgs>errors;
16+
List<BuildWarningEventArgs>warnings;
17+
List<BuildMessageEventArgs>messages;
18+
MockBuildEngineengine;
19+
20+
publicclassMyAndroidTask:AndroidTask
21+
{
1622
publicoverridestringTaskPrefix{get;}="MAT";
1723
publicstringKey{get;set;}
1824
publicstringValue{get;set;}
@@ -25,7 +31,8 @@ public override bool RunTask ()
2531
}
2632
}
2733

28-
publicclassMyOtherAndroidTask:AndroidTask{
34+
publicclassMyOtherAndroidTask:AndroidTask
35+
{
2936
publicoverridestringTaskPrefix{get;}="MOAT";
3037
publicstringKey{get;set;}
3138
publicboolProjectSpecific{get;set;}=false;
@@ -40,15 +47,31 @@ public override bool RunTask ()
4047
}
4148
}
4249

50+
publicclassDotnetToolOutputTestTask:AndroidToolTask
51+
{
52+
publicoverridestringTaskPrefix{get;}="DTOT";
53+
protectedoverridestringToolName=>"dotnet";
54+
protectedoverridestringGenerateFullPathToTool()=>ToolExe;
55+
publicstringCommandLineArgs{get;set;}="--info";
56+
protectedoverridestringGenerateCommandLineCommands()=>CommandLineArgs;
57+
}
58+
59+
[SetUp]
60+
publicvoidTestSetup()
61+
{
62+
errors=newList<BuildErrorEventArgs>();
63+
warnings=newList<BuildWarningEventArgs>();
64+
messages=newList<BuildMessageEventArgs>();
65+
engine=newMockBuildEngine(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
publicvoidTestRegisterTaskObjectCanRetrieveCorrectItem(boolprojectSpecificA,boolprojectSpecificB,boolexpectedResult)
4974
{
50-
varengine=newMockBuildEngine(TestContext.Out){
51-
};
5275
vartask=newMyAndroidTask(){
5376
BuildEngine=engine,
5477
Key="Foo",
@@ -72,8 +95,6 @@ public void TestRegisterTaskObjectCanRetrieveCorrectItem (bool projectSpecificA,
7295
[TestCase(false,true,false)]
7396
publicvoidTestRegisterTaskObjectFailsWhenDirectoryChanges(boolprojectSpecificA,boolprojectSpecificB,boolexpectedResult)
7497
{
75-
varengine=newMockBuildEngine(TestContext.Out){
76-
};
7798
MyAndroidTasktask;
7899
varcurrentDir=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+
publicvoidFailedAndroidToolTaskShouldLogOutputAsError(stringargs,boolexpectedResult,stringexpectedErrorText)
125+
{
126+
vartask=newDotnetToolOutputTestTask(){
127+
BuildEngine=engine,
128+
CommandLineArgs=args,
129+
};
130+
vartaskSucceeded=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
<ImportProject="..\..\src\Microsoft.Android.Build.BaseTasks\MSBuildReferences.projitems" />

0 commit comments

Comments
 (0)