diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/Initialisation/NugetRestoreProcessTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/Initialisation/NugetRestoreProcessTests.cs index e22018d45..3cbfcf7a3 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/Initialisation/NugetRestoreProcessTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/Initialisation/NugetRestoreProcessTests.cs @@ -70,7 +70,7 @@ public void HappyFlow() [TestMethodWithIgnoreIfSupport] [IgnoreIf(nameof(Is.Unix))] //DotnetFramework does not run on Unix - public void ThrowIfRestoreFails() + public void RetryIfRestoreFails() { var nugetPath = @"C:\choco\bin\NuGet.exe"; var msBuildVersion = "16.0.0"; @@ -112,19 +112,21 @@ public void ThrowIfRestoreFails() { ExitCode = 1, Output = "Packages restore failed." - }); - processExecutorMock.Setup(x => x.Start(It.Is(s => s.Contains("Microsoft Visual Studio")), It.Is(s => s.Contains("vswhere.exe")), - @"-latest -requires Microsoft.Component.MSBuild -products * -find MSBuild\**\Bin\MSBuild.exe", null, It.IsAny())) + }).Verifiable(Times.Once); + + processExecutorMock.Setup(x => x.Start(nugetDirectory, nugetPath, + $"restore \"{Path.GetFullPath(SolutionPath)}\"", null, It.IsAny())) .Returns(new ProcessResult() { - ExitCode = 0, - Output = "Msbuild executable path found at " - }); - var target = new NugetRestoreProcess(processExecutorMock.Object); + ExitCode = 1, + Output = "Packages restore failed." + }).Verifiable(Times.Once); - var action = () => target.RestorePackages(SolutionPath); + var target = new NugetRestoreProcess(processExecutorMock.Object); + + target.RestorePackages(SolutionPath); - action.ShouldThrow("Packages restore failed."); + processExecutorMock.VerifyAll(); } [TestMethodWithIgnoreIfSupport] diff --git a/src/Stryker.Core/Stryker.Core/Initialisation/InputFileResolver.cs b/src/Stryker.Core/Stryker.Core/Initialisation/InputFileResolver.cs index 35e06c86d..f2b249c7a 100644 --- a/src/Stryker.Core/Stryker.Core/Initialisation/InputFileResolver.cs +++ b/src/Stryker.Core/Stryker.Core/Initialisation/InputFileResolver.cs @@ -256,15 +256,18 @@ private IAnalyzerResults AnalyzeSingleProject(IProjectAnalyzer project, IStryker if (!buildResultOverallSuccess) { - if (options.DevMode) - { - // clear the logs to remove the noise - _buildalyzerLog.GetStringBuilder().Clear(); - } // if this is a full framework project, we can retry after a nuget restore if (buildResult.Any(r => !IsValid(r) && r.TargetsFullFramework())) { _logger.LogWarning("Project {projectFilePath} analysis failed. Stryker will retry after a nuget restore.", projectLogName); + + if (options.DevMode) + { + _logger.LogWarning("The MsBuild log is below."); + _logger.LogInformation(_buildalyzerLog.ToString()); + _buildalyzerLog.GetStringBuilder().Clear(); + } + _nugetRestoreProcess.RestorePackages(options.SolutionPath, options.MsBuildPath ?? buildResult.First().MsBuildPath()); } var buildOptions = new EnvironmentOptions @@ -279,10 +282,10 @@ private IAnalyzerResults AnalyzeSingleProject(IProjectAnalyzer project, IStryker buildResult.Any(br => IsValid(br) && br.TargetFramework == tf)); } + LogAnalyzerResult(buildResult, options); if (buildResultOverallSuccess) { _logger.LogDebug("Analysis of project {projectFilePath} succeeded.", projectLogName); - LogAnalyzerResult(buildResult, options); return buildResult; } var failedFrameworks = project.ProjectFile.TargetFrameworks.Where(tf => @@ -316,7 +319,7 @@ private void LogAnalyzerResult(IAnalyzerResults analyzerResults, IStrykerOptions foreach (var analyzerResult in analyzerResults) { log.AppendLine($"TargetFramework: {analyzerResult.TargetFramework}"); - log.AppendLine("Succeeded: {analyzerResult.Succeeded}"); + log.AppendLine($"Succeeded: {analyzerResult.Succeeded}"); var properties = analyzerResult.Properties ?? new Dictionary(); foreach (var property in importantProperties) diff --git a/src/Stryker.Core/Stryker.Core/Initialisation/NugetRestoreProcess.cs b/src/Stryker.Core/Stryker.Core/Initialisation/NugetRestoreProcess.cs index 9d396111b..3cbb79c1d 100644 --- a/src/Stryker.Core/Stryker.Core/Initialisation/NugetRestoreProcess.cs +++ b/src/Stryker.Core/Stryker.Core/Initialisation/NugetRestoreProcess.cs @@ -42,20 +42,7 @@ public void RestorePackages(string solutionPath, string msbuildPath = null) var solutionDir = Path.GetDirectoryName(solutionPath); var helper = new MsBuildHelper(null, ProcessExecutor, msbuildPath, _logger); - // Locate MSBuild.exe - var msBuildVersionOutput = helper.GetVersion(); - string msBuildVersion; - if (string.IsNullOrWhiteSpace(msBuildVersionOutput)) - { - msBuildVersion = string.Empty; - _logger.LogDebug("Auto detected msbuild at: {MsBuildPath}, but failed to get version.", msbuildPath); - } - else - { - msBuildVersion = msBuildVersionOutput.Trim(); - _logger.LogDebug("Auto detected msbuild version {MsBuildVersion} at: {MsBuildPath}", msBuildVersion, - msbuildPath); - } + var msBuildVersion = FindMsBuildShortVersion(helper); // Validate nuget.exe is installed and included in path var nugetWhereExeResult = ProcessExecutor.Start(solutionDir, "where.exe", "nuget.exe"); @@ -74,7 +61,14 @@ public void RestorePackages(string solutionPath, string msbuildPath = null) var nugetPath = nugetWhereExeResult.Output .Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).First().Trim(); + if (!InternalRestore(solutionPath, msBuildVersion, nugetPath) && !string.IsNullOrEmpty(msBuildVersion)) + { + InternalRestore(solutionPath, string.Empty, nugetPath); + } + } + private bool InternalRestore(string solutionPath, string msBuildVersion, string nugetPath) + { // Restore packages using nuget.exe var nugetRestoreCommand = $"restore \"{solutionPath}\""; if (!string.IsNullOrEmpty(msBuildVersion)) @@ -85,25 +79,42 @@ public void RestorePackages(string solutionPath, string msbuildPath = null) _logger.LogDebug("Restoring packages using command: {NugetPath} {NugetRestoreCommand}", nugetPath, nugetRestoreCommand); + const int NugetRestoreTimeoutMs = 120000; try { var nugetRestoreResult = ProcessExecutor.Start(Path.GetDirectoryName(nugetPath), nugetPath, - nugetRestoreCommand, timeoutMs: 120000); - if (nugetRestoreResult.ExitCode != ExitCodes.Success) + nugetRestoreCommand, timeoutMs: NugetRestoreTimeoutMs); + if (nugetRestoreResult.ExitCode == ExitCodes.Success) { - _logger.LogCritical("Failed to restore nuget packages. Nuget error: {Error}", - nugetRestoreResult.Error); - throw new InputException( - "Nuget.exe failed to restore packages for your solution. Please review your nuget setup.", - nugetRestoreResult.Output); + _logger.LogDebug("Restored packages using nuget.exe, output: {Error}", nugetRestoreResult.Output); + return true; } - _logger.LogDebug("Restored packages using nuget.exe, output: {Error}", nugetRestoreResult.Output); + _logger.LogError("Failed to restore nuget packages. Nuget error: {Error}", nugetRestoreResult.Error); } - catch (OperationCanceledException) + catch (OperationCanceledException e) { - throw new InputException( - "Nuget.exe failed to restore packages for your solution. Please review your nuget setup."); + _logger.LogError(e, "Failed to restore nuget packages in less than {time} seconds.", NugetRestoreTimeoutMs / 1000); + } + return false; + } + + private string FindMsBuildShortVersion(MsBuildHelper helper) + { + var msBuildVersionOutput = helper.GetVersion(); + string msBuildVersion; + if (string.IsNullOrWhiteSpace(msBuildVersionOutput)) + { + msBuildVersion = string.Empty; + _logger.LogInformation("Auto detected msbuild at: {MsBuildPath}, but failed to get version.", helper.GetMsBuildPath()); + } + else + { + msBuildVersion = msBuildVersionOutput.Trim(); + _logger.LogDebug("Auto detected msbuild version {MsBuildVersion} at: {MsBuildPath}", msBuildVersion, + helper.GetMsBuildPath()); } + + return msBuildVersion; } }