[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:
Родитель
8d3987b84a
Коммит
a2f57b38d6
|
@ -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) {
|
||||||
|
@ -1789,6 +1791,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,13 +1,14 @@
|
||||||
using System.Threading.Tasks;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.DotNet.XHarness.iOS.Shared.Execution;
|
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 {
|
public override string TestName {
|
||||||
get => base.TestName;
|
get => base.TestName;
|
||||||
|
@ -35,8 +36,10 @@ namespace Xharness.Jenkins.TestTasks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BuildToolTask (Jenkins jenkins, IProcessManager processManager) : base (jenkins)
|
protected BuildToolTask (Jenkins jenkins, IProcessManager processManager) : base (jenkins) {
|
||||||
=> buildToolTask = new Xharness.TestTasks.BuildToolTask (processManager);
|
ProcessManager = processManager ?? throw new ArgumentNullException (nameof (processManager));
|
||||||
|
InitializeTool ();
|
||||||
|
}
|
||||||
|
|
||||||
public override TestPlatform Platform {
|
public override TestPlatform Platform {
|
||||||
get => base.Platform;
|
get => base.Platform;
|
||||||
|
@ -51,6 +54,7 @@ namespace Xharness.Jenkins.TestTasks
|
||||||
set => buildToolTask.Mode = value;
|
set => buildToolTask.Mode = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void InitializeTool () => buildToolTask = new Xharness.TestTasks.BuildToolTask (ProcessManager);
|
||||||
public virtual Task CleanAsync () => buildToolTask.CleanAsync ();
|
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 (
|
||||||
await RestoreNugetsAsync (BuildLog, resource, useXIBuild: true);
|
projectPlatform: ProjectPlatform,
|
||||||
|
projectConfiguration: ProjectConfiguration,
|
||||||
using (var xbuild = new Process ()) {
|
projectFile: ProjectFile,
|
||||||
xbuild.StartInfo.FileName = ToolName;
|
resource: resource,
|
||||||
xbuild.StartInfo.Arguments = StringUtils.FormatArguments (ToolArguments);
|
dryRun: Harness.DryRun,
|
||||||
SetEnvironmentVariables (xbuild);
|
buildLog: BuildLog,
|
||||||
xbuild.StartInfo.EnvironmentVariables.Remove ("MSBuildExtensionsPath");
|
mainLog: Jenkins.MainLog);
|
||||||
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 ();
|
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">
|
||||||
|
|
Загрузка…
Ссылка в новой задаче