diff --git a/build.gradle b/build.gradle index 255f7b3..6bde4e1 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,9 @@ github { dependencies { api 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.2.0' + implementation 'net.wooga.gradle:dotnet:0.3.0' implementation 'net.wooga.gradle:github:[3,4[' testImplementation 'com.wooga.spock.extensions:spock-github-extension:0.4.0' testImplementation 'org.ajoberstar.grgit:grgit-core:4.+' + testImplementation 'com.wooga.gradle:gradle-commons-test:[2,3)' } diff --git a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/SonarScannerExtensionIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/SonarScannerExtensionIntegrationSpec.groovy index 6329cee..c310e66 100644 --- a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/SonarScannerExtensionIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/SonarScannerExtensionIntegrationSpec.groovy @@ -16,10 +16,10 @@ package wooga.gradle.dotnetsonar +import com.wooga.gradle.test.executable.FakeExecutables import spock.lang.Unroll import wooga.gradle.dotnetsonar.tasks.internal.SonarScannerInstaller import wooga.gradle.dotnetsonar.tasks.utils.PluginIntegrationSpec -import wooga.gradle.dotnetsonar.utils.SpecFakes import static wooga.gradle.dotnetsonar.tasks.internal.SonarScannerInstaller.defaultBaseURL import static wooga.gradle.dotnetsonar.utils.SpecUtils.* @@ -27,14 +27,13 @@ import static wooga.gradle.dotnetsonar.utils.SpecUtils.* class SonarScannerExtensionIntegrationSpec extends PluginIntegrationSpec { def "registers custom build task for sonar scanner"() { - given: "a sonnar scanner executable" - File fakeScannerExec = SpecFakes.argReflectingFakeExecutable("sonarscanner") + given: "a sonar scanner executable" + def fakeScanner = FakeExecutables.argsReflector("sonarscanner", 0) and: "custom task registering itself on sonar scanner extension" buildFile << """ - ${forceAddObjectsToExtension(fakeScannerExec)} - ${getSonarScannerExtension("sonarScannerExt")} + ${forceAddObjectsToExtension(fakeScanner.executable)} tasks.register("custom") { - sonarScannerExt.registerBuildTask(it) + sonarScanner.registerBuildTask(it) } """ when: "executing custom task" @@ -53,16 +52,19 @@ class SonarScannerExtensionIntegrationSpec extends PluginIntegrationSpec { and: "unset sonarScannerExecutable property in the extension" when: "running tasks dependent on sonar scanner executable" - runTasks("sonarScannerBegin") + def result = runTasks("sonarScannerBegin") then: "dotnet sonar scanner package should be installed at default directory" - def defaultInstallDir = "build/bin/net-sonarscanner/" - new File(projectDir, - "${defaultInstallDir}/${SonarScannerInstaller.EXECUTABLE_NAME}").exists() + result.wasExecuted(":installSonarScanner") + def defaultInstallDir = "build/bin/net-sonarscanner/${defaultVersion}-netcoreapp2.0" + new File(projectDir, "${defaultInstallDir}/${SonarScannerInstaller.DLL_NAME}").exists() + + where: + defaultVersion = DotNetSonarqubePluginConventions.scannerInstallVersion.defaultValue.toString() } @Unroll - def "installs sonar scanner version #version-net46 in #installDir"() { + def "installs sonar scanner version #version-netcoreapp2.0 in #installDir"() { given: "installed dotnet sonarscanner plugin" and: "no pre-existent sonarscanner executable on PATH" and: "configured sonar scanner extension" @@ -70,16 +72,17 @@ class SonarScannerExtensionIntegrationSpec extends PluginIntegrationSpec { sonarScanner { installInfo { version = "${version}" - installDir = "${installDir}" + installDir = ${wrapValueBasedOnType(installDir, File)} } } """ when: "running tasks dependent on sonar scanner executable" - runTasks("sonarScannerBegin") + def result = runTasks("sonarScannerBegin") then: "dotnet sonar scanner package should be installed at default directory" + result.wasExecuted(":installSonarScanner") new File(projectDir, - "${installDir}/${SonarScannerInstaller.EXECUTABLE_NAME}").exists() + "${installDir}/${SonarScannerInstaller.DLL_NAME}").exists() where: version | installDir "5.2.2.33595" | "bin/fdlr" @@ -95,15 +98,16 @@ class SonarScannerExtensionIntegrationSpec extends PluginIntegrationSpec { buildFile << """ sonarScanner { installInfo { - sourceURL = "${url}" - installDir = "${installDir}" + installURL = "${url}" + installDir = ${wrapValueBasedOnType(installDir, File)} } } """ when: "running tasks dependent on sonar scanner executable" - runTasks("sonarScannerBegin") + def result = runTasks("sonarScannerBegin") then: "dotnet sonar scanner package should be installed at default directory" + result.wasExecuted(":installSonarScanner") new File(projectDir, "${installDir}/${SonarScannerInstaller.EXECUTABLE_NAME}").exists() where: @@ -115,10 +119,10 @@ class SonarScannerExtensionIntegrationSpec extends PluginIntegrationSpec { def "doesn't install sonar scanner if executable already exists on extension"() { given: "installed dotnet sonarscanner plugin" and: "pre-existent sonarscanner executable" - def sonarScannerExec = SpecFakes.argReflectingFakeExecutable("sonarscanner.bat") + def sonarScannerExec = FakeExecutables.argsReflector("sonarscanner.bat", 0) buildFile << """ sonarScanner { - sonarScannerExecutable = ${wrapValueBasedOnType(sonarScannerExec.absolutePath, File)} + sonarScannerExecutable = ${wrapValueBasedOnType(sonarScannerExec.executable.absolutePath, File)} installInfo { version = "5.2.1.31210" } @@ -126,9 +130,10 @@ class SonarScannerExtensionIntegrationSpec extends PluginIntegrationSpec { """ when: "running tasks dependent on sonar scanner executable" - runTasks("sonarScannerBegin") + def result = runTasks("sonarScannerBegin") then: "sonar scanner should not be downloaded" + result.standardOutput.contains(":installSonarScanner SKIPPED") def defaultInstallDir = "build/bin/net-sonarscanner/" !new File(projectDir, "${defaultInstallDir}/${SonarScannerInstaller.EXECUTABLE_NAME}").exists() diff --git a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolutionTaskIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolutionTaskIntegrationSpec.groovy index cbf7a0e..64f4c92 100644 --- a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolutionTaskIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolutionTaskIntegrationSpec.groovy @@ -16,28 +16,27 @@ package wooga.gradle.dotnetsonar.tasks -import org.gradle.process.internal.ExecException +import com.wooga.gradle.test.executable.FakeExecutables +import org.gradle.api.GradleException import spock.lang.Unroll import wooga.gradle.dotnetsonar.tasks.utils.PluginIntegrationSpec import java.nio.file.Paths -import static wooga.gradle.dotnetsonar.utils.FakeExecutable.executionResults -import static wooga.gradle.dotnetsonar.utils.SpecFakes.argReflectingFakeExecutable import static wooga.gradle.dotnetsonar.utils.SpecUtils.rootCause import static wooga.gradle.dotnetsonar.utils.SpecUtils.wrapValueBasedOnType class BuildSolutionTaskIntegrationSpec extends PluginIntegrationSpec { def setup() { - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + def fakeSonarScanner = FakeExecutables.argsReflector("sonarscanner", 0) + buildFile << forceAddObjectsToExtension(fakeSonarScanner.executable) } @Unroll def "Builds a C# solution with dotnet #subtool #extraArgs command"() { given: "a msbuild executable" - def fakeBuildExec = argReflectingFakeExecutable("dotnet", 0) + def fakeBuild = FakeExecutables.argsReflector("dotnet-build", 0) and: "fake solution file" new File(projectDir, solutionPath).with { parentFile.mkdirs() @@ -46,18 +45,19 @@ class BuildSolutionTaskIntegrationSpec extends PluginIntegrationSpec { and: "build file with configured task" buildFile << """ project.tasks.create("solutionBuild", ${BuildSolution.name}) { - dotnetExecutable = ${wrapValueBasedOnType(fakeBuildExec.absolutePath, File)} + executable = ${wrapValueBasedOnType(fakeBuild.executable.absolutePath, File)} solution = ${wrapValueBasedOnType(solutionPath, File)} environment = ${wrapValueBasedOnType(environment, Map)} - extraArgs = ${wrapValueBasedOnType(extraArgs, List)} + additionalArguments.addAll(${wrapValueBasedOnType(extraArgs, List)}) } """ when: def result = runTasksSuccessfully("solutionBuild") then: - def buildResult = executionResults(fakeBuildExec, result) - buildResult.args == subtool + [Paths.get(projectDir.absolutePath, solutionPath).toString()] + extraArgs + def buildResult = fakeBuild.firstResult(result.standardOutput) + def args = [Paths.get(projectDir.absolutePath, solutionPath).toString()] + extraArgs + buildResult.args == subtool + args buildResult.envs.entrySet().containsAll(environment.entrySet()) where: @@ -66,43 +66,10 @@ class BuildSolutionTaskIntegrationSpec extends PluginIntegrationSpec { "dir/solution.sln" | ["build"] | ["b": "c"] | ["-arg", "/arg:value"] } - - @Unroll - def "Builds a C# solution with msbuild #extraArgs command"() { - given: "a msbuild executable" - def fakeBuildExec = argReflectingFakeExecutable("msBuild", 0) - and: "fake solution file" - new File(projectDir, solutionPath).with { - parentFile.mkdirs() - createNewFile() - } - and: "build file with configured task" - buildFile << """ - project.tasks.create("solutionBuild", ${BuildSolution.name}) { - msBuildExecutable = ${wrapValueBasedOnType(fakeBuildExec.absolutePath, File)} - solution = ${wrapValueBasedOnType(solutionPath, File)} - environment = ${wrapValueBasedOnType(environment, Map)} - extraArgs = ${wrapValueBasedOnType(extraArgs, List)} - } - """ - when: - def result = runTasksSuccessfully("solutionBuild") - - then: - def buildResult = executionResults(fakeBuildExec, result) - buildResult.args == extraArgs + [Paths.get(projectDir.absolutePath, solutionPath).toString()] - buildResult.envs.entrySet().containsAll(environment.entrySet()) - - where: - solutionPath | environment | extraArgs - "solution.sln" | ["a": "b"] | [] - "solution.sln" | [:] | ["-arg", "/arg:value"] - } - @Unroll - def "#tool build task fails if tool returns non-zero status"() { + def "BuildSolution task fails if tool returns non-zero status"() { given: "a build executable" - def fakeMsBuildExec = argReflectingFakeExecutable(tool, 1) + def fakeDotnet = FakeExecutables.argsReflector("dotnet", 1) and: "fake solution file" new File(projectDir, solutionPath).with { parentFile.mkdirs() @@ -111,7 +78,7 @@ class BuildSolutionTaskIntegrationSpec extends PluginIntegrationSpec { and: "build file with configured task" buildFile << """ project.tasks.create("solutionBuild", ${BuildSolution.name}) { - ${tool}Executable = ${wrapValueBasedOnType(fakeMsBuildExec.absolutePath, File)} + executable = ${wrapValueBasedOnType(fakeDotnet.executable.absolutePath, File)} solution = ${wrapValueBasedOnType(solutionPath, File)} } """ @@ -120,11 +87,9 @@ class BuildSolutionTaskIntegrationSpec extends PluginIntegrationSpec { then: "should fail on execution with non-zero exit value" def e = rootCause(result.failure) - e.getClass().name == ExecException.name - e.message.contains(fakeMsBuildExec.absolutePath) + e.getClass().name == GradleException.name e.message.contains("exit value 1") where: - tool << ["msBuild", "dotnet"] solutionPath = "solution.sln" } } diff --git a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBeginTaskIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBeginTaskIntegrationSpec.groovy index a256202..3218822 100644 --- a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBeginTaskIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBeginTaskIntegrationSpec.groovy @@ -16,17 +16,15 @@ package wooga.gradle.dotnetsonar.tasks +import com.wooga.gradle.test.executable.FakeExecutables import com.wooga.spock.extensions.github.GithubRepository import com.wooga.spock.extensions.github.Repository import com.wooga.spock.extensions.github.api.RateLimitHandlerWait import com.wooga.spock.extensions.github.api.TravisBuildNumberPostFix import org.ajoberstar.grgit.Grgit -import org.gradle.process.internal.ExecException +import org.gradle.api.GradleException import spock.lang.Unroll import wooga.gradle.dotnetsonar.tasks.utils.PluginIntegrationSpec -import wooga.gradle.dotnetsonar.utils.FakeExecutable - -import static wooga.gradle.dotnetsonar.utils.SpecFakes.argReflectingFakeExecutable class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { @@ -39,9 +37,9 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { ) def "task executes sonar scanner tool begin command with git-based properties"(Repository testRepo) { given: "a sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) + def fakeSonarScannerExec = FakeExecutables.argsReflector("sonarscanner", 0) and: "a set up sonar scanner extension" - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + buildFile << forceAddObjectsToExtension(fakeSonarScannerExec.executable) and: "a set up github extension" buildFile << """ github { @@ -55,7 +53,7 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { def result = runTasksSuccessfully("sonarScannerBegin") then: - def execResults = FakeExecutable.lastExecutionResults(result) + def execResults = fakeSonarScannerExec.firstResult(result.standardOutput) def companyName = testRepo.fullName.split("/")[0] execResults.args.contains("-n:${testRepo.name}".toString()) execResults.args.contains("-k:${companyName}_${testRepo.name}".toString()) @@ -63,32 +61,32 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { def "task sets branch property name accordingly with its PR or non-PR status"() { given: "a sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) + def fakeSonarScanner = FakeExecutables.argsReflector("sonarscanner", 0) and: "a set up sonar scanner extension" - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + buildFile << forceAddObjectsToExtension(fakeSonarScanner.executable) when: def result = runTasksSuccessfully("sonarScannerBegin") then: - def execResults = FakeExecutable.lastExecutionResults(result) - if(expectedBranchProperty) { + def execResults = fakeSonarScanner.firstResult(result.standardOutput) + if (expectedBranchProperty) { execResults.args.contains("-d:sonar.branch.name=${expectedBranchProperty}".toString()) } else { !execResults.args.contains("-d:sonar.branch.name") } where: branchName | expectedBranchProperty - "name" | "name" - "PR-10" | null - "PR-fe" | "PR-fe" + "name" | "name" + "PR-10" | null + "PR-fe" | "PR-fe" } def "task executes sonar scanner tool begin command with extension properties"() { given: "a sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) + def fakeSonarScanner = FakeExecutables.argsReflector("sonarscanner", 0) and: "a set up sonar scanner extension" - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + buildFile << forceAddObjectsToExtension(fakeSonarScanner.executable) and: "a configured github extension" def companyName = "company" @@ -120,7 +118,7 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { def result = runTasksSuccessfully("sonarScannerBegin") then: - def execResults = FakeExecutable.lastExecutionResults(result) + def execResults = fakeSonarScanner.firstResult(result.standardOutput) execResults.args.contains("-n:${repoName}".toString()) execResults.args.contains("-k:${companyName}_${repoName}".toString()) execResults.args.contains("-v:${projectVersion}".toString()) @@ -132,12 +130,11 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { def "task executes sonar scanner tool begin command with task properties"() { given: "a sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) + def fakeSonarScanner = FakeExecutables.argsReflector("sonarscanner", 0) and: "a set up sonar scanner task" + buildFile << forceAddObjectsToExtension(fakeSonarScanner.executable) buildFile << """ - ${createSonarScannerFromExecutable("scanner", fakeSonarScannerExec)} sonarScannerBegin { - sonarScanner.set(scanner) sonarqubeProperties.put("sonar.projectKey", "key") sonarqubeProperties.put("sonar.projectName", "name") sonarqubeProperties.put("sonar.version", "0.0.1") @@ -148,7 +145,7 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { when: "running the sonarScannerBegin task" def result = runTasksSuccessfully("sonarScannerBegin") then: - def execResults = FakeExecutable.lastExecutionResults(result) + def execResults = fakeSonarScanner.firstResult(result.standardOutput) execResults.args.contains("-k:key") execResults.args.contains("-v:0.0.1") execResults.args.contains("-n:name") @@ -159,14 +156,13 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { @Unroll def "task fails #key property isn't present"() { given: "a sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) + def fakeSonarScanner = FakeExecutables.argsReflector("sonarscanner", 0) and: "a set up sonar scanner task without mandatory properties" + buildFile << forceAddObjectsToExtension(fakeSonarScanner.executable) buildFile << """ - ${createSonarScannerFromExecutable("scanner", fakeSonarScannerExec)} sonarScannerBegin { - sonarScanner.set(scanner) - ${key=="sonar.projectKey"? - """sonarqubeProperties.put("sonar.version", "val")""": + ${key == "sonar.projectKey" ? + """sonarqubeProperties.put("sonar.version", "val")""" : """sonarqubeProperties.put("sonar.projectKey", "val")"""} sonarqubeProperties.put("sonar.exclusions", "src") sonarqubeProperties.put("sonar.prop", "value") @@ -178,7 +174,7 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { then: def e = rootCause(result.failure) e instanceof IllegalArgumentException - e.message == "SonarqubeBegin needs a set ${key} property" + e.message == "SonarScannerBegin task needs a set ${key} property" where: key << ["sonar.projectKey", "sonar.version"] @@ -186,16 +182,16 @@ class SonarScannerBeginTaskIntegrationSpec extends PluginIntegrationSpec { def "task fails if sonar scanner tool begin command returns non-zero status"() { given: "a failing sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 1) + def fakeSonarScanner = FakeExecutables.argsReflector("sonarscanner", 1) and: "a set up sonar scanner extension" - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + buildFile << forceAddObjectsToExtension(fakeSonarScanner.executable) when: "running the sonarScannerBegin task" def result = runTasksWithFailure("sonarScannerBegin") then: "should fail on execution with non-zero exit value" def e = rootCause(result.failure) - e.getClass().name == ExecException.name + e.getClass().name == GradleException.name e.message.contains("exit value 1") } } diff --git a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEndTaskIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEndTaskIntegrationSpec.groovy index b607990..d449c96 100644 --- a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEndTaskIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEndTaskIntegrationSpec.groovy @@ -16,11 +16,10 @@ package wooga.gradle.dotnetsonar.tasks -import org.gradle.process.internal.ExecException +import com.wooga.gradle.test.executable.FakeExecutables +import org.gradle.api.GradleException import wooga.gradle.dotnetsonar.tasks.utils.PluginIntegrationSpec -import wooga.gradle.dotnetsonar.utils.FakeExecutable -import static wooga.gradle.dotnetsonar.utils.SpecFakes.argReflectingFakeExecutable import static wooga.gradle.dotnetsonar.utils.SpecUtils.rootCause class SonarScannerEndTaskIntegrationSpec extends PluginIntegrationSpec { @@ -28,9 +27,9 @@ class SonarScannerEndTaskIntegrationSpec extends PluginIntegrationSpec { def "executes sonar scanner tool end command with extension properties"() { given: "a applied dotnet sonar scanner plugin" and: "a sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) + def fakeSonarScannerExec = FakeExecutables.argsReflector("sonarscanner", 0) and: "a set up sonar scanner extension" - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + buildFile << forceAddObjectsToExtension(fakeSonarScannerExec.executable) and: "a configurated sonarqube extension" def loginToken = "loginToken" buildFile << """ @@ -44,51 +43,45 @@ class SonarScannerEndTaskIntegrationSpec extends PluginIntegrationSpec { when: "running sonarScannerEnd task" def result = runTasksSuccessfully("sonarScannerEnd") - then: "executes sonar scanner begin task" - result.wasExecuted(":sonarScannerBegin") - and: "executes sonar scanner tool end command with sonarscanner extension login property" - def execResult = FakeExecutable.lastExecutionResults(result) + then: "executes sonar scanner tool end command with sonarscanner extension login property" + def execResult = fakeSonarScannerExec.firstResult(result.standardOutput) execResult.args == ["end", "-d:sonar.login=${loginToken}"] } def "executes sonar scanner tool end command with task properties"() { given: "a applied dotnet sonar scanner plugin" and: "a sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 0) + def fakeSonarScannerExec = FakeExecutables.argsReflector("sonarscanner", 0) and: "a set up sonar scanner extension (for sonarScannerBegin task)" - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + buildFile << forceAddObjectsToExtension(fakeSonarScannerExec.executable) and: "a configurated sonarScannerEnd task" def loginToken = "loginToken" buildFile << """ - ${createSonarScannerFromExecutable("scanner", fakeSonarScannerExec)} sonarScannerEnd { - sonarScanner.set(scanner) loginToken = "${loginToken}" } """ when: "running sonarScannerEnd task" def result = runTasksSuccessfully("sonarScannerEnd") - then: "executes sonar scanner begin task" - result.wasExecuted(":sonarScannerBegin") - and: "executes sonar scanner tool end command with sonarscanner extension login property" - def execResult = FakeExecutable.lastExecutionResults(result) + then: "executes sonar scanner tool end command with sonarscanner extension login property" + def execResult = fakeSonarScannerExec.firstResult(result.standardOutput) execResult.args == ["end", "-d:sonar.login=${loginToken}"] } def "task fails if sonar scanner tool end command returns non-zero status"() { given: "a failing sonar scanner executable" - def fakeSonarScannerExec = argReflectingFakeExecutable("sonarscanner", 1) + def fakeSonarScannerExec = FakeExecutables.argsReflector("sonarscanner", 1) and: "a set up sonar scanner extension" - buildFile << forceAddObjectsToExtension(fakeSonarScannerExec) + buildFile << forceAddObjectsToExtension(fakeSonarScannerExec.executable) when: "running the sonarScannerEnd task" def result = runTasksWithFailure("sonarScannerEnd") then: "should fail on execution with non-zero exit value" def e = rootCause(result.failure) - e.getClass().name == ExecException.name + e.getClass().name == GradleException.name e.message.contains("exit value 1") } diff --git a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/utils/PluginIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/utils/PluginIntegrationSpec.groovy index 1050275..ed9bada 100644 --- a/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/utils/PluginIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/dotnetsonar/tasks/utils/PluginIntegrationSpec.groovy @@ -16,14 +16,11 @@ package wooga.gradle.dotnetsonar.tasks.utils -import nebula.test.IntegrationSpec +import com.wooga.gradle.test.IntegrationSpec +import com.wooga.gradle.test.executable.FakeExecutables import wooga.gradle.dotnetsonar.DotNetSonarqubePlugin import wooga.gradle.dotnetsonar.SonarScannerExtension import wooga.gradle.dotnetsonar.tasks.internal.SonarScanner -import wooga.gradle.dotnetsonar.tasks.internal.SonarScannerFactory -import wooga.gradle.dotnetsonar.utils.SpecFakes - -import static wooga.gradle.dotnetsonar.utils.SpecUtils.isWindows import static wooga.gradle.dotnetsonar.utils.SpecUtils.wrapValueBasedOnType class PluginIntegrationSpec extends IntegrationSpec { @@ -32,51 +29,24 @@ class PluginIntegrationSpec extends IntegrationSpec { buildFile << """ import ${SonarScannerExtension.name} import ${SonarScanner.name} - import ${SonarScannerFactory.name} group = 'test' ${applyPlugin(DotNetSonarqubePlugin)} """.stripIndent() } - String createSonarScannerFromExecutable(String scannerVarName, File executable) { - return """ - ${forceAddMonoOnNonWindows()} - def createSonarScanner() { - ${getSonarScannerExtension("ext")} - def factory = SonarScannerFactory.withPathFallback(project, ext.monoExecutable.asFile) - return factory.fromExecutable(${wrapValueBasedOnType(executable, File)}, project.projectDir) - } - def ${scannerVarName} = createSonarScanner() - """ - } - - String getSonarScannerExtension(String extensionVarName) { + String forceAddObjectsToExtension(File sonarScannerExec) { return """ - SonarScannerExtension ${extensionVarName} = project.extensions.getByType(SonarScannerExtension) + ${forceAddFakeDotnet()} + sonarScanner.sonarScannerExecutable = ${wrapValueBasedOnType(sonarScannerExec.absolutePath, File)} """ } - String forceAddObjectsToExtension(File sonarScannerExec) { + String forceAddFakeDotnet() { + def dotnetExec = FakeExecutables.runFirstParam("dotnet", true) return """ - ${forceAddMonoOnNonWindows()} - def setupSonarScannerFile() { - ${getSonarScannerExtension("sonarScannerExt")} - sonarScannerExt.sonarScannerExecutable = ${wrapValueBasedOnType(sonarScannerExec.absolutePath, File)} + sonarScanner { + dotnetExecutable = ${wrapValueBasedOnType(dotnetExec.absolutePath, File)} } - setupSonarScannerFile() """ } - - String forceAddMonoOnNonWindows() { - if(!isWindows()) { - File monoExec = SpecFakes.runFirstParameterFakeExecutable("mono") - return """ - sonarScanner { - monoExecutable = ${wrapValueBasedOnType(monoExec.absolutePath, File)} - } - """ - } else { - return "" - } - } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePlugin.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePlugin.groovy index db46a1a..07fe7d6 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePlugin.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePlugin.groovy @@ -25,15 +25,22 @@ import org.sonarqube.gradle.SonarQubeProperties import wooga.gradle.dotnetsonar.tasks.BuildSolution import wooga.gradle.dotnetsonar.tasks.SonarScannerBegin import wooga.gradle.dotnetsonar.tasks.SonarScannerEnd +import wooga.gradle.dotnetsonar.tasks.SonarScannerInstall +import wooga.gradle.dotnetsonar.tasks.SonarScannerTask import wooga.gradle.dotnetsonar.tasks.internal.OSOps +import wooga.gradle.dotnetsonar.tasks.internal.SonarScannerInstaller import wooga.gradle.github.base.GithubBasePlugin import wooga.gradle.github.base.GithubPluginExtension import wooga.gradle.github.base.internal.DefaultGithubPluginExtension -import static wooga.gradle.dotnetsonar.SonarScannerExtension.* - class DotNetSonarqubePlugin implements Plugin { + public static final String SONARSCANNER_EXTENSION_NAME = "sonarScanner" + public static final String DOTNET_BUILD_TASK_NAME = "solutionDotnetBuild" + public static final String INSTALL_TASK_NAME = "installSonarScanner" + public static final String BEGIN_TASK_NAME = "sonarScannerBegin" + public static final String END_TASK_NAME = "sonarScannerEnd" + protected Project project @Override @@ -51,70 +58,78 @@ class DotNetSonarqubePlugin implements Plugin { project.tasks.withType(BuildSolution).configureEach {task -> def projectDir = project.layout.projectDirectory - task.msBuildExecutable.convention(sonarScannerExt.buildTools.msBuildExecutable) - task.dotnetExecutable.convention(sonarScannerExt.buildTools.dotnetExecutable) + task.executableName.convention(sonarScannerExt.dotnetExecutable) task.solution.convention(projectDir.file("${project.name}.sln")) - sonarScannerExt.registerBuildTask(task) } + project.tasks.register(DOTNET_BUILD_TASK_NAME, BuildSolution) - project.tasks.register(MS_BUILD_TASK_NAME, BuildSolution).configure { task -> - task.buildTool.convention(task.msBuildBuildTool(sonarScannerExt.buildTools.msBuildExecutable.asFile)) + def installTask = project.tasks.register(INSTALL_TASK_NAME, SonarScannerInstall) {installTask -> + installTask.onlyIf { + return !sonarScannerExt.sonarScannerExecutable.present + } + installTask.installURL.convention(sonarScannerExt.installInfo.installURL) + installTask.version.convention(sonarScannerExt.installInfo.version) + installTask.installDir.convention(sonarScannerExt.installInfo.installDir.map { + it.asFile.mkdirs() + return it + }) } - project.tasks.register(DOTNET_BUILD_TASK_NAME, BuildSolution).configure { task -> - task.buildTool.convention(task.dotnetBuildTool(sonarScannerExt.buildTools.dotnetExecutable.asFile)) + + def endTask = project.tasks.register(END_TASK_NAME, SonarScannerEnd) { endTask -> + def tokenProvider = sonarScannerExt.sonarQubeProperties.map{ + it["sonar.login"].toString() + } + endTask.loginToken.convention(tokenProvider) } - def beginTask = project.tasks.register(BEGIN_TASK_NAME, SonarScannerBegin) {beginTask -> - beginTask.sonarScanner.convention(sonarScannerExt.sonarScanner) + project.tasks.register(BEGIN_TASK_NAME, SonarScannerBegin) {beginTask -> beginTask.sonarqubeProperties.convention(sonarScannerExt.sonarQubeProperties) + beginTask.finalizedBy(endTask) } - project.tasks.register(END_TASK_NAME, SonarScannerEnd) { endTask -> - def tokenProvider = sonarScannerExt.sonarQubeProperties.map{it["sonar.login"].toString()} - endTask.sonarScanner.convention(sonarScannerExt.sonarScanner) - endTask.loginToken.convention(tokenProvider) - endTask.dependsOn(beginTask) + project.tasks.withType(SonarScannerTask).configureEach { + dependsOn(installTask) + it.dotnetExecutable.convention(sonarScannerExt.dotnetExecutable) + it.sonarScannerExecutable.convention(sonarScannerExt.sonarScannerExecutable.orElse( + installTask.flatMap {it.sonarScannerEntrypoint } + )) } } - SonarScannerExtension createSonarScannerExtension(ActionBroadcast actionBroadcast) { def extension = project.extensions.create(SONARSCANNER_EXTENSION_NAME, SonarScannerExtension, project) + def resolvedProperties = project.provider{ computeSonarProperties(actionBroadcast) } extension.sonarQubeProperties.convention(resolvedProperties) - extension.sonarScannerExecutable.convention(DotNetSonarqubePluginConventions.sonarScannerExecutable.getFileValueProvider(project)) - DotNetSonarqubePluginConventions.monoExecutable.defaultValue = { - OSOps.findInOSPath(project, "dotnet") - .or { OSOps.findInOSPath(project, "mono") } - .map {it.absolutePath } - .orElse(null) + DotNetSonarqubePluginConventions.scannerExecutable.defaultValue = { + OSOps.findInOSPath(project, SonarScannerInstaller.EXECUTABLE_NAME).orElse(null) } - extension.monoExecutable.convention(DotNetSonarqubePluginConventions.monoExecutable.getFileValueProvider(project)) + extension.dotnetExecutable.convention(DotNetSonarqubePluginConventions.scannerDotnetExecutable.getStringValueProvider(project)) + extension.sonarScannerExecutable.convention(DotNetSonarqubePluginConventions.scannerExecutable.getFileValueProvider(project)) - DotNetSonarqubePluginConventions.msbuildExecutable.defaultValue = { - OSOps.findInOSPath(project, "MSBuild.exe", "msbuild") - .map {it.absolutePath } - .orElse(null) - } - extension.buildTools.msBuildExecutable.convention( - DotNetSonarqubePluginConventions.msbuildExecutable.getFileValueProvider(project) - ) - - DotNetSonarqubePluginConventions.msbuildExecutable.defaultValue = { - OSOps.findInOSPath(project, "dotnet") - .map {it.absolutePath } - .orElse(null) - } - extension.buildTools.dotnetExecutable.convention( - DotNetSonarqubePluginConventions.dotnetExecutable.getFileValueProvider(project) - ) + configureInstallInfo(extension.installInfo) return extension } + SonarScannerInstallInfo configureInstallInfo(SonarScannerInstallInfo installInfo) { + installInfo.dotnetFramework.convention("netcoreapp2.0") + DotNetSonarqubePluginConventions.scannerInstallUrl.defaultValue = { + installInfo.versionBasedSourceUrl.getOrElse(null) + } + installInfo.installURL.convention(DotNetSonarqubePluginConventions.scannerInstallUrl.getStringValueProvider(project)) + + installInfo.version.convention(DotNetSonarqubePluginConventions.scannerInstallVersion.getStringValueProvider(project)) + + DotNetSonarqubePluginConventions.scannerInstallDir.defaultValue = { + project.layout.buildDirectory.dir("bin/net-sonarscanner/${installInfo.version.get()}-${installInfo.dotnetFramework.get()}").getOrElse(null) + } + installInfo.installDir.convention(DotNetSonarqubePluginConventions.scannerInstallDir.getDirectoryValueProvider(project)) + return installInfo + } //Wizardry from the sonarqube plugin. Needed for resolving the properties. diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePluginConventions.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePluginConventions.groovy index 072fd3a..e419f23 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePluginConventions.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/DotNetSonarqubePluginConventions.groovy @@ -3,27 +3,34 @@ package wooga.gradle.dotnetsonar import com.wooga.gradle.PropertyLookup class DotNetSonarqubePluginConventions { - static PropertyLookup sonarScannerExecutable = new PropertyLookup( - "SONAR_SCANNER_SONAR_SCANNER_EXECUTABLE", - "sonarScanner.sonarScannerExecutable", + + static PropertyLookup scannerInstallUrl = new PropertyLookup( + "SONAR_SCANNER_SCANNER_INSTALL_URL", + "sonarScanner.scannerInstallUrl", null ) - static PropertyLookup monoExecutable = new PropertyLookup( - ["SONAR_SCANNER_MONO_EXECUTABLE", "SONAR_SCANNER_DOTNET_EXECUTABLE"], - ["sonarScanner.monoExecutable", "sonarScanner.dotnetExecutable"], + static PropertyLookup scannerInstallDir = new PropertyLookup( + "SONAR_SCANNER_SCANNER_INSTALL_DIR", + "sonarScanner.scannerInstallDir", null ) - static PropertyLookup msbuildExecutable = new PropertyLookup( - ["SONAR_SCANNER_BUILD_TOOLS_MSBUILD_EXECUTABLE"], - "sonarScanner.buildTools.msBuildExecutable", - null + static PropertyLookup scannerInstallVersion = new PropertyLookup( + "SONAR_SCANNER_SCANNER_INSTALL_VERSION", + "sonarScanner.sonarScannerVersion", + '5.15.1.88158' ) - static PropertyLookup dotnetExecutable = new PropertyLookup( - ["SONAR_SCANNER_BUILD_TOOLS_DOTNET_EXECUTABLE"], - ["sonarScanner.buildTools.dotnetExecutable"], + static PropertyLookup scannerDotnetExecutable = new PropertyLookup( + "SONAR_SCANNER_SCANNER_DOTNET_EXECUTABLE", + "sonarScanner.scannerDotNetExecutable", + 'dotnet' //system dotnet + ) + + static PropertyLookup scannerExecutable = new PropertyLookup( + "SONAR_SCANNER_SONAR_SCANNER_EXECUTABLE", + "sonarScanner.scannerExecutable", null ) } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerExtension.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerExtension.groovy index 1e3a0c2..89aaa43 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerExtension.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerExtension.groovy @@ -20,39 +20,28 @@ import groovy.transform.stc.ClosureParams import groovy.transform.stc.SimpleType import org.gradle.api.Project import org.gradle.api.Task -import org.gradle.api.file.RegularFile -import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.MapProperty -import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskProvider import wooga.gradle.dotnetsonar.tasks.SonarScannerBegin import wooga.gradle.dotnetsonar.tasks.SonarScannerEnd -import wooga.gradle.dotnetsonar.tasks.internal.SonarScanner -import wooga.gradle.dotnetsonar.tasks.internal.SonarScannerFactory +import wooga.gradle.dotnetsonar.tasks.traits.SonarScannerSpec -class SonarScannerExtension { - - public static final String SONARSCANNER_EXTENSION_NAME = "sonarScanner" - public static final String MS_BUILD_TASK_NAME = "solutionMSBuild" - public static final String DOTNET_BUILD_TASK_NAME = "solutionDotnetBuild" - public static final String BEGIN_TASK_NAME = "sonarScannerBegin" - public static final String END_TASK_NAME = "sonarScannerEnd" +class SonarScannerExtension implements SonarScannerSpec { private final Project project; + final SonarScannerInstallInfo installInfo - final BuildToolsInfo buildTools - private final Provider sonarScanner; - private final RegularFileProperty sonarScannerExecutable = project.objects.fileProperty() - private final RegularFileProperty monoExecutable = project.objects.fileProperty() private final MapProperty sonarQubeProperties = project.objects.mapProperty(String, Object) + MapProperty getSonarQubeProperties() { + return sonarQubeProperties; + } + SonarScannerExtension(Project project) { this.project = project - this.installInfo = new SonarScannerInstallInfo(project) - this.buildTools = new BuildToolsInfo(project) - this.sonarScanner = createSonarScannerProvider(project, new SonarScannerFactory(project, monoExecutable.asFile)) + this.installInfo = objects.newInstance(SonarScannerInstallInfo) } /** @@ -64,7 +53,6 @@ class SonarScannerExtension { tasks.each {taskProvider -> taskProvider.configure { task -> this.registerBuildTask(task) } } - } /** @@ -81,7 +69,7 @@ class SonarScannerExtension { } /** * Convenience method for filling up sonarscanner installation info. Only used if sonar scanner is downloaded from remote. - * @param installInfoOps closure operating over install info object + * @param installInfoOps closure operating over @{SonarScannerInstallInfo} object */ void installInfo(@DelegatesTo(SonarScannerInstallInfo) @ClosureParams(value=SimpleType, options=["wooga.gradle.dotnetsonar.SonarScannerInstallInfo"]) @@ -89,76 +77,5 @@ class SonarScannerExtension { this.installInfo.with(installInfoOps) } - void buildTools(@DelegatesTo(BuildToolsInfo) - @ClosureParams(value=SimpleType, options=["wooga.gradle.dotnetsonar.BuildToolsInfo"]) - Closure buildToolsOps) { - this.buildTools.with(buildToolsOps) - } - - Provider getSonarScanner() { - return sonarScanner - } - - Provider createSonarScannerProvider(Project project, SonarScannerFactory scanners) { - def workingDir = project.projectDir - - def scannerFromFile = sonarScannerExecutable.map( { RegularFile scannerExec -> - scanners.fromExecutable(scannerExec.asFile, workingDir) - }.memoize()) - def scannerFromPath = project.provider({ scanners.fromPath(workingDir).orElse(null) }.memoize()) - def scannerFromRemote = installInfo.provideScannerFromRemote(project, scanners, workingDir) - return scannerFromFile.orElse(scannerFromPath).orElse(scannerFromRemote) - } - - RegularFileProperty getMonoExecutable() { - return monoExecutable - } - - void setMonoExecutable(Provider monoExecutable) { - this.monoExecutable.set(monoExecutable) - } - - void setMonoExecutable(RegularFileProperty monoExecutable) { - this.monoExecutable.set(monoExecutable) - } - - void setMonoExecutable(File monoExecutable) { - this.monoExecutable.set(monoExecutable) - } - - RegularFileProperty getDotnetExecutable() { - return monoExecutable - } - - void setDotnetExecutable(Provider monoExecutable) { - this.monoExecutable.set(monoExecutable) - } - - void setDotnetExecutable(RegularFileProperty monoExecutable) { - this.monoExecutable.set(monoExecutable) - } - - void setDotnetExecutable(File monoExecutable) { - this.monoExecutable.set(monoExecutable) - } - - RegularFileProperty getSonarScannerExecutable() { - return sonarScannerExecutable - } - - void setSonarScannerExecutable(File sonarScannerExecutable) { - this.sonarScannerExecutable.set(sonarScannerExecutable) - } - - void setSonarScannerExecutable(RegularFileProperty sonarScannerExecutable) { - this.sonarScannerExecutable.set(sonarScannerExecutable) - } - void setSonarScannerExecutable(Provider sonarScannerExecutable) { - this.sonarScannerExecutable.set(sonarScannerExecutable) - } - - MapProperty getSonarQubeProperties() { - return sonarQubeProperties; - } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerInstallInfo.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerInstallInfo.groovy index 0982459..848ac50 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerInstallInfo.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/SonarScannerInstallInfo.groovy @@ -16,72 +16,30 @@ package wooga.gradle.dotnetsonar -import org.gradle.api.Project -import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider -import wooga.gradle.dotnetsonar.tasks.internal.SonarScanner -import wooga.gradle.dotnetsonar.tasks.internal.SonarScannerFactory +import wooga.gradle.dotnetsonar.tasks.traits.SonarScannerInstallSpec -class SonarScannerInstallInfo { - private Property sourceURL - private Property version - private DirectoryProperty installDir +class SonarScannerInstallInfo implements SonarScannerInstallSpec { - SonarScannerInstallInfo(Project project) { - def buildDir = project.layout.buildDirectory - this.sourceURL = project.objects.property(String) - this.version = project.objects.property(String).convention("5.2.2.33595") - this.installDir = project.objects.directoryProperty().convention(buildDir.dir("bin/net-sonarscanner")) - } - - Provider provideScannerFromRemote(Project project, SonarScannerFactory factory, File workingDir) { - return sourceURL. - map({String sourceURL -> - factory.fromRemoteURL(project, new URL(sourceURL), installDir.get().asFile, workingDir) - }.memoize()). - orElse(project.provider({ - factory.fromRemote(project, version.get(), installDir.get().asFile, workingDir) - }.memoize())) - } - - Property getSourceURL() { - return sourceURL - } - - Property getVersion() { - return version - } + private final Property dotnetFramework = objects.property(String) - DirectoryProperty getInstallDir() { - return installDir + Property getDotnetFramework() { + return dotnetFramework } - void setSourceURL(Property sourceURL) { - this.sourceURL.set(sourceURL) + void setDotnetFramework(String dotnetVersion) { + this.dotnetFramework.set(dotnetVersion) } - void setSourceURL(String sourceURL) { - this.sourceURL.set(sourceURL) + void setDotnetFramework(Provider dotnetVersion) { + this.dotnetFramework.set(dotnetVersion) } - void setVersion(Property version) { - this.version.set(version) + Provider getVersionBasedSourceUrl() { + return version.map { + "https://github.com/SonarSource/sonar-scanner-msbuild/releases/download/${it}/sonar-scanner-msbuild-${it}-${dotnetFramework.get()}.zip".toString() + } } - void setVersion(String version) { - this.version.set(version) - } - - void setInstallDir(DirectoryProperty installDir) { - this.installDir.set(installDir) - } - - void setInstallDir(File installDir) { - this.installDir.set(installDir) - } - - void setInstallDir(String installDir) { - this.installDir.set(new File(installDir)) - } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolution.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolution.groovy index dd95e92..8ef736b 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolution.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/BuildSolution.groovy @@ -16,157 +16,37 @@ package wooga.gradle.dotnetsonar.tasks -import org.gradle.api.DefaultTask import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.ListProperty -import org.gradle.api.provider.MapProperty -import org.gradle.api.provider.Property import org.gradle.api.provider.Provider -import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Optional import org.gradle.api.tasks.TaskAction -import wooga.gradle.dotnetsonar.tasks.internal.DotNet -import wooga.gradle.dotnetsonar.tasks.internal.MSBuild -import wooga.gradle.dotnetsonar.tasks.internal.SolutionBuildTool +import wooga.gradle.dotnet.tasks.Build -class BuildSolution extends DefaultTask { +class BuildSolution extends Build { - private Property buildTool - private RegularFileProperty msBuildExecutable - private RegularFileProperty dotnetExecutable - private RegularFileProperty solution - private MapProperty environment - private ListProperty extraArgs - - BuildSolution() { - this.buildTool = project.objects.property(SolutionBuildTool) - this.msBuildExecutable = project.objects.fileProperty() - this.dotnetExecutable = project.objects.fileProperty() - this.solution = project.objects.fileProperty() - this.environment = project.objects.mapProperty(String, Object) - this.extraArgs = project.objects.listProperty(String) - } - - @TaskAction - void run() { - def resolvedBuildTool = buildTool. - orElse(dotnetExecutable.map { DotNet.gradleBased(getProject(), it.asFile) }). - orElse(msBuildExecutable.map { MSBuild.gradleBased(getProject(), it.asFile) }). - get() - resolvedBuildTool.buildSolution(solution.get().asFile, environment.get(), extraArgs.getOrElse([])) - } - - - /** - * - * @param dotnetExecutable: Provider or Provider object to the dotnet exxecutable - * @return - */ - Provider dotnetBuildTool(Provider dotnetExecutable) { - dotnetExecutable.map { exec -> - if(exec instanceof File) { - return DotNet.gradleBased(project, exec as File) - } else if (exec instanceof RegularFile) { - return DotNet.gradleBased(project, exec.asFile) - } - throw new IllegalArgumentException("'dotnetExecutable' should be a Provider or Provider") - } - } - /** - * * Helper to create SolutionBuildTool objects to be used with the {@code buildTool} property - * @return {@code SolutionBuildTool} to build with dotnet - */ - SolutionBuildTool dotnetBuildTool(File dotnetExecutable) { - DotNet.gradleBased(project, dotnetExecutable) - } - - /** - * Helper to create SolutionBuildTool objects to be used with the {@code buildTool} property - * @return {@code Provider} to build with msbuild - */ - Provider msBuildBuildTool(Provider msBuildExecutable) { - msBuildExecutable.map { exec -> - return MSBuild.gradleBased(project, exec as File) - } - } - - /** - * Helper to create SolutionBuildTool objects to be used with the {@code buildTool} property - * @return {@code Provider} to build with msbuild - */ - SolutionBuildTool msBuildBuildTool(File msBuildExecutable) { - MSBuild.gradleBased(project, msBuildExecutable) - } + private final RegularFileProperty solution = objects.fileProperty() @InputFile + @Optional RegularFileProperty getSolution() { return solution } - @Optional @Input - MapProperty getEnvironment() { - return environment - } - - @Optional @Input - ListProperty getExtraArgs() { - return extraArgs - } - - @Input @Optional - Property getBuildTool() { - return buildTool - } - - @InputFile @Optional - RegularFileProperty getDotnetExecutable() { - return dotnetExecutable + void setSolution(Provider solution) { + this.solution.set(solution) } - @InputFile @Optional - RegularFileProperty getMsBuildExecutable() { - return msBuildExecutable + void setSolution(RegularFile solution) { + this.solution.set(solution) } void setSolution(File solution) { this.solution.set(solution) } - void setSolution(String solutionPath) { - this.setSolution(project.file(solutionPath)) - } - - void setEnvironment(Map environment) { - this.environment.set(environment) - } - - void setExtraArgs(List extraArgs) { - this.extraArgs.set(extraArgs) - } - - void addEnvironment(String key, Object value) { - this.environment.put(key, value) - } - - void setBuildTool(SolutionBuildTool buildTool) { - this.buildTool.set(buildTool) - } - - void setDotnetExecutable(File file) { - dotnetExecutable.set(file) - } - - void setDotnetExecutable(String filePath) { - setDotnetExecutable(new File(filePath)) - } - - void setMsBuildExecutable(File file) { - msBuildExecutable.set(file) - } - - void setMsBuildExecutable(String filePath) { - setMsBuildExecutable(new File(filePath)) + BuildSolution() { + this.additionalArguments.addAll(solution.map {[it.asFile.absolutePath] }.orElse([])) } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBegin.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBegin.groovy index 0956544..6ad3ab2 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBegin.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerBegin.groovy @@ -17,57 +17,18 @@ package wooga.gradle.dotnetsonar.tasks -import org.gradle.api.DefaultTask import org.gradle.api.provider.MapProperty -import org.gradle.api.provider.Property import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction -import wooga.gradle.dotnetsonar.tasks.internal.SonarScanner -class SonarScannerBegin extends DefaultTask { +class SonarScannerBegin extends SonarScannerTask { - private final Property sonarScanner; private final MapProperty sonarqubeProperties; - SonarScannerBegin() { - this.sonarScanner = project.objects.property(SonarScanner) - this.sonarqubeProperties = project.objects.mapProperty(String, Object) - } - - @TaskAction - def run() { - def properties = sonarqubeProperties.get() - def sonarScanner = sonarScanner.get() - assertKeyOnMap(properties, "sonar.projectKey") - assertKeyOnMap(properties, "sonar.version") - sonarScanner.begin( - properties["sonar.projectKey"].toString(), - properties["sonar.projectName"]?.toString(), - properties["sonar.version"]?.toString(), - properties) - } - - private static void assertKeyOnMap(Map map, T key) { - if(!map.containsKey(key)) { - throw new IllegalArgumentException("SonarqubeBegin needs a set ${key} property") - } - } - - @Input - Property getSonarScanner() { - return sonarScanner - } - @Input MapProperty getSonarqubeProperties() { - return sonarqubeProperties } - void setSonarScanner(SonarScanner sonarScanner) { - this.sonarScanner.set(sonarScanner) - } - void setSonarqubeProperties(MapProperty sonarqubeProperties) { this.sonarqubeProperties.set(sonarqubeProperties) } @@ -76,4 +37,24 @@ class SonarScannerBegin extends DefaultTask { this.sonarqubeProperties.set(sonarqubeProperties) } + + SonarScannerBegin() { + this.sonarqubeProperties = project.objects.mapProperty(String, Object) + this.additionalArguments.addAll(sonarScanner.map {sonarScanner -> + def properties = sonarqubeProperties.getOrElse([:]) + SonarScannerBegin.assertKeyOnMap(properties, "sonar.projectKey") + SonarScannerBegin.assertKeyOnMap(properties, "sonar.version") + return sonarScanner.beginArgs( + properties["sonar.projectKey"].toString(), + properties["sonar.projectName"]?.toString(), + properties["sonar.version"]?.toString(), + properties) + }) + } + + private static void assertKeyOnMap(Map map, T key) { + if(!map.containsKey(key)) { + throw new IllegalArgumentException("SonarScannerBegin task needs a set ${key} property") + } + } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEnd.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEnd.groovy index b371b57..c73b25f 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEnd.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerEnd.groovy @@ -20,28 +20,20 @@ import org.gradle.api.DefaultTask import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction +import wooga.gradle.dotnet.tasks.DotnetTask import wooga.gradle.dotnetsonar.tasks.internal.SonarScanner +import wooga.gradle.dotnetsonar.tasks.traits.SonarScannerSpec -class SonarScannerEnd extends DefaultTask { +class SonarScannerEnd extends SonarScannerTask { - private final Property sonarScanner; private final Property loginToken; SonarScannerEnd() { - this.sonarScanner = project.objects.property(SonarScanner) this.loginToken = project.objects.property(String) - } - - @TaskAction - def run() { - def sonarScanner = sonarScanner.get() - def token = loginToken.get() - sonarScanner.end(token) - } - - @Input - Property getSonarScanner() { - return sonarScanner + additionalArguments.addAll(sonarScanner.map {sonarScanner -> + def token = loginToken.getOrNull() + return sonarScanner.endArgs(token) + }) } @Input @@ -52,8 +44,4 @@ class SonarScannerEnd extends DefaultTask { void setLoginToken(String token) { this.loginToken.set(token) } - - void setSonarScanner(SonarScanner sonarScanner) { - this.sonarScanner.set(sonarScanner) - } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerInstall.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerInstall.groovy index 4ca0c33..1f11b7d 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerInstall.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerInstall.groovy @@ -17,89 +17,46 @@ package wooga.gradle.dotnetsonar.tasks import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.Optional +import org.gradle.api.file.RegularFile +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.TaskAction -import wooga.gradle.dotnetsonar.SonarScannerExtension import wooga.gradle.dotnetsonar.tasks.internal.SonarScannerInstaller +import wooga.gradle.dotnetsonar.tasks.traits.SonarScannerInstallSpec -class SonarScannerInstall extends DefaultTask { +class SonarScannerInstall extends DefaultTask implements SonarScannerInstallSpec { - public static final String EXECUTABLE_NAME = SonarScannerInstaller.EXECUTABLE_NAME + private final RegularFileProperty sonarScannerEntrypoint = objects.fileProperty() - private Property sourceURL - private Property version - private DirectoryProperty installationDir - - static void configureDefaultInstall(SonarScannerInstall scannerInstallTask) { - def project = scannerInstallTask.project - scannerInstallTask.with { - version.convention("5.2.2.33595") - installationDir.convention(project.layout.buildDirectory.dir("bin/net-sonarscanner")) - } - scannerInstallTask.onlyIf { - SonarScannerExtension sonarScannerExt = project.extensions.getByType(SonarScannerExtension) - return !sonarScannerExt.sonarScanner.present - } + @Internal + Provider getSonarScannerEntrypoint() { + return sonarScannerEntrypoint } SonarScannerInstall() { - this.sourceURL = project.objects.property(String) - this.version = project.objects.property(String) - this.installationDir = project.objects.directoryProperty() + sonarScannerEntrypoint.convention(installDir.map { installDir -> + def sonarScanner = SonarScannerInstaller.findSonarScannerEntrypoint(installDir.asFile) + return sonarScanner.map {installDir.file(it.absolutePath) }.orElse(null) + }) + + onlyIf { + def lacksScanner = !sonarScannerEntrypoint.present + if(!lacksScanner) { + logger.info("SonarScanner already installed in " + + "${sonarScannerEntrypoint.get().asFile.parentFile.absolutePath}, skipping" + ) + } + return lacksScanner + } } @TaskAction def run() { - SonarScannerExtension sonarScannerExt = project.extensions.getByType(SonarScannerExtension) - def scannerExec = downloadSonarScannerFiles() - sonarScannerExt.sonarScanner = sonarScannerExt.createSonarScanner(scannerExec) - } - - private File downloadSonarScannerFiles() { - def version = version.get() - def dotnetVersion = SonarScannerInstaller.DOTNET_VERSION - def installationDir = installationDir.map{it.dir("sonarscanner-${version}")}.get() + def installationDir = installDir.get() def scannerInstaller = SonarScannerInstaller.gradleBased(project) - return sourceURL.map{urlStr -> - scannerInstaller.install(new URL(urlStr), installationDir.asFile) - }.orElse( - project.provider { scannerInstaller.install(version, dotnetVersion, installationDir.asFile) } - ).get() - } - - @Input @Optional - Property getSourceURL() { - return sourceURL - } - - @Input - Property getVersion() { - return version - } - - @InputDirectory - DirectoryProperty getInstallationDir() { - return installationDir - } - - void setSourceURL(String sourceURL) { - this.sourceURL.set(sourceURL) - } - - void setVersion(String version) { - this.version.set(version) - } - - void setInstallationDir(String installationDir) { - this.installationDir.set(project.layout.projectDirectory.dir(installationDir)) - } - - void setInstallationDir(File installationDir) { - this.installationDir.set(installationDir) + def executable = scannerInstaller.install(new URL(installURL.get()), installationDir.asFile) + sonarScannerEntrypoint.set(executable) } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerTask.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerTask.groovy new file mode 100644 index 0000000..54bc797 --- /dev/null +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/SonarScannerTask.groovy @@ -0,0 +1,19 @@ +package wooga.gradle.dotnetsonar.tasks + +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Internal +import wooga.gradle.dotnet.tasks.DotnetTask +import wooga.gradle.dotnetsonar.tasks.internal.SonarScanner +import wooga.gradle.dotnetsonar.tasks.traits.SonarScannerSpec + +abstract class SonarScannerTask extends DotnetTask implements SonarScannerSpec { + + SonarScannerTask() { + this.executableName.convention(dotnetExecutable) + } + + @Internal + Provider getSonarScanner() { + return sonarScannerExecutable.map {new SonarScanner(it.asFile) } + } +} diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/DotNet.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/DotNet.groovy deleted file mode 100644 index b8ab6f9..0000000 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/DotNet.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -import org.gradle.api.Project -import org.gradle.process.ExecSpec - -class DotNet implements SolutionBuildTool { - - private final File executable - private final Shell shell - - static DotNet gradleBased(Project project, File executable) { - return new DotNet(new GradleShell(project), executable) - } - - DotNet(Shell shell, File executable) { - this.shell = shell - this.executable = executable - } - - public void buildSolution(File solution, Map environment = new HashMap<>(), List extraArgs=[]) { - shell.execute { ExecSpec execSpec -> - execSpec.executable = executable.absolutePath - execSpec.environment(environment) - execSpec.args("build") - execSpec.args(solution.absolutePath) - execSpec.args(*extraArgs) - }.throwsOnFailure() - } - - File getExecutable() { - return executable - } -} diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/MSBuild.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/MSBuild.groovy deleted file mode 100644 index ab2b454..0000000 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/MSBuild.groovy +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -import org.gradle.api.Project - -class MSBuild implements SolutionBuildTool { - private final File executable - private final Shell shell - - static MSBuild gradleBased(Project project, File executable) { - return new MSBuild(new GradleShell(project), executable) - } - - MSBuild(Shell shell, File executable) { - this.shell = shell - this.executable = executable - } - - public void buildSolution(File solution, Map environment = new HashMap<>(), List extraArgs=[]) { - shell.execute { execSpec -> - execSpec.executable = executable.absolutePath - execSpec.environment(environment) - execSpec.args(*extraArgs) - execSpec.args(solution.absolutePath) - }.throwsOnFailure() - } - - File getExecutable() { - return executable - } -} diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/MonoShell.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/MonoShell.groovy deleted file mode 100644 index a151d4a..0000000 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/MonoShell.groovy +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -import org.gradle.api.Project -import org.gradle.process.ExecSpec - -import java.util.function.Consumer - -class MonoShell implements Shell { - - private Shell baseShell; - private File monoExecutable - - - static MonoShell forProject(Project project, File monoExecutable) { - Shell baseShell = new GradleShell(project) - return new MonoShell(baseShell, monoExecutable) - } - - MonoShell(Shell baseShell, File monoExecutable) { - this.baseShell = baseShell - this.monoExecutable = monoExecutable - } - - @Override - public ShellResult execute(boolean logging=true, Consumer execSpecClosure) { - return baseShell.execute { ExecSpec exec -> - execSpecClosure(exec) - exec.args = [exec.executable] + exec.args - exec.executable = monoExecutable.absolutePath - } - } -} diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SolutionBuildTool.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SolutionBuildTool.groovy deleted file mode 100644 index d948d0a..0000000 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SolutionBuildTool.groovy +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -interface SolutionBuildTool { - - public void buildSolution(File solution); - public void buildSolution(File solution, Map environment); - public void buildSolution(File solution, Map environment, List extraArgs); - -} diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScanner.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScanner.groovy index bd24f44..b90483d 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScanner.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScanner.groovy @@ -16,64 +16,49 @@ package wooga.gradle.dotnetsonar.tasks.internal -import org.gradle.api.Project -import org.gradle.process.ExecSpec +import com.wooga.gradle.io.ExecSpec class SonarScanner implements Serializable { - static SonarScanner nativeBased(Project project, File executable, File workingDir) { - return new SonarScanner(new GradleShell(project), executable, workingDir) - } - - static SonarScanner monoBased(Project project, File executable, File monoExecutable, File workingDir) { - return new SonarScanner(MonoShell.forProject(project, monoExecutable), executable, workingDir) - } - - private Shell shell; private File executable; - private File workingDir; - private SonarScanner(Shell shell, File executable, File workingDir) { - this.shell = shell + SonarScanner(File executable) { this.executable = executable - this.workingDir = workingDir } - public void begin(String sonarProjectKey, String sonarProjectName, String version, Map sonarqubeProperties) { - shell.execute { ExecSpec execSpec -> - execSpec.workingDir = workingDir - execSpec.executable = executable.absolutePath - execSpec.args("begin") - execSpec.args("-k:${sonarProjectKey}") - if(sonarProjectName != null) { - execSpec.args("-n:${sonarProjectName}") - } - if(version != null) { - execSpec.args("-v:${version}") - } - addPropertiesArgs(execSpec, sonarqubeProperties) - }.throwsOnFailure() + List beginArgs(String sonarProjectKey, String sonarProjectName, String version, Map sonarqubeProperties) { + def args = new ArrayList() + args.add(executable.absolutePath) + args.add("begin") + args.add("-k:${sonarProjectKey}") + if(sonarProjectName != null) { + args.add("-n:${sonarProjectName}") + } + if(version != null) { + args.add("-v:${version}") + } + addPropertiesArgs(args, sonarqubeProperties) + return args } - public void end(String loginToken=null) { - shell.execute { ExecSpec execSpec -> - execSpec.workingDir = workingDir - execSpec.executable = executable.absolutePath - execSpec.args("end") - if(loginToken != null) { - addPropertiesArgs(execSpec, ["sonar.login": loginToken]) - } - }.throwsOnFailure() + List endArgs(String loginToken=null) { + def args = new ArrayList() + args.add(executable.absolutePath) + args.add("end") + if(loginToken != null) { + addPropertiesArgs(args, ["sonar.login": loginToken]) + } + return args } - static void addPropertiesArgs(ExecSpec execSpec, Map sonarqubeProperties) { + static void addPropertiesArgs(List args, Map sonarqubeProperties) { sonarqubeProperties.entrySet().findAll { it.key != "sonar.projectKey" && //replaced by -k it.key != "sonar.projectName" && //replaced by -n it.key != "sonar.projectVersion" && //replace by -v it.key != "sonar.working.directory" //automatically set by SonarScanner and cannot be overridden }.forEach() { propEntry -> - execSpec.args("-d:${propEntry.key}=${propEntry.value.toString()}") + args.add("-d:${propEntry.key}=${propEntry.value.toString()}") } } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerFactory.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerFactory.groovy deleted file mode 100644 index 3c4a1eb..0000000 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerFactory.groovy +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -import org.gradle.api.Project -import org.gradle.api.provider.Provider - -import static wooga.gradle.dotnetsonar.tasks.internal.OSOps.isWindows - -class SonarScannerFactory { - - private Project project; - private Provider monoExecutable; - - SonarScannerFactory(Project project, Provider monoExecutable) { - this.project = project; - this.monoExecutable = monoExecutable - } - - public Optional fromPath(File workingDir) { - def maybeExecutable = OSOps.findInOSPath(project, SonarScannerInstaller.EXECUTABLE_NAME) - return maybeExecutable.map {executable -> fromExecutable(executable, workingDir) } - } - - public SonarScanner fromExecutable(File scannerExec, File workingDir) { - if(isWindows()) { - return SonarScanner.nativeBased(project, scannerExec, workingDir) - } else { - def monoExec = monoExecutable.get() - return SonarScanner.monoBased(project, scannerExec, monoExec, workingDir) - } - } - - public SonarScanner fromRemote(Project project, String version, File installDir, File workingDir) { - def installer = SonarScannerInstaller.gradleBased(project) - def scannerExec = installer.install(version, installDir) - return fromExecutable(scannerExec, workingDir) - } - - public SonarScanner fromRemoteURL(Project project, URL remoteZipFile, File installDir, File workingDir) { - def installer = SonarScannerInstaller.gradleBased(project) - def scannerExec = installer.install(remoteZipFile, installDir) - return fromExecutable(scannerExec, workingDir) - } - -} diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerInstaller.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerInstaller.groovy index 1ba5436..1da2972 100644 --- a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerInstaller.groovy +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerInstaller.groovy @@ -26,6 +26,7 @@ class SonarScannerInstaller { //this executable only exists for .NET [4.6, 5) public static final String EXECUTABLE_NAME = "SonarScanner.MSBuild.exe"; + public static final String DLL_NAME = "SonarScanner.MSBuild.dll"; public static final String DOTNET_VERSION = "net46"; public static final String defaultBaseURL = "https://github.com/SonarSource/sonar-scanner-msbuild/releases/download" @@ -63,19 +64,34 @@ class SonarScannerInstaller { it.readable = true it.executable = true } - def sonarScannerExecutable = executableFiles.find{it.absolutePath.endsWith(EXECUTABLE_NAME)} - return Optional.ofNullable(sonarScannerExecutable).orElseThrow { + def sonarScannerEntrypoint = findSonarScannerEntrypoint(installationDir) + return sonarScannerEntrypoint.orElseThrow { new FileNotFoundException("Couldn't find sonar-scanner executable in installed package") } } + public static Optional findSonarScannerEntrypoint(File installationDir, boolean forceExecutable=false) { + def targetFiles = forceExecutable? + ["SonarScanner.MSBuild.exe"] : + ["SonarScanner.MSBuild.dll", "SonarScanner.MSBuild.exe"] - private static File[] findScannerExecutableFiles(File installationDir) { + Files.walk(installationDir.toPath()).filter { + it.fileName.toString() in targetFiles + } + .map {it.toFile()} + .findFirst() + } + + public static List findScannerExecutableFiles(File installationDir) { + if(!installationDir.directory) { + return [] + } def installedFiles = Files.walk(Paths.get(installationDir.absolutePath)) return installedFiles.filter { path -> def file = path.toFile() def isBaseExecutable = file.isFile() && file.absolutePath.endsWith(EXECUTABLE_NAME) def isFromBinFolder = file.isFile() && path.parent.fileName.toString() == "bin" - return isBaseExecutable || isFromBinFolder + def isDotExeFile = file.isFile() && path.parent.fileName.toString().endsWith(".exe") + return isBaseExecutable || isFromBinFolder || isDotExeFile }.map{it.toFile()}.collect(Collectors.toList()) } } diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/traits/SonarScannerInstallSpec.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/traits/SonarScannerInstallSpec.groovy new file mode 100644 index 0000000..a4bbc02 --- /dev/null +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/traits/SonarScannerInstallSpec.groovy @@ -0,0 +1,61 @@ +package wooga.gradle.dotnetsonar.tasks.traits + +import com.wooga.gradle.BaseSpec +import org.gradle.api.file.Directory +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory + +trait SonarScannerInstallSpec extends BaseSpec{ + + private final Property installURL = objects.property(String) + + @Input + Property getInstallURL() { + return installURL + } + + void setInstallURL(String sourceURL) { + this.installURL.set(sourceURL) + } + + void setInstallURL(Provider sourceURL) { + this.installURL.set(sourceURL) + } + + private final Property version = objects.property(String) + + @Input + Property getVersion() { + return version + } + + void setVersion(String version) { + this.version.set(version) + } + + void setVersion(Provider version) { + this.version.set(version) + } + + private final DirectoryProperty installDir = objects.directoryProperty() + + @InputDirectory + DirectoryProperty getInstallDir() { + return installDir + } + + void setInstallDir(Provider installationDir) { + this.installDir.set(installationDir) + } + + void setInstallDir(Directory installationDir) { + this.installDir.set(installationDir) + } + + void setInstallDir(File installationDir) { + this.installDir.set(installationDir) + } +} diff --git a/src/main/groovy/wooga/gradle/dotnetsonar/tasks/traits/SonarScannerSpec.groovy b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/traits/SonarScannerSpec.groovy new file mode 100644 index 0000000..4749fc8 --- /dev/null +++ b/src/main/groovy/wooga/gradle/dotnetsonar/tasks/traits/SonarScannerSpec.groovy @@ -0,0 +1,75 @@ +package wooga.gradle.dotnetsonar.tasks.traits + +import com.wooga.gradle.BaseSpec +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.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional +import wooga.gradle.dotnetsonar.tasks.internal.SonarScanner + +trait SonarScannerSpec implements BaseSpec { + + private final Property dotnetExecutable = objects.property(String) + + @Input + @Optional + Property getDotnetExecutable() { + return dotnetExecutable + } + + void setDotnetExecutable(String dotnetExecutable) { + this.dotnetExecutable.set(dotnetExecutable) + } + + void setDotnetExecutable(Provider dotnetExecutable) { + this.dotnetExecutable.set(dotnetExecutable.map { + if(it instanceof RegularFile) { + return it.asFile.absolutePath + } + if(it instanceof File) { + return it.absolutePath + } + if(it instanceof String || it instanceof GString) { + return it.toString() + } + throw new IllegalArgumentException("DotnetExecutable must be a Provider") + }) + } + + void setDotnetExecutable(File dotnetExecutable) { + this.dotnetExecutable.set(dotnetExecutable.absolutePath) + } + + void setDotnetExecutable(RegularFile dotnetExecutable) { + this.dotnetExecutable.set(dotnetExecutable.asFile.absolutePath) + } + + private final RegularFileProperty sonarScannerExecutable = objects.fileProperty() + + @InputFile + @Optional + RegularFileProperty getSonarScannerExecutable() { + return sonarScannerExecutable + } + + void setSonarScannerExecutable(Provider sonarScannerExecutable) { + this.sonarScannerExecutable.set(sonarScannerExecutable) + } + + void setSonarScannerExecutable(RegularFile sonarScannerExecutable) { + this.sonarScannerExecutable.set(sonarScannerExecutable) + } + + void setSonarScannerExecutable(File sonarScannerExecutable) { + this.sonarScannerExecutable.set(sonarScannerExecutable) + } + + Provider getSonarScanner() { + sonarScannerExecutable.map { + new SonarScanner(it.asFile) + } + } +} diff --git a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/DotNetSpec.groovy b/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/DotNetSpec.groovy deleted file mode 100644 index da34146..0000000 --- a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/DotNetSpec.groovy +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -import spock.lang.Specification -import spock.lang.Unroll -import wooga.gradle.dotnetsonar.utils.FakeShell - -class DotNetSpec extends Specification { - - @Unroll - def "sets up execution specifications to build a solution with given dotnet executable"() { - given: "a dotnet executable" - def executable = new File(executablePath) - and: "any solution" - def solution = new File(solutionPath) - and: "any environment" - and: "a shell executor" - def shell = new FakeShell() - - when: "setting up specification" - def dotnet = new DotNet(shell, executable) - dotnet.buildSolution(solution, environment, extraArgs) - - then: - shell.lastExecSpec.executable == executable.absolutePath - shell.lastExecSpec.args == ["build"] + [solution.absolutePath] + extraArgs - shell.lastExecSpec.environment.entrySet().containsAll(environment.entrySet()) - - where: - executablePath | solutionPath | environment | extraArgs - "dotnet.exe" | "solution.sln" | [:] | [] - "dotnet.exe" | "solution.sln" | [envVar: "envValue"] | [] - "dotnet.exe" | "solution.sln" | [envVar: "envValue"] | ["-arg"] - "dotnet.exe" | "solution.sln" | [envVar: "envValue"] | ["/arg"] - "dotnet.exe" | "solution.sln" | [envVar: "envValue"] | ["-arg", "/arg:value"] - } -} diff --git a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/MSBuildSpec.groovy b/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/MSBuildSpec.groovy deleted file mode 100644 index 05e34d7..0000000 --- a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/MSBuildSpec.groovy +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -import spock.lang.Specification -import spock.lang.Unroll -import wooga.gradle.dotnetsonar.utils.FakeShell - -class MSBuildSpec extends Specification { - - @Unroll - def "sets up execution specifications to build a solution with given MSBuild executable"() { - given: "a MSBuild executable" - def executable = new File(executablePath) - and: "any solution" - def solution = new File(solutionPath) - and: "any environment" - and: "a shell executor" - def shell = new FakeShell() - - when: "setting up specification" - def msbuild = new MSBuild(shell, executable) - msbuild.buildSolution(solution, environment, extraArgs) - - then: - shell.lastExecSpec.executable == executable.absolutePath - shell.lastExecSpec.args == extraArgs + [solution.absolutePath] - shell.lastExecSpec.environment.entrySet().containsAll(environment.entrySet()) - - where: - executablePath | solutionPath | environment | extraArgs - "msbuild.exe" | "solution.sln" | [:] | [] - "msbuild.exe" | "solution.sln" | [envVar: "envValue"] | [] - "msbuild.exe" | "solution.sln" | [envVar: "envValue"] | ["-arg"] - "msbuild.exe" | "solution.sln" | [envVar: "envValue"] | ["/arg"] - "msbuild.exe" | "solution.sln" | [envVar: "envValue"] | ["/arg", "-arg:value"] - } -} diff --git a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/MonoShellSpec.groovy b/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/MonoShellSpec.groovy deleted file mode 100644 index daeb28e..0000000 --- a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/MonoShellSpec.groovy +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.tasks.internal - -import org.gradle.process.ExecSpec -import spock.lang.Specification - -import static wooga.gradle.dotnetsonar.utils.SpecFakes.argReflectingFakeExecutable -import static wooga.gradle.dotnetsonar.utils.SpecFakes.fakeShell -import static wooga.gradle.dotnetsonar.utils.SpecUtils.emptyTmpFile - -class MonoShellSpec extends Specification { - - def "sets up execution specification to be ran using given mono executable"() { - given: "a mono executable" - def monoExec = emptyTmpFile("mono") - and: "a executable file to be executed using mono" - def runExec = argReflectingFakeExecutable("executable", 0) - and: "a base shell" - def shell = fakeShell() - - when: "executing given file using gradle mono shell" - def monoShell = new MonoShell(shell, monoExec) - monoShell.execute { ExecSpec exec -> - exec.executable = runExec.absolutePath - exec.args = ["arg1", "arg2"] - } - - then: "spec should run using mono" - shell.lastExecSpec.executable == monoExec.absolutePath - and: "executable file and its arguments must be present in order in the argument list" - shell.lastExecSpec.args == [runExec.absolutePath, "arg1", "arg2"] - } -} diff --git a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerSpec.groovy b/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerSpec.groovy index 684d383..bda44f4 100644 --- a/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerSpec.groovy +++ b/src/test/groovy/wooga/gradle/dotnetsonar/tasks/internal/SonarScannerSpec.groovy @@ -19,29 +19,22 @@ package wooga.gradle.dotnetsonar.tasks.internal import spock.lang.Specification import spock.lang.Unroll -import static wooga.gradle.dotnetsonar.utils.SpecFakes.fakeShell - class SonarScannerSpec extends Specification { def "runs sonar scanner begin with given properties"() { given: "a Sonar Scanner executable with a working dir" File scannerExec = new File("sonarscanner.exe") - File workingDir = new File("a_dir") and: "a sonarqube project key, project version number, and properties" - and: "a shell executor" - def shell = fakeShell() when: "setting up execution for given sonar scanner executable begin with project key, version and properties" - def sonarScanner = new SonarScanner(shell, scannerExec, workingDir) - sonarScanner.begin(projectKey, projectName, version, sonarProperties) + def sonarScanner = new SonarScanner(scannerExec) + def args = sonarScanner.beginArgs(projectKey, projectName, version, sonarProperties) def expectedArgs = ["begin", "-k:${projectKey}", "-n:${projectName}", "-v:${version}"] expectedArgs.addAll(sonarProperties.entrySet().collect {"-d:${it.key}=${it.value}"}) then: - shell.lastExecSpec.executable == scannerExec.absolutePath - shell.lastExecSpec.workingDir == workingDir - shell.lastExecSpec.args == expectedArgs + args == [scannerExec.absolutePath] + expectedArgs where: projectKey | projectName | version | sonarProperties @@ -54,18 +47,15 @@ class SonarScannerSpec extends Specification { def "ignores redundant property #property on begin"() { given: "a Sonar Scanner executable with a working dir" File scannerExec = new File("sonarscanner.exe") - File workingDir = new File("a_dir") and: "one of sonarqube properties that should be ignored by SonarScanner" def propToBeIgnored = [property: value] - and: "a shell executor" - def shell = fakeShell() when: "setting up execution for given sonar scanner executable begin with project key, version and properties" - def sonarScanner = new SonarScanner(shell, scannerExec, workingDir) - sonarScanner.begin("pjkey", "pjname", "pjversion", propToBeIgnored) + def sonarScanner = new SonarScanner(scannerExec) + def args = sonarScanner.beginArgs("pjkey", "pjname", "pjversion", propToBeIgnored) then: - !shell.lastExecSpec.args.contains("-d:${property}=${value}") + !args.contains("-d:${property}=${value}") where: property | value @@ -78,19 +68,14 @@ class SonarScannerSpec extends Specification { def "runs sonar scanner end with given properties"() { given: "a Sonar Scanner executable with a working dir" File scannerExec = new File("sonarscanner.exe") - File workingDir = new File("a_dir") and: "a sonarqube login token" def sonarToken = "token" - and: "a shell executor" - def shell = fakeShell() when: "setting up execution for given sonar scanner executable begin with project key, version and properties" - def sonarScanner = new SonarScanner(shell, scannerExec, workingDir) - sonarScanner.end(sonarToken) + def sonarScanner = new SonarScanner(scannerExec) + def args = sonarScanner.endArgs(sonarToken) then: - shell.lastExecSpec.executable == scannerExec.absolutePath - shell.lastExecSpec.workingDir == workingDir - shell.lastExecSpec.args == ["end", "-d:sonar.login=${sonarToken}"] + args == [scannerExec.absolutePath, "end", "-d:sonar.login=${sonarToken}"] } } diff --git a/src/test/groovy/wooga/gradle/dotnetsonar/utils/FakeExecutable.groovy b/src/test/groovy/wooga/gradle/dotnetsonar/utils/FakeExecutable.groovy deleted file mode 100644 index e49d2d6..0000000 --- a/src/test/groovy/wooga/gradle/dotnetsonar/utils/FakeExecutable.groovy +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.utils - -import nebula.test.functional.ExecutionResult -import org.gradle.internal.impldep.org.apache.commons.lang.StringUtils - -import java.nio.file.Path - -import static SpecUtils.isWindows - -class FakeExecutable { - - static File runFirstParam(Path fakeFilePath, boolean overwrites=true) { - File fakeExec = setupExecutableFile(fakeFilePath, overwrites) - if(isWindows()) { - //https://stackoverflow.com/questions/935609/batch-parameters-everything-after-1 - fakeExec << """ - @echo off - echo [[${fakeExec.name}]] - for /f "tokens=1,* delims= " %%a in ("%*") do set ALL_BUT_FIRST=%%b - call %1 %ALL_BUT_FIRST% - echo [[end ${fakeExec.name}]] - exit %errorlevel% - """.stripIndent() - } else { - //running subscript with '.' in practice includes it on the mother script, including its parameters - fakeExec << - """#!/usr/bin/env bash - echo [[mono]] - fst_param=\$1 - shift - . "\${fst_param}" - echo [[end mono]] - exit \$? - """.stripIndent() - } - } - - static File argsReflector(Path fakeFilePath, int exitCode, boolean overwrites=true) { - File fakeExec = setupExecutableFile(fakeFilePath, overwrites) - if (isWindows()) { - fakeExec << """ - @echo off - echo [[${fakeExec.name}]] - echo [[arguments]] - echo %* - echo [[environment]] - set - echo [[end]] - echo [[end ${fakeExec.name}]] - exit ${exitCode} - """.stripIndent() - } else { - fakeExec << """ - #!/usr/bin/env bash - echo [[${fakeExec.name}]] - echo [[arguments]] - echo \$@ - echo [[environment]] - env - echo [[end]] - echo [[end ${fakeExec.name}]] - exit ${exitCode} - """.stripIndent() - } - } - - private static File setupExecutableFile(Path fakeFilePath, boolean overwrites) { - File fakeExec = fakeFilePath.toFile() - if (fakeExec.exists()) { - if (overwrites) { - fakeExec.delete() - } else { - throw new IllegalArgumentException("File ${fakeFilePath} already exists") - } - } - fakeExec.createNewFile() - fakeExec.executable = true - return fakeExec - } - - static Result lastExecutionResults(ExecutionResult executionResult) { - return lastExecutionResults(executionResult.standardOutput) - } - - static Result lastExecutionResults(String stdout) { - return new Result(stdout) - } - - - static Result executionResults(File file, ExecutionResult executionResult) { - return new Result(file, executionResult.standardOutput) - } - - static class Result { - private final File file; - private final ArrayList args; - private final Map envs; - - Result(String stdOutput) { - this(null, stdOutput) - } - - Result(File file, String stdOutput) { - this.file = file - this.args = loadArgs(file, stdOutput) - this.envs = loadEnvs(file, stdOutput) - } - - ArrayList getArgs() { - return args - } - - Map getEnvs() { - return envs - } - - private static ArrayList loadArgs(File file, String stdOutput) { - def logs = stdOutput - if(file != null) { - logs = substringBetween(stdOutput, "[[${file.name}]]", "[[end ${file.name}]]") - } - loadArgs(logs) - } - - private static Map loadEnvs(File file, String stdOutput) { - def logs = stdOutput - if(file != null) { - logs = substringBetween(stdOutput, "[[${file.name}]]", "[[end ${file.name}]]") - } - return loadEnvs(logs) - } - - private static ArrayList loadArgs(String stdOutput) { - def lastExecutionOffset = stdOutput.lastIndexOf("[[arguments]]") - if(lastExecutionOffset < 0) { - System.out.println(stdOutput) - throw new IllegalArgumentException("stdout does not contains a execution of a file generated by " + - "FakeExecutable.argsReflector") - } - def lastExecTailString = stdOutput.substring(lastExecutionOffset) - def argsString = substringBetween(lastExecTailString, "[[arguments]]", "[[environment]]"). - replace("[[arguments]]", "") - def parts = argsString.split(" "). - findAll {!StringUtils.isEmpty(it) }.collect{ it.trim() } - return parts - } - - private static Map loadEnvs(String stdOutput) { - def argsString = substringBetween(stdOutput, "[[environment]]", "[[end]]"). - replace("[[environment]]", "") - def parts = argsString.split(System.lineSeparator()). - findAll {!StringUtils.isEmpty(it) }.collect{ it.trim() } - return parts.collectEntries { - return it.split("=", 2) - } - } - } - - private static String substringBetween(String base, String from, String to) { - def customArgsIndex = base.indexOf(from) - def tailString = base.substring(customArgsIndex) - def endIndex = tailString.indexOf(to) - return tailString.substring(0, endIndex) - } -} diff --git a/src/test/groovy/wooga/gradle/dotnetsonar/utils/FakeShell.groovy b/src/test/groovy/wooga/gradle/dotnetsonar/utils/FakeShell.groovy deleted file mode 100644 index 0b18964..0000000 --- a/src/test/groovy/wooga/gradle/dotnetsonar/utils/FakeShell.groovy +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.utils - - -import org.gradle.process.ExecResult -import org.gradle.process.ExecSpec -import org.gradle.process.internal.DefaultExecSpec -import org.gradle.process.internal.ExecException -import wooga.gradle.dotnetsonar.tasks.internal.Shell -import wooga.gradle.dotnetsonar.tasks.internal.ShellResult - -import java.util.function.Consumer - -class FakeShell implements Shell { - - private ExecSpec lastExecSpec - private int exitStatus - - FakeShell(int exitStatus=0) { - this.exitStatus = exitStatus - } - - @Override - ShellResult execute(boolean logging=true, Consumer execSpecClosure) { - ExecSpec spec = new DefaultExecSpec(SpecFakes.fakeResolver()) - execSpecClosure(spec) - this.lastExecSpec = spec - return new ShellResult(new ExecResult() { - @Override - int getExitValue() { return exitStatus } - @Override - ExecResult assertNormalExitValue() throws ExecException { - if(exitStatus > 0) { - throw new ExecException("") - } - return this - } - @Override - ExecResult rethrowFailure() throws ExecException { return this } - }, null, null) - } - - ExecSpec getLastExecSpec() { - return lastExecSpec - } -} diff --git a/src/test/groovy/wooga/gradle/dotnetsonar/utils/SpecFakes.groovy b/src/test/groovy/wooga/gradle/dotnetsonar/utils/SpecFakes.groovy deleted file mode 100644 index 36f4c2e..0000000 --- a/src/test/groovy/wooga/gradle/dotnetsonar/utils/SpecFakes.groovy +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2021 Wooga GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package wooga.gradle.dotnetsonar.utils - - -import org.gradle.internal.file.PathToFileResolver - -import java.nio.file.Paths - -import static SpecUtils.isWindows - -class SpecFakes { - - static File argReflectingFakeExecutable(String fakeFilePath, exitCode = 0) { - String osAwareFakePath = isWindows() && !fakeFilePath.endsWith(".bat")? - "${fakeFilePath}.bat" : - fakeFilePath - def fakeExecFile = FakeExecutable.argsReflector(Paths.get(osAwareFakePath), exitCode) - fakeExecFile.deleteOnExit() - return fakeExecFile - } - - static File runFirstParameterFakeExecutable(String fakeFilePath) { - String osAwareFakePath = isWindows() && !fakeFilePath.endsWith(".bat")? - "${fakeFilePath}.bat" : - fakeFilePath - def fakeExecFile = FakeExecutable.runFirstParam(Paths.get(osAwareFakePath)) - fakeExecFile.deleteOnExit() - return fakeExecFile - } - - - static PathToFileResolver fakeResolver() { - return new PathToFileResolver() { - @Override - File resolve(Object o) { return o as File } - @Override - PathToFileResolver newResolver(File file) { return this } - @Override - boolean canResolveRelativePath() { return false } - } - } - - static FakeShell fakeShell() { - return new FakeShell() - } -}