[Harness] Generalize MSBuildTask and DotnetBuildTask. (#8306)

Move all the logic outside of the Jenkins namespace. Rework a little the
inheritance to make it nicer in the constructors.

Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
Co-authored-by: Přemek Vysoký <premek.vysoky@microsoft.com>
This commit is contained in:
Manuel de la Pena 2020-04-10 16:50:50 -04:00 коммит произвёл GitHub
Родитель 8d3987b84a
Коммит a2f57b38d6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 309 добавлений и 188 удалений

Просмотреть файл

@ -13,9 +13,11 @@ using Microsoft.DotNet.XHarness.iOS.Shared.Utilities;
using Microsoft.DotNet.XHarness.iOS.Shared; using Microsoft.DotNet.XHarness.iOS.Shared;
using Microsoft.DotNet.XHarness.iOS.Shared.Hardware; using Microsoft.DotNet.XHarness.iOS.Shared.Hardware;
using Xharness.TestTasks; using Xharness.TestTasks;
using MSBuildTask = Xharness.Jenkins.TestTasks.MSBuildTask;
using DotNetBuildTask = Xharness.Jenkins.TestTasks.DotNetBuildTask;
namespace Xharness.Jenkins { namespace Xharness.Jenkins {
public class Jenkins : IResourceManager public class Jenkins : IResourceManager, IErrorKnowledgeBase
{ {
readonly ISimulatorLoader simulators; readonly ISimulatorLoader simulators;
readonly IHardwareDeviceLoader devices; readonly IHardwareDeviceLoader devices;
@ -1756,7 +1758,7 @@ namespace Xharness.Jenkins {
} }
} }
public bool IsHE0038Error (ILog log) { bool IsHE0038Error (ILog log) {
if (log == null) if (log == null)
return false; return false;
if (File.Exists (log.FullPath) && new FileInfo (log.FullPath).Length > 0) { if (File.Exists (log.FullPath) && new FileInfo (log.FullPath).Length > 0) {
@ -1773,7 +1775,7 @@ namespace Xharness.Jenkins {
return false; return false;
} }
public bool IsMonoMulti3Issue (ILog log) { bool IsMonoMulti3Issue (ILog log) {
if (log == null) if (log == null)
return false; return false;
if (File.Exists (log.FullPath) && new FileInfo (log.FullPath).Length > 0) { if (File.Exists (log.FullPath) && new FileInfo (log.FullPath).Length > 0) {
@ -1788,6 +1790,27 @@ namespace Xharness.Jenkins {
} }
return false; return false;
} }
public bool IsKnownBuildIssue (ILog buildLog, out string knownFailureMessage)
{
knownFailureMessage = null;
if (IsMonoMulti3Issue (buildLog)) {
knownFailureMessage = $"<a href='https://github.com/mono/mono/issues/18560'>Undefined symbol ___multi3 on Release Mode</a>";
return true;
}
return false;
}
public bool IsKnownTestIssue (ILog runLog, out string knownFailureMessage)
{
knownFailureMessage = null;
if (IsHE0038Error (runLog)) {
knownFailureMessage = $"<a href='https://github.com/xamarin/maccore/issues/581'>HE0038</a>";
return true;
}
return false;
}
string previous_test_runs; string previous_test_runs;
void GenerateReportImpl (Stream stream, StreamWriter markdown_summary = null) void GenerateReportImpl (Stream stream, StreamWriter markdown_summary = null)

Просмотреть файл

@ -7,36 +7,26 @@ using Xharness.TestTasks;
namespace Xharness.Jenkins.TestTasks { namespace Xharness.Jenkins.TestTasks {
abstract class BuildProjectTask : BuildToolTask abstract class BuildProjectTask : BuildToolTask
{ {
Xharness.TestTasks.BuildProjectTask BuildProject => buildToolTask as Xharness.TestTasks.BuildProjectTask;
public string SolutionPath { public string SolutionPath {
get => buildProjectTask.SolutionPath; get => BuildProject.SolutionPath;
set => buildProjectTask.SolutionPath = value; set => BuildProject.SolutionPath = value;
} }
Xharness.TestTasks.BuildProjectTask buildProjectTask;
public override TestProject TestProject {
get => base.TestProject;
set {
base.TestProject = value;
buildProjectTask.TestProject = value;
}
}
protected BuildProjectTask (Jenkins jenkins, TestProject testProject, IProcessManager processManager) : base (jenkins, processManager) protected BuildProjectTask (Jenkins jenkins, TestProject testProject, IProcessManager processManager) : base (jenkins, processManager)
{ => TestProject = testProject ?? throw new ArgumentNullException (nameof (testProject));
buildProjectTask = new Xharness.TestTasks.BuildProjectTask (processManager, Jenkins, this, this);
TestProject = testProject ?? throw new ArgumentNullException (nameof (testProject));
}
public virtual bool RestoreNugets => buildProjectTask.RestoreNugets; public virtual bool RestoreNugets => BuildProject.RestoreNugets;
public override bool SupportsParallelExecution => buildProjectTask.SupportsParallelExecution; public override bool SupportsParallelExecution => BuildProject.SupportsParallelExecution;
protected override void InitializeTool ()
=> buildToolTask = new Xharness.TestTasks.BuildProjectTask (ProcessManager, Jenkins, this, this);
// This method must be called with the desktop resource acquired // This method must be called with the desktop resource acquired
// (which is why it takes an IAcquiredResources as a parameter without using it in the function itself). // (which is why it takes an IAcquiredResources as a parameter without using it in the function itself).
protected async Task RestoreNugetsAsync (ILog log, IAcquiredResource resource, bool useXIBuild = false) => protected async Task RestoreNugetsAsync (ILog log, IAcquiredResource resource, bool useXIBuild = false) =>
ExecutionResult = await buildProjectTask.RestoreNugetsAsync (log, resource, useXIBuild); ExecutionResult = await BuildProject.RestoreNugetsAsync (log, resource, useXIBuild);
} }
} }

Просмотреть файл

@ -1,56 +1,60 @@
using System.Threading.Tasks; using System;
using Microsoft.DotNet.XHarness.iOS.Shared.Execution; using System.Threading.Tasks;
using Microsoft.DotNet.XHarness.iOS.Shared.Execution;
namespace Xharness.Jenkins.TestTasks
{ namespace Xharness.Jenkins.TestTasks
public abstract class BuildToolTask : AppleTestTask {
{ public abstract class BuildToolTask : AppleTestTask
readonly Xharness.TestTasks.BuildToolTask buildToolTask; {
protected Xharness.TestTasks.BuildToolTask buildToolTask;
public IProcessManager ProcessManager => buildToolTask.ProcessManager;
public IProcessManager ProcessManager { get; }
public override string TestName {
get => base.TestName; public override string TestName {
set { get => base.TestName;
base.TestName = value; set {
buildToolTask.TestName = value; base.TestName = value;
} buildToolTask.TestName = value;
} }
}
public bool SpecifyPlatform {
get => buildToolTask.SpecifyPlatform; public bool SpecifyPlatform {
set => buildToolTask.SpecifyPlatform = value; get => buildToolTask.SpecifyPlatform;
} set => buildToolTask.SpecifyPlatform = value;
}
public bool SpecifyConfiguration {
get => buildToolTask.SpecifyConfiguration; public bool SpecifyConfiguration {
set => buildToolTask.SpecifyConfiguration = value; get => buildToolTask.SpecifyConfiguration;
} set => buildToolTask.SpecifyConfiguration = value;
}
public override TestProject TestProject {
get => base.TestProject; public override TestProject TestProject {
set { get => base.TestProject;
base.TestProject = value; set {
buildToolTask.TestProject = value; base.TestProject = value;
} buildToolTask.TestProject = value;
} }
}
protected BuildToolTask (Jenkins jenkins, IProcessManager processManager) : base (jenkins)
=> buildToolTask = new Xharness.TestTasks.BuildToolTask (processManager); protected BuildToolTask (Jenkins jenkins, IProcessManager processManager) : base (jenkins) {
ProcessManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
public override TestPlatform Platform { InitializeTool ();
get => base.Platform; }
set {
base.Platform = value; public override TestPlatform Platform {
buildToolTask.Platform = value; get => base.Platform;
} set {
} base.Platform = value;
buildToolTask.Platform = value;
public override string Mode { }
get => buildToolTask.Mode; }
set => buildToolTask.Mode = value;
} public override string Mode {
get => buildToolTask.Mode;
public virtual Task CleanAsync () => buildToolTask.CleanAsync (); set => buildToolTask.Mode = value;
} }
}
protected virtual void InitializeTool () => buildToolTask = new Xharness.TestTasks.BuildToolTask (ProcessManager);
public virtual Task CleanAsync () => buildToolTask.CleanAsync ();
}
}

Просмотреть файл

@ -1,30 +1,35 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.DotNet.XHarness.iOS.Shared.Execution; using Microsoft.DotNet.XHarness.iOS.Shared.Execution;
namespace Xharness.Jenkins.TestTasks { namespace Xharness.Jenkins.TestTasks {
class DotNetBuildTask : MSBuildTask { class DotNetBuildTask : MSBuildTask {
public DotNetBuildTask (Jenkins jenkins, TestProject testProject, IProcessManager processManager) : base (jenkins, testProject, processManager) public DotNetBuildTask (Jenkins jenkins, TestProject testProject, IProcessManager processManager)
: base (jenkins, testProject, processManager) { }
protected override string ToolName => Harness.DOTNET;
public override void SetEnvironmentVariables (Process process)
{ {
SetDotNetEnvironmentVariables (Environment); base.SetEnvironmentVariables (process);
} // modify those env vars that we do care about
protected override string ToolName { process.StartInfo.EnvironmentVariables.Remove ("MSBUILD_EXE_PATH");
get { return Harness.DOTNET; } process.StartInfo.EnvironmentVariables.Remove ("MSBuildExtensionsPathFallbackPathsOverride");
} process.StartInfo.EnvironmentVariables.Remove ("MSBuildSDKsPath");
process.StartInfo.EnvironmentVariables.Remove ("TargetFrameworkFallbackSearchPaths");
public override bool RestoreNugets => false; // 'dotnet build' will restore process.StartInfo.EnvironmentVariables.Remove ("MSBuildExtensionsPathFallbackPathsOverride");
protected override List<string> ToolArguments {
get {
var args = base.ToolArguments;
// 'dotnet build' takes almost the same arguments as 'msbuild', so just massage a little bit.
args.Remove ("--");
args.Insert (0, "build");
return args;
}
} }
protected override void InitializeTool () =>
buildToolTask = new Xharness.TestTasks.DotNetBuildTask (
msbuildPath: ToolName,
processManager: ProcessManager,
resourceManager: Jenkins,
eventLogger: this,
envManager: this,
errorKnowledgeBase: Jenkins);
public static void SetDotNetEnvironmentVariables (Dictionary<string, string> environment) public static void SetDotNetEnvironmentVariables (Dictionary<string, string> environment)
{ {

Просмотреть файл

@ -1,12 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using Microsoft.DotNet.XHarness.iOS.Shared;
using Microsoft.DotNet.XHarness.iOS.Shared.Execution; using Microsoft.DotNet.XHarness.iOS.Shared.Execution;
using Microsoft.DotNet.XHarness.iOS.Shared.Logging; using Microsoft.DotNet.XHarness.iOS.Shared.Logging;
using Microsoft.DotNet.XHarness.iOS.Shared.Utilities;
namespace Xharness.Jenkins.TestTasks { namespace Xharness.Jenkins.TestTasks {
class MSBuildTask : BuildProjectTask class MSBuildTask : BuildProjectTask
@ -15,98 +11,45 @@ namespace Xharness.Jenkins.TestTasks {
protected virtual string ToolName => Harness.XIBuildPath; protected virtual string ToolName => Harness.XIBuildPath;
protected virtual List<string> ToolArguments { protected virtual List<string> ToolArguments =>
get { MSBuild.GetToolArguments (ProjectPlatform, ProjectConfiguration, ProjectFile, BuildLog);
var binlogPath = BuildLog.FullPath.Replace (".txt", ".binlog");
var args = new List<string> (); Xharness.TestTasks.MSBuildTask MSBuild => buildToolTask as Xharness.TestTasks.MSBuildTask;
args.Add ("--");
args.Add ("/verbosity:diagnostic");
args.Add ($"/bl:{binlogPath}");
if (SpecifyPlatform)
args.Add ($"/p:Platform={ProjectPlatform}");
if (SpecifyConfiguration)
args.Add ($"/p:Configuration={ProjectConfiguration}");
args.Add (ProjectFile);
return args;
}
}
public MSBuildTask (Jenkins jenkins, TestProject testProject, IProcessManager processManager) : base (jenkins, testProject, processManager) public MSBuildTask (Jenkins jenkins, TestProject testProject, IProcessManager processManager)
{ : base (jenkins, testProject, processManager) { }
}
protected override void InitializeTool () =>
buildToolTask = new Xharness.TestTasks.MSBuildTask (
msbuildPath: ToolName,
processManager: ProcessManager,
resourceManager: Jenkins,
eventLogger: this,
envManager: this,
errorKnowledgeBase: Jenkins);
protected override async Task ExecuteAsync () protected override async Task ExecuteAsync ()
{ {
using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) { using var resource = await NotifyAndAcquireDesktopResourceAsync ();
BuildLog = Logs.Create ($"build-{Platform}-{Timestamp}.txt", LogType.BuildLog.ToString ()); BuildLog = Logs.Create ($"build-{Platform}-{Timestamp}.txt", LogType.BuildLog.ToString ());
(ExecutionResult, KnownFailure) = await MSBuild.ExecuteAsync (
projectPlatform: ProjectPlatform,
projectConfiguration: ProjectConfiguration,
projectFile: ProjectFile,
resource: resource,
dryRun: Harness.DryRun,
buildLog: BuildLog,
mainLog: Jenkins.MainLog);
await RestoreNugetsAsync (BuildLog, resource, useXIBuild: true); BuildLog.Dispose ();
using (var xbuild = new Process ()) {
xbuild.StartInfo.FileName = ToolName;
xbuild.StartInfo.Arguments = StringUtils.FormatArguments (ToolArguments);
SetEnvironmentVariables (xbuild);
xbuild.StartInfo.EnvironmentVariables.Remove ("MSBuildExtensionsPath");
LogEvent (BuildLog, "Building {0} ({1})", TestName, Mode);
if (!Harness.DryRun) {
var timeout = TimeSpan.FromMinutes (60);
var result = await ProcessManager.RunAsync (xbuild, BuildLog, timeout);
if (result.TimedOut) {
ExecutionResult = TestExecutingResult.TimedOut;
BuildLog.WriteLine ("Build timed out after {0} seconds.", timeout.TotalSeconds);
} else if (result.Succeeded) {
ExecutionResult = TestExecutingResult.Succeeded;
} else {
ExecutionResult = TestExecutingResult.Failed;
if (Jenkins.IsMonoMulti3Issue (BuildLog)) {
KnownFailure = $"<a href='https://github.com/mono/mono/issues/18560'>Undefined symbol ___multi3 on Release Mode</a>";
}
}
}
Jenkins.MainLog.WriteLine ("Built {0} ({1})", TestName, Mode);
}
BuildLog.Dispose ();
}
} }
async Task CleanProjectAsync (ILog log, string project_file, string project_platform, string project_configuration) public override Task CleanAsync () =>
{ MSBuild.CleanAsync (
// Don't require the desktop resource here, this shouldn't be that resource sensitive projectPlatform: ProjectPlatform,
using (var xbuild = new Process ()) { projectConfiguration: ProjectConfiguration,
xbuild.StartInfo.FileName = Harness.XIBuildPath; projectFile: ProjectFile,
var args = new List<string> (); cleanLog: Logs.Create ($"clean-{Platform}-{Timestamp}.txt", "Clean log"),
args.Add ("--"); mainLog: Jenkins.MainLog);
args.Add ("/verbosity:diagnostic");
if (project_platform != null)
args.Add ($"/p:Platform={project_platform}");
if (project_configuration != null)
args.Add ($"/p:Configuration={project_configuration}");
args.Add (project_file);
args.Add ("/t:Clean");
xbuild.StartInfo.Arguments = StringUtils.FormatArguments (args);
SetEnvironmentVariables (xbuild);
LogEvent (log, "Cleaning {0} ({1}) - {2}", TestName, Mode, project_file);
var timeout = TimeSpan.FromMinutes (1);
await ProcessManager.RunAsync (xbuild, log, timeout);
log.WriteLine ("Clean timed out after {0} seconds.", timeout.TotalSeconds);
Jenkins.MainLog.WriteLine ("Cleaned {0} ({1})", TestName, Mode);
}
}
public async override Task CleanAsync ()
{
var log = Logs.Create ($"clean-{Platform}-{Timestamp}.txt", "Clean log");
await CleanProjectAsync (log, ProjectFile, SpecifyPlatform ? ProjectPlatform : null, SpecifyConfiguration ? ProjectConfiguration : null);
// Iterate over all the project references as well.
var doc = new XmlDocument ();
doc.LoadWithoutNetworkAccess (ProjectFile);
foreach (var pr in doc.GetProjectReferences ()) {
var path = pr.Replace ('\\', '/');
await CleanProjectAsync (log, path, SpecifyPlatform ? ProjectPlatform : null, SpecifyConfiguration ? ProjectConfiguration : null);
}
}
} }
} }

Просмотреть файл

@ -127,8 +127,8 @@ namespace Xharness.Jenkins.TestTasks {
ExecutionResult = runner.Result; ExecutionResult = runner.Result;
KnownFailure = null; KnownFailure = null;
if (Jenkins.IsHE0038Error (runner.MainLog)) if (Jenkins.IsKnownTestIssue (runner.MainLog, out KnownFailure))
KnownFailure = $"<a href='https://github.com/xamarin/maccore/issues/581'>HE0038</a>"; Jenkins.MainLog.WriteLine ($"Test run has a known failure: '{KnownFailure}'");
} }
protected override string XIMode { protected override string XIMode {

Просмотреть файл

@ -0,0 +1,24 @@
using System.Collections.Generic;
using Microsoft.DotNet.XHarness.iOS.Shared.Execution;
using Microsoft.DotNet.XHarness.iOS.Shared.Logging;
namespace Xharness.TestTasks {
public class DotNetBuildTask : MSBuildTask {
public DotNetBuildTask (string msbuildPath,
IProcessManager processManager,
IResourceManager resourceManager,
IEventLogger eventLogger,
IEnvManager envManager,
IErrorKnowledgeBase errorKnowledgeBase)
: base (msbuildPath, processManager, resourceManager, eventLogger, envManager, errorKnowledgeBase) { }
public override List<string> GetToolArguments (string projectPlatform, string projectConfiguration, string projectFile, ILog buildLog)
{
var args = base.GetToolArguments (projectPlatform, projectConfiguration, projectFile, buildLog);
args.Remove ("--");
args.Insert (0, "build");
return args;
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using Microsoft.DotNet.XHarness.iOS.Shared.Logging;
namespace Xharness.TestTasks {
/// <summary>
/// Interface to be implemented by those classes that know about common errors that will be reporter to the
/// harness runner. This allows to store certain problems that we know are common and that we can skip, helping
/// those that are monitoring the result.
/// </summary>
public interface IErrorKnowledgeBase {
bool IsKnownBuildIssue (ILog buildLog, out string knownFailureMessage);
bool IsKnownTestIssue (ILog runLog, out string knownFailureMessage);
}
}

Просмотреть файл

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.DotNet.XHarness.iOS.Shared;
using Microsoft.DotNet.XHarness.iOS.Shared.Execution;
using Microsoft.DotNet.XHarness.iOS.Shared.Logging;
using Microsoft.DotNet.XHarness.iOS.Shared.Utilities;
namespace Xharness.TestTasks {
public class MSBuildTask : BuildProjectTask {
readonly IErrorKnowledgeBase errorKnowledgeBase;
readonly string msbuildPath;
public virtual List<string> GetToolArguments (string projectPlatform, string projectConfiguration, string projectFile, ILog buildLog) {
var binlogPath = buildLog.FullPath.Replace (".txt", ".binlog");
var args = new List<string> ();
args.Add ("--");
args.Add ("/verbosity:diagnostic");
args.Add ($"/bl:{binlogPath}");
if (SpecifyPlatform)
args.Add ($"/p:Platform={projectPlatform}");
if (SpecifyConfiguration)
args.Add ($"/p:Configuration={projectConfiguration}");
args.Add (projectFile);
return args;
}
public MSBuildTask (string msbuildPath,
IProcessManager processManager,
IResourceManager resourceManager,
IEventLogger eventLogger,
IEnvManager envManager,
IErrorKnowledgeBase errorKnowledgeBase) : base (processManager, resourceManager, eventLogger, envManager)
{
this.msbuildPath = msbuildPath ?? throw new ArgumentNullException (nameof (msbuildPath));
this.errorKnowledgeBase = errorKnowledgeBase ?? throw new ArgumentNullException (nameof (errorKnowledgeBase));
}
public async Task<(TestExecutingResult ExecutionResult, string KnownFailure)> ExecuteAsync (string projectPlatform,
string projectConfiguration,
string projectFile,
IAcquiredResource resource,
bool dryRun,
ILog buildLog,
ILog mainLog)
{
(TestExecutingResult ExecutionResult, string KnownFailure) result = (TestExecutingResult.NotStarted, (string) null);
await RestoreNugetsAsync (buildLog, resource, useXIBuild: true);
using (var xbuild = new Process ()) {
xbuild.StartInfo.FileName = msbuildPath;
xbuild.StartInfo.Arguments = StringUtils.FormatArguments (GetToolArguments (projectPlatform, projectConfiguration, projectFile, buildLog));
EnviromentManager.SetEnvironmentVariables (xbuild);
xbuild.StartInfo.EnvironmentVariables ["MSBuildExtensionsPath"] = null;
EventLogger.LogEvent (buildLog, "Building {0} ({1})", TestName, Mode);
if (!dryRun) {
var timeout = TimeSpan.FromMinutes (60);
var processResult = await ProcessManager.RunAsync (xbuild, buildLog, timeout);
if (processResult.TimedOut) {
result.ExecutionResult = TestExecutingResult.TimedOut;
buildLog.WriteLine ("Build timed out after {0} seconds.", timeout.TotalSeconds);
} else if (processResult.Succeeded) {
result.ExecutionResult = TestExecutingResult.Succeeded;
} else {
result.ExecutionResult = TestExecutingResult.Failed;
if (errorKnowledgeBase.IsKnownBuildIssue (buildLog, out result.KnownFailure))
buildLog.WriteLine ($"Build has a known failure: '{result.KnownFailure}'");
}
}
mainLog.WriteLine ("Built {0} ({1})", TestName, Mode);
}
return result;
}
async Task CleanProjectAsync (string project_file, string project_platform, string project_configuration, ILog log, ILog mainLog)
{
// Don't require the desktop resource here, this shouldn't be that resource sensitive
using (var xbuild = new Process ()) {
xbuild.StartInfo.FileName = Harness.XIBuildPath;
var args = new List<string> ();
args.Add ("--");
args.Add ("/verbosity:diagnostic");
if (project_platform != null)
args.Add ($"/p:Platform={project_platform}");
if (project_configuration != null)
args.Add ($"/p:Configuration={project_configuration}");
args.Add (project_file);
args.Add ("/t:Clean");
xbuild.StartInfo.Arguments = StringUtils.FormatArguments (args);
EnviromentManager.SetEnvironmentVariables (xbuild);
EventLogger.LogEvent (log, "Cleaning {0} ({1}) - {2}", TestName, Mode, project_file);
var timeout = TimeSpan.FromMinutes (1);
await ProcessManager.RunAsync (xbuild, log, timeout);
log.WriteLine ("Clean timed out after {0} seconds.", timeout.TotalSeconds);
mainLog.WriteLine ("Cleaned {0} ({1})", TestName, Mode);
}
}
public async Task CleanAsync (string projectPlatform, string projectConfiguration, string projectFile, ILog cleanLog, ILog mainLog)
{
await CleanProjectAsync (projectFile, SpecifyPlatform ? projectPlatform : null, SpecifyConfiguration ? projectConfiguration : null, cleanLog, mainLog);
// Iterate over all the project references as well.
var doc = new XmlDocument ();
doc.LoadWithoutNetworkAccess (projectFile);
foreach (var pr in doc.GetProjectReferences ()) {
var path = pr.Replace ('\\', '/');
await CleanProjectAsync (path, SpecifyPlatform ? projectPlatform : null, SpecifyConfiguration ? projectConfiguration : null, cleanLog, mainLog);
}
}
}
}

Просмотреть файл

@ -124,6 +124,9 @@
<Compile Include="TestTasks\BuildProjectTask.cs" /> <Compile Include="TestTasks\BuildProjectTask.cs" />
<Compile Include="TestTasks\IResourceManager.cs" /> <Compile Include="TestTasks\IResourceManager.cs" />
<Compile Include="TestTasks\IEnvManager.cs" /> <Compile Include="TestTasks\IEnvManager.cs" />
<Compile Include="TestTasks\MSBuildTask.cs" />
<Compile Include="TestTasks\IErrorKnowledgeBase.cs" />
<Compile Include="TestTasks\DotNetBuildTask.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\tools\common\SdkVersions.cs"> <Compile Include="..\..\tools\common\SdkVersions.cs">