diff --git a/src/integrationTest/groovy/wooga/gradle/unity/UnityPluginIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/unity/UnityPluginIntegrationSpec.groovy index 94213111..f98febc4 100644 --- a/src/integrationTest/groovy/wooga/gradle/unity/UnityPluginIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/unity/UnityPluginIntegrationSpec.groovy @@ -20,7 +20,6 @@ package wooga.gradle.unity import com.wooga.spock.extensions.unity.UnityPathResolution import com.wooga.spock.extensions.unity.UnityPluginTestOptions import spock.lang.Unroll -import wooga.gradle.unity.models.BuildTarget import wooga.gradle.unity.models.UnityCommandLineOption import wooga.gradle.unity.tasks.Test import wooga.gradle.unity.utils.ProjectSettingsFile diff --git a/src/integrationTest/groovy/wooga/gradle/unity/UnityTaskIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/unity/UnityTaskIntegrationSpec.groovy index e0a8c607..7824ced7 100644 --- a/src/integrationTest/groovy/wooga/gradle/unity/UnityTaskIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/unity/UnityTaskIntegrationSpec.groovy @@ -21,6 +21,7 @@ import com.wooga.spock.extensions.unity.UnityPathResolution import com.wooga.spock.extensions.unity.UnityPluginTestOptions import com.wooga.spock.extensions.uvm.UnityInstallation import org.gradle.api.logging.LogLevel +import spock.lang.Ignore import spock.lang.IgnoreIf import spock.lang.Unroll import spock.util.environment.RestoreSystemProperties @@ -406,4 +407,22 @@ abstract class UnityTaskIntegrationSpec extends UnityIntegr logFile.text.contains(mockUnityStartupMessage) } + @Ignore + // TODO: How to make the task fail/throw within the exec block? + def "task action does not invoke post execute if process didn't run"() { + given: "a task that is definitely gonna fail" + appendToSubjectTask(""" + environment = null + """.stripIndent()) + + when: + def result = runTasks(subjectUnderTestName) + + then: + !result.success + outputContains(result, "${subjectUnderTestName}.preExecute") + outputContains(result, "${subjectUnderTestName}.execute") + !outputContains(result, "${subjectUnderTestName}.postExecute") + } + } diff --git a/src/main/groovy/wooga/gradle/unity/UnityPlugin.groovy b/src/main/groovy/wooga/gradle/unity/UnityPlugin.groovy index 7e63717b..0716b452 100644 --- a/src/main/groovy/wooga/gradle/unity/UnityPlugin.groovy +++ b/src/main/groovy/wooga/gradle/unity/UnityPlugin.groovy @@ -31,7 +31,6 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin import wooga.gradle.unity.models.APICompatibilityLevel import wooga.gradle.unity.models.DefaultUnityAuthentication import wooga.gradle.unity.internal.DefaultUnityPluginExtension -import wooga.gradle.unity.models.BuildTarget import wooga.gradle.unity.models.TestPlatform import wooga.gradle.unity.tasks.Activate @@ -39,8 +38,8 @@ import wooga.gradle.unity.tasks.ReturnLicense import wooga.gradle.unity.tasks.SetAPICompatibilityLevel import wooga.gradle.unity.tasks.Test import wooga.gradle.unity.utils.ProjectSettingsFile -import wooga.gradle.unity.utils.UnityTestTaskReport -import wooga.gradle.unity.utils.UnityTestTaskReportsImpl +import wooga.gradle.unity.utils.UnityLogErrorParse +import wooga.gradle.unity.utils.UnityLogErrorReader /** * A {@link org.gradle.api.Plugin} which provides tasks to run unity batch-mode commands. @@ -111,6 +110,7 @@ class UnityPlugin implements Plugin { extension.pluginsDir.convention(extension.assetsDir.dir("Plugins")) extension.logsDir.convention(UnityPluginConventions.logDirectory.getDirectoryValueProvider(project)) + extension.logErrorReader.convention(new UnityLogErrorReader()) extension.logCategory.convention(UnityPluginConventions.logCategory.getStringValueProvider(project)) final ReportingExtension reportingExtension = (ReportingExtension) project.extensions.getByName(ReportingExtension.NAME) extension.reportsDir.convention(project.layout.buildDirectory.dir(project.provider({ reportingExtension.file("unity").path }))) @@ -149,6 +149,7 @@ class UnityPlugin implements Plugin { t.projectDirectory.convention(extension.projectDirectory) t.projectSettings.convention(extension.projectSettings) t.logCategory.convention(extension.logCategory) + t.logErrorReader.convention(extension.logErrorReader) t.unityLogFile.convention(extension.logsDir.file(project.provider { t.logCategory.get().isEmpty() ? "${t.name}.log" : "${t.logCategory.get()}/${t.name}.log" diff --git a/src/main/groovy/wooga/gradle/unity/UnityPluginExtension.groovy b/src/main/groovy/wooga/gradle/unity/UnityPluginExtension.groovy index cf440c0b..66fea85e 100644 --- a/src/main/groovy/wooga/gradle/unity/UnityPluginExtension.groovy +++ b/src/main/groovy/wooga/gradle/unity/UnityPluginExtension.groovy @@ -24,7 +24,6 @@ import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.Internal -import wooga.gradle.unity.models.BuildTarget import wooga.gradle.unity.traits.APICompatibilityLevelSpec import wooga.gradle.unity.traits.UnityAuthenticationSpec import wooga.gradle.unity.traits.UnityLicenseSpec diff --git a/src/main/groovy/wooga/gradle/unity/UnityTask.groovy b/src/main/groovy/wooga/gradle/unity/UnityTask.groovy index 1515a7e6..eac681a1 100644 --- a/src/main/groovy/wooga/gradle/unity/UnityTask.groovy +++ b/src/main/groovy/wooga/gradle/unity/UnityTask.groovy @@ -27,13 +27,13 @@ import org.gradle.internal.io.LineBufferingOutputStream import org.gradle.internal.io.TextStream import org.gradle.process.ExecResult import org.gradle.process.ExecSpec -import sun.reflect.misc.FieldUtil import wooga.gradle.unity.models.UnityCommandLineOption import wooga.gradle.unity.traits.ArgumentsSpec import wooga.gradle.unity.traits.UnityCommandLineSpec import wooga.gradle.unity.traits.UnitySpec import wooga.gradle.unity.utils.FileUtils import wooga.gradle.unity.utils.ForkTextStream +import wooga.gradle.unity.utils.UnityLogErrorReader import wooga.gradle.unity.utils.UnityVersionManager abstract class UnityTask extends DefaultTask @@ -47,21 +47,24 @@ abstract class UnityTask extends DefaultTask // and also an additional one for our custom use wooga_gradle_unity_traits_ArgumentsSpec__arguments = project.provider({ getUnityCommandLineOptions() }) wooga_gradle_unity_traits_ArgumentsSpec__additionalArguments = project.objects.listProperty(String) - wooga_gradle_unity_traits_ArgumentsSpec__environment = project.objects.mapProperty(String, Object) + wooga_gradle_unity_traits_ArgumentsSpec__environment = project.objects.mapProperty(String, Object) } @TaskAction void exec() { + // Invoked before the unity process + logger.info("${name}.preExecute") + preExecute() + // Execute the unity process + logger.info("${name}.execute") ExecResult execResult = project.exec(new Action() { @Override void execute(ExecSpec exec) { + // TODO: Should these be moved before preExecute? if (!unityPath.present) { throw new GradleException("Unity path is not set") } - - preExecute() - def unityPath = unityPath.get().asFile.absolutePath def unityArgs = getAllArguments() def unityEnvironment = environment.get() @@ -76,8 +79,11 @@ abstract class UnityTask extends DefaultTask } } }) - - execResult.assertNormalExitValue() + if (execResult.exitValue != 0) { + handleUnityProcessError(execResult) + } + // Invoked after the unity process (even if it failed) + logger.info("${name}.postExecute") postExecute(execResult) } @@ -97,6 +103,31 @@ abstract class UnityTask extends DefaultTask protected void postExecute(ExecResult result) { } + /** + * Invoked whenever the Unity process executed by the task exits with an error, + * @param result The execution result of the Unity process + */ + protected void handleUnityProcessError(ExecResult result) { + logger.error("Unity process failed with exit value ${result.exitValue}...") + + // Look up the log + if (!unityLogFile.isPresent()) { + logger.warn("No log file was configured for the task ${this.name}") + return + } + + File logFile = unityLogFile.get().asFile + if (!logFile.exists()) { + logger.warn("No log file was written for the task ${this.name}") + return + } + + // TODO: Gracefully show the error here? + UnityLogErrorReader reader = new UnityLogErrorReader() + def errorParse = reader.parse(logFile) + logger.error(errorParse.toString()) + } + @Internal protected ArtifactVersion getUnityVersion() { File file = unityPath.present ? unityPath.get().asFile : null diff --git a/src/main/groovy/wooga/gradle/unity/traits/UnitySpec.groovy b/src/main/groovy/wooga/gradle/unity/traits/UnitySpec.groovy index 3b14bce2..38f9ab16 100644 --- a/src/main/groovy/wooga/gradle/unity/traits/UnitySpec.groovy +++ b/src/main/groovy/wooga/gradle/unity/traits/UnitySpec.groovy @@ -16,25 +16,17 @@ package wooga.gradle.unity.traits -import org.gradle.api.model.ObjectFactory import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider -import org.gradle.api.provider.ProviderFactory -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.SkipWhenEmpty -import org.gradle.internal.impldep.org.eclipse.jgit.errors.NotSupportedException -import wooga.gradle.unity.UnityPluginConventions -import wooga.gradle.unity.models.BuildTarget import wooga.gradle.unity.utils.ProjectSettingsFile +import wooga.gradle.unity.utils.UnityLogErrorReader import javax.inject.Inject @@ -115,5 +107,14 @@ trait UnitySpec extends UnityBaseSpec { logToStdout } + private final Property logErrorReader = objects.property(UnityLogErrorReader) + /** + * @return The reader used for parsing the Unity Editor log whenever the exits with a failure code + */ + @Internal + Property getLogErrorReader(){ + logErrorReader + } + } diff --git a/src/main/groovy/wooga/gradle/unity/utils/UnityLogErrorReader.groovy b/src/main/groovy/wooga/gradle/unity/utils/UnityLogErrorReader.groovy index 3752b2ee..4adc2d2c 100644 --- a/src/main/groovy/wooga/gradle/unity/utils/UnityLogErrorReader.groovy +++ b/src/main/groovy/wooga/gradle/unity/utils/UnityLogErrorReader.groovy @@ -17,37 +17,172 @@ package wooga.gradle.unity.utils +import java.util.regex.Matcher + +enum UnityLogErrorType { + /** + * No error was found + */ + None, + /** + * The error could not be parsed + */ + Unknown, + /** + * The Unity scripts have compiler errors + */ + ScriptCompilerError, + /** + * The build failed + */ + BuildFailure, + /** + * Tests failed + */ + TestFailure +} + +class UnityLogErrorParse { + UnityLogErrorType type + String message + List compilerOutput + + @Override + String toString() { + def result = "${type}:" + switch (type) { + case UnityLogErrorType.ScriptCompilerError: + compilerOutput.forEach({ l -> + result += "\n${l.text}" + }) + break + } + result + } +} + +class CSharpFileCompilationResult { + String text + String filePath + Integer line + Integer column + String level + String code + String message + + CSharpFileCompilationResult(String filePath, Integer line, Integer column, String level, String code, String message) { + this.filePath = filePath + this.line = line + this.column = column + this.level = level + this.code = code + this.message = message + } + + CSharpFileCompilationResult(String text, String filePath, Integer line, Integer column, String level, String code, String message) { + this.text = text + this.filePath = filePath + this.line = line + this.column = column + this.level = level + this.code = code + this.message = message + } + + CSharpFileCompilationResult() { + } + + // e.g: "A/B.cs(9,7): warning CS0105: WRONG!" + static String pattern = /(?.+)\((?\d+),(?\d+)\):\s(?.*?)\s(?.+):\s(?.*)/ + + static CSharpFileCompilationResult Parse(String text) { + Matcher matcher = (text =~ pattern) + if (matcher.count == 0) { + return null + } + + def (all, filePath, line, column, level, code, message) = matcher[0] + CSharpFileCompilationResult result = new CSharpFileCompilationResult() + result.text = all + result.filePath = filePath + result.line = Integer.parseInt(line) + result.column = Integer.parseInt(column) + result.level = level + result.code = code + result.message = message + result + } +} + +// TODO: Perhaps named Parser? +/** + * Given a valid Unity Editor log file that was written to, + * parses it for errors that can be viewed by an user + * (by default, Editor.log) + */ class UnityLogErrorReader { - static String DEFAULT_MESSAGE = "no error" + static String compilerOutputStartMarker = "-----CompilerOutput:" + static String compilerOutputEndMarker = "-----EndCompilerOutput" + static String compilerErrorMarker = "Scripts have compiler errors." + static String errorMarker = "Aborting batchmode due to failure:" + static String dialogError = "Cancelling DisplayDialog:" - static String readErrorMessageFromLog(File logfile) { - def message = DEFAULT_MESSAGE - if(!logfile || !logfile.exists()) { - return message + UnityLogErrorParse parse(File logfile) { + + UnityLogErrorParse parse = new UnityLogErrorParse() + parse.type = UnityLogErrorType.None + + if (!logfile || !logfile.exists()) { + return parse } + boolean foundCompilerMarker = false boolean foundErrorMarker = false - String errorMarker = "Aborting batchmode due to failure:" - String dialogError = "Cancelling DisplayDialog:" + parse.compilerOutput = [] String line + Integer lineNumber = 0 + + // Read through the log file logfile.withReader { reader -> - while ((line = reader.readLine())!=null) { - if(foundErrorMarker) { - message = line - break - } - if(line.startsWith(errorMarker)) { - foundErrorMarker = true - } + while ((line = reader.readLine()) != null) { + lineNumber++ - if(line.startsWith(dialogError)) { - message = line.replace(dialogError, "").trim() - break + // If inside a compiler marker, parse the compiler output + if (foundCompilerMarker) { + // Finished reading compiler output + if (line.startsWith(compilerOutputEndMarker)) { + foundCompilerMarker = false + } + // Record all warnings/errors + else { + CSharpFileCompilationResult fileCompilationResult = CSharpFileCompilationResult.Parse(line) + if (fileCompilationResult != null) { + parse.compilerOutput.add(fileCompilationResult) + } + } + } else if (foundErrorMarker) { + if (line.startsWith(compilerErrorMarker)) { + parse.type = UnityLogErrorType.ScriptCompilerError + break + } else { + parse.message = line + } + } + // Look for markers + else { + // The error marker is found near the end of the log output + if (line.startsWith(errorMarker)) { + parse.type = UnityLogErrorType.Unknown + foundErrorMarker = true + } + // Started reading through C# compiler output + else if (line.startsWith(compilerOutputStartMarker)) { + foundCompilerMarker = true + } } } } - - message + parse } } diff --git a/src/test/groovy/wooga/gradle/unity/utils/UnityErrorLogReaderTest.groovy b/src/test/groovy/wooga/gradle/unity/utils/UnityErrorLogReaderTest.groovy index 36c2d2c6..0e20951d 100644 --- a/src/test/groovy/wooga/gradle/unity/utils/UnityErrorLogReaderTest.groovy +++ b/src/test/groovy/wooga/gradle/unity/utils/UnityErrorLogReaderTest.groovy @@ -18,12 +18,19 @@ package wooga.gradle.unity.utils import spock.lang.Specification +import spock.lang.Unroll class UnityErrorLogReaderTest extends Specification { + UnityLogErrorReader reader + + def setup(){ + reader = new UnityLogErrorReader() + } + def "reads error message from logfile"() { given: "logfile with error message" - def log = File.createTempFile("log","log") + def log = File.createTempFile("log", "log") log << """ Reloading assemblies after script compilation. Validating Project structure ... 0.005520 seconds. @@ -45,16 +52,16 @@ class UnityErrorLogReaderTest extends Specification { (Filename: /Users/builduser/buildslave/unity/build/Runtime/Threads/Posix/PlatformThread.cpp Line: 38) """.stripIndent() - when:"parsing error message" - def message = UnityLogErrorReader.readErrorMessageFromLog(log) + when: "parsing error message" + def message = reader.parse(log) then: - message == "Scripts have compiler errors." + message.type == UnityLogErrorType.ScriptCompilerError } def "returns default message when error marker is not included"() { given: "logfile with no error message" - def log = File.createTempFile("log","log") + def log = File.createTempFile("log", "log") log << """ Reloading assemblies after script compilation. Validating Project structure ... 0.005520 seconds. @@ -72,21 +79,194 @@ class UnityErrorLogReaderTest extends Specification { (Filename: /Users/builduser/buildslave/unity/build/Runtime/Threads/Posix/PlatformThread.cpp Line: 38) """.stripIndent() - when:"parsing error message" - def message = UnityLogErrorReader.readErrorMessageFromLog(log) + when: "parsing error message" + def message = reader.parse(log) then: - message == UnityLogErrorReader.DEFAULT_MESSAGE + message.type == UnityLogErrorType.None } def "returns default message log file doesn't exist"() { given: "path to nonexisting logfile" def log = new File("test.log") - when:"parsing error message" - def message = UnityLogErrorReader.readErrorMessageFromLog(log) + when: "parsing error message" + def message = reader.parse(log) then: - message == UnityLogErrorReader.DEFAULT_MESSAGE + message.type == UnityLogErrorType.None } + + def "finds script compiler errors"() { + given: "logfile with compiler errors" + def log = File.createTempFile("log", "log") + log << """ +-----CompilerOutput:-stdout--exitcode: 1--compilationhadfailure: True--outfile: Temp/Assembly-CSharp-Editor.dll + +Microsoft (R) Visual C# Compiler version 2.9.1.65535 (9d34608e) + +Copyright (C) Microsoft Corporation. All rights reserved. + +Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/BuildStepTest.cs(9,7): warning CS0105: The using directive for 'Wooga.UnifiedBuildSystem.Editor' appeared previously in this namespace +Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/GroupedBuildStepTest.cs(9,39): error CS0234: The type or namespace name 'Tests' does not exist in the namespace 'Wooga.UnifiedBuildSystem.Editor' (are you missing an assembly reference?) +Assets/Wooga/UnifiedBuildSystem/Samples/Editor/BuildExamples.cs(13,45): warning CS0618: 'BuildStep.RunAfter' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Samples/Editor/BuildExamples.cs(16,45): warning CS0618: 'BuildStep.RunBefore' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Editor/AppConfig/AppConfig.ISerializationCallbackReceiver.cs(7,21): warning CS0114: 'AppConfig.OnBeforeSerialize()' hides inherited member 'BuildConfigScriptable.OnBeforeSerialize()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. +Assets/Wooga/UnifiedBuildSystem/Editor/AppConfig/AppConfig.ISerializationCallbackReceiver.cs(23,21): warning CS0114: 'AppConfig.OnAfterDeserialize()' hides inherited member 'BuildConfigScriptable.OnAfterDeserialize()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. +Assets/Wooga/UnifiedBuildSystem/Editor/Build/Build.ExportProject.cs(9,41): warning CS0618: 'BuildStep.RunBefore' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Editor/Build/Build.PostBuildAndroid.cs(8,46): warning CS0618: 'BuildStep.RunAfter' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Editor/Build/Build.PostBuildAndroid.cs(8,83): warning CS0618: 'BuildStep.RunBefore' is obsolete: 'This ordering is planned to be deprecated. ' + +-----CompilerOutput:-stderr---------- + +-----EndCompilerOutput--------------- + +- Finished script compilation in 7.715436 seconds + +Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/BuildStepTest.cs(9,7): warning CS0105: The using directive for 'Wooga.UnifiedBuildSystem.Editor' appeared previously in this namespace +Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/GroupedBuildStepTest.cs(9,39): error CS0234: The type or namespace name 'Tests' does not exist in the namespace 'Wooga.UnifiedBuildSystem.Editor' (are you missing an assembly reference?) +Assets/Wooga/UnifiedBuildSystem/Samples/Editor/BuildExamples.cs(13,45): warning CS0618: 'BuildStep.RunAfter' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Samples/Editor/BuildExamples.cs(16,45): warning CS0618: 'BuildStep.RunBefore' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Editor/AppConfig/AppConfig.ISerializationCallbackReceiver.cs(7,21): warning CS0114: 'AppConfig.OnBeforeSerialize()' hides inherited member 'BuildConfigScriptable.OnBeforeSerialize()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. +Assets/Wooga/UnifiedBuildSystem/Editor/AppConfig/AppConfig.ISerializationCallbackReceiver.cs(23,21): warning CS0114: 'AppConfig.OnAfterDeserialize()' hides inherited member 'BuildConfigScriptable.OnAfterDeserialize()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. +Assets/Wooga/UnifiedBuildSystem/Editor/Build/Build.ExportProject.cs(9,41): warning CS0618: 'BuildStep.RunBefore' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Editor/Build/Build.PostBuildAndroid.cs(8,46): warning CS0618: 'BuildStep.RunAfter' is obsolete: 'This ordering is planned to be deprecated. ' +Assets/Wooga/UnifiedBuildSystem/Editor/Build/Build.PostBuildAndroid.cs(8,83): warning CS0618: 'BuildStep.RunBefore' is obsolete: 'This ordering is planned to be deprecated. ' + +Unloading 1218 Unused Serialized files (Serialized files now loaded: 0) +System memory in use before: 321.0 MB. +System memory in use after: 321.2 MB. + +... + +Unloading 1798 Unused Serialized files (Serialized files now loaded: 0) +System memory in use before: 348.5 MB. +System memory in use after: 347.6 MB. + +Unloading 1814 unused Assets to reduce memory usage. Loaded Objects now: 1668. +Total: 7.968787 ms (FindLiveObjects: 0.574456 ms CreateObjectMapping: 0.243863 ms MarkObjects: 4.823242 ms DeleteObjects: 2.326409 ms) + +Disconnect from CacheServer +Refreshing native plugins compatible for Editor in 4.99 ms, found 0 plugins. +Preloading 0 native plugins for Editor in 0.00 ms. +Warming cache for 1797 main assets: 0.003021 seconds elapsed + +Initializing Unity extensions: + + '/Users/jenkins_agent/Applications/Unity/Hub/Editor/2019.4.19f1/Unity.app/Contents/UnityExtensions/Unity/UnityVR/Editor/UnityEditor.VR.dll' GUID: 4ba2329b63d54f0187bcaa12486b1b0f + +Unloading 53 Unused Serialized files (Serialized files now loaded: 0) + +System memory in use before: 309.1 MB. +System memory in use after: 309.1 MB. +Unloading 56 unused Assets to reduce memory usage. Loaded Objects now: 1678. +Total: 5.620424 ms (FindLiveObjects: 0.363267 ms CreateObjectMapping: 0.103867 ms MarkObjects: 5.024895 ms DeleteObjects: 0.127224 ms) + + +Scripts have compiler errors. +(Filename: ./Runtime/Utilities/Argv.cpp Line: 376) + +Aborting batchmode due to failure: +Scripts have compiler errors. + +[Package Manager] Server::Kill -- Server was shutdown + +(lldb) command source -s 0 '/tmp/mono-gdb-commands.Fr24P1' + + +> Task :Wooga.UnifiedBuildSystem:exportUnityPackage FAILED +> Task :Wooga.UnifiedBuildSystem:returnUnityLicense SKIPPED +> Task :Wooga.UnifiedBuildSystem:unsetAPICompatibilityLevel SKIPPED + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':Wooga.UnifiedBuildSystem:exportUnityPackage'. + +> Unity batchmode finished with non-zero exit value 1 and error 'Scripts have compiler errors.' + +* Try: + +Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. + +* Get more help at https://help.gradle.org + +Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0. +Use '--warning-mode all' to show the individual deprecation warnings. +See https://docs.gradle.org/4.10.2/userguide/command_line_interface.html#sec:command_line_warnings + +BUILD FAILED in 2m 24s +10 actionable tasks: 9 executed, 1 up-to-date + +""" + when: "parsing error message" + def message = reader.parse(log) + + then: + message.type == UnityLogErrorType.ScriptCompilerError + message.compilerOutput.size() == 9 + message.compilerOutput[0].properties == new CSharpFileCompilationResult( + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/BuildStepTest.cs(9,7): warning CS0105: The using directive for 'Wooga.UnifiedBuildSystem.Editor' appeared previously in this namespace", + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/BuildStepTest.cs", + 9, + 7, + "warning", + "CS0105", + "The using directive for 'Wooga.UnifiedBuildSystem.Editor' appeared previously in this namespace" + ).properties + + } + + @Unroll("parses #testCase[0]") + def "parses csharp file compilation result"() { + given: + def input = testCase[0] + def expected = testCase[1] + + when: + def result = CSharpFileCompilationResult.Parse(input) + + then: + result != null + result.properties == expected.properties + + where: + testCase << [ + [ + "A/B.cs(9,7): warning CS0105: WRONG!", + new CSharpFileCompilationResult( + "A/B.cs(9,7): warning CS0105: WRONG!", + "A/B.cs", + 9, + 7, + "warning", + "CS0105", + "WRONG!") + ], + [ + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/BuildStepTest.cs(9,7): warning CS0105: The using directive for 'Wooga.UnifiedBuildSystem.Editor' appeared previously in this namespace", + new CSharpFileCompilationResult( + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/BuildStepTest.cs(9,7): warning CS0105: The using directive for 'Wooga.UnifiedBuildSystem.Editor' appeared previously in this namespace", + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/BuildStepTest.cs", + 9, + 7, + "warning", + "CS0105", + "The using directive for 'Wooga.UnifiedBuildSystem.Editor' appeared previously in this namespace") + ], + [ + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/GroupedBuildStepTest.cs(9,39): error CS0234: The type or namespace name 'Tests' does not exist in the namespace 'Wooga.UnifiedBuildSystem.Editor' (are you missing an assembly reference?)", + new CSharpFileCompilationResult( + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/GroupedBuildStepTest.cs(9,39): error CS0234: The type or namespace name 'Tests' does not exist in the namespace 'Wooga.UnifiedBuildSystem.Editor' (are you missing an assembly reference?)", + "Assets/Wooga/UnifiedBuildSystem/Tests/Editor/BuildEngine/GroupedBuildStepTest.cs", + 9, + 39, + "error", + "CS0234", + "The type or namespace name 'Tests' does not exist in the namespace 'Wooga.UnifiedBuildSystem.Editor' (are you missing an assembly reference?)") + ], + ] + + } + }