diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index b78a21d6..daec9e89 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - beta pull_request: {} workflow_dispatch: {} diff --git a/detekt-baseline.xml b/detekt-baseline.xml index 22944c8b..7ac09705 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -19,16 +19,13 @@ MaxLineLength:SpotBugsExtension.kt$SpotBugsExtension$* Property to specify the name of project. Some reporting formats use this property. Default value is the name of your Gradle project. MaxLineLength:SpotBugsHtmlReport.kt$SpotBugsHtmlReport$configuration.files { dependency: Dependency -> dependency.group == "com.github.spotbugs" && dependency.name == "spotbugs" } MaxLineLength:SpotBugsRunnerForHybrid.kt$SpotBugsRunnerForHybrid.Companion$* - MaxLineLength:SpotBugsRunnerForWorker.kt$SpotBugsRunnerForWorker$"Spotbugs will be executed using Java Toolchain configuration: Vendor: {} | Version: {}" MaxLineLength:SpotBugsTask.kt$SpotBugsTask$* MaxLineLength:SpotBugsTask.kt$SpotBugsTask$* Property to set the directory to generate report files. Default is {@code "$buildDir/reports/spotbugs/$taskName"}. MaxLineLength:SpotBugsTask.kt$SpotBugsTask$* Property to specify the extra arguments for JVM process. Default value is empty so JVM process will get no extra argument. MaxLineLength:SpotBugsTask.kt$SpotBugsTask$* Property to specify the extra arguments for SpotBugs. Default value is empty so SpotBugs will get no extra argument. MaxLineLength:SpotBugsTask.kt$SpotBugsTask$* Property to specify the release identifier of project. Some reporting formats use this property. Default value is the version of your Gradle project. MaxLineLength:SpotBugsTask.kt$SpotBugsTask$fun - NestedBlockDepth:SpotBugsRunnerForWorker.kt$SpotBugsRunnerForWorker.SpotBugsExecutor$override fun execute() TooGenericExceptionCaught:SpotBugsRunner.kt$SpotBugsRunner$e: Exception - TooGenericExceptionCaught:SpotBugsRunnerForWorker.kt$SpotBugsRunnerForWorker.SpotBugsExecutor$e: Exception TooManyFunctions:SpotBugsReport.kt$SpotBugsReport : SingleFileReportCustomizableHtmlReport diff --git a/package.json b/package.json index 93487745..a889234d 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,11 @@ "branches": [ { "name": "master" + }, + { + "channel": "beta", + "name": "beta", + "prerelease": true } ], "plugins": [ diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy index 3850f6c5..8a1e99dc 100644 --- a/src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy @@ -122,7 +122,6 @@ task spotbugsMain(type: com.github.spotbugs.snom.SpotBugsTask) { } def runner = gradleRunner .withArguments(arguments) - .withDebug(true) def result = runner.buildAndFail() diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/GradleJavaToolchainsSupportFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/GradleJavaToolchainsSupportFunctionalTest.groovy index 781ce5fa..c2504512 100644 --- a/src/functionalTest/groovy/com/github/spotbugs/snom/GradleJavaToolchainsSupportFunctionalTest.groovy +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/GradleJavaToolchainsSupportFunctionalTest.groovy @@ -52,19 +52,13 @@ public class Foo { """ new File(rootDir, "settings.gradle.kts") << """ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version("0.6.0") + id("org.gradle.toolchains.foojay-resolver-convention") version("0.7.0") } """ } @Unroll def 'Supports Gradle Java Toolchains (#processConfiguration)'() { - setup: - buildFile << """ - spotbugs { - useJavaToolchains = true - }""" - when: def arguments = [':spotbugsMain', '-is'] arguments.add(processConfigurationArgument) @@ -82,11 +76,16 @@ plugins { processConfiguration | processConfigurationArgument 'javaexec' | '-Pcom.github.spotbugs.snom.worker=false' 'worker-api' | '-Pcom.github.spotbugs.snom.worker=true' - 'javaexec-in-worker' | '-Pcom.github.spotbugs.snom.javaexec-in-worker=true' } @Unroll - def 'Do not use Gradle Java Toolchains if extension is not configured (#processConfiguration)'() { + def 'Do not use Gradle Java Toolchains if extension is disabled explicitly (#processConfiguration)'() { + setup: + buildFile << """ + spotbugs { + useJavaToolchains = false + }""" + when: def arguments = [':spotbugsMain', '-is'] arguments.add(processConfigurationArgument) @@ -105,6 +104,5 @@ plugins { processConfiguration | processConfigurationArgument 'javaexec' | '-Pcom.github.spotbugs.snom.worker=false' 'worker-api' | '-Pcom.github.spotbugs.snom.worker=true' - 'javaexec-in-worker' | '-Pcom.github.spotbugs.snom.javaexec-in-worker=true' } } diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/KotlinBuildScriptFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/KotlinBuildScriptFunctionalTest.groovy index e6744b29..e7a20e9c 100644 --- a/src/functionalTest/groovy/com/github/spotbugs/snom/KotlinBuildScriptFunctionalTest.groovy +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/KotlinBuildScriptFunctionalTest.groovy @@ -15,6 +15,7 @@ package com.github.spotbugs.snom import org.gradle.testkit.runner.BuildResult import org.gradle.util.GradleVersion +import spock.lang.Ignore import spock.lang.IgnoreIf import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -86,6 +87,7 @@ spotbugs { result.task(":spotbugsMain").outcome == SUCCESS } + @Ignore("because output does not contain the message generated by SpotBugs") def "can add plugins by spotbugsPlugins configuration"() { setup: buildFile << """ @@ -96,7 +98,7 @@ dependencies { when: def result = gradleRunner - .withArguments('check', "-Pcom.github.spotbugs.snom.javaexec-in-worker=false") + .withArguments('check') .build() then: diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy index f127e33b..9b468032 100644 --- a/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy @@ -15,6 +15,7 @@ package com.github.spotbugs.snom import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.TaskOutcome +import spock.lang.Ignore import spock.lang.Unroll import java.nio.file.Paths @@ -167,7 +168,7 @@ spotbugsMain { TaskOutcome.UP_TO_DATE == result.task(":spotbugsMain").outcome } - def 'ignore missing classes (Hybrid API? #isHybridApi)'() { + def 'ignore missing classes'() { given: def code = new File(rootDir, 'src/main/java/Bar.java') code << ''' @@ -191,7 +192,6 @@ spotbugsMain { ':spotbugsMain', '-is' ] - arguments.add('-Pcom.github.spotbugs.snom.javaexec-in-worker=' + isHybridApi) def runner = gradleRunner .withArguments(arguments) @@ -199,9 +199,6 @@ spotbugsMain { then: result.task(':spotbugsMain').outcome == SUCCESS - - where: - isHybridApi << [true, false] } @Unroll @@ -412,6 +409,7 @@ public class Foo { result.task(":spotbugsMain").outcome == SUCCESS } + @Ignore("because output does not contain the message generated by SpotBugs") def "can apply plugin"() { given: buildFile << """ @@ -420,7 +418,7 @@ dependencies{ }""" when: BuildResult result = gradleRunner - .withArguments("spotbugsMain", "-Pcom.github.spotbugs.snom.javaexec-in-worker=false") + .withArguments("spotbugsMain") .build() then: @@ -429,6 +427,7 @@ dependencies{ !result.output.contains("Trying to add already registered factory") } + @Ignore("because output does not contain the message generated by SpotBugs") def "can apply plugin to multiple tasks"() { given: buildFile << """ @@ -450,7 +449,7 @@ public class FooTest { }""" when: BuildResult result = gradleRunner - .withArguments("spotbugsMain", "spotbugsTest", "-Pcom.github.spotbugs.snom.javaexec-in-worker=false") + .withArguments("spotbugsMain", "spotbugsTest") .build() then: @@ -585,7 +584,6 @@ spotbugsMain { } def runner = gradleRunner .withArguments(arguments) - .withDebug(true) def result = runner.buildAndFail() @@ -653,7 +651,6 @@ spotbugs { } def runner = gradleRunner .withArguments(arguments) - .withDebug(true) def result = runner.build() diff --git a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt index fc4d840b..932d0661 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt @@ -32,7 +32,6 @@ class SpotBugsBasePlugin : Plugin { createConfiguration(project, extension) createPluginConfiguration(project.configurations) val enableWorkerApi = getPropertyOrDefault(project, FEATURE_FLAG_WORKER_API, "true") - val enableHybridWorker = getPropertyOrDefault(project, FEATURE_FLAG_HYBRID_WORKER, "true") project .tasks .withType(SpotBugsTask::class.java) @@ -40,7 +39,6 @@ class SpotBugsBasePlugin : Plugin { task.init( extension, enableWorkerApi.toBoolean(), - enableHybridWorker.toBoolean(), ) } } @@ -77,7 +75,7 @@ class SpotBugsBasePlugin : Plugin { }, ) extension.useAuxclasspathFile.convention(true) - extension.useJavaToolchains.convention(false) + extension.useJavaToolchains.convention(true) return extension } @@ -163,7 +161,6 @@ class SpotBugsBasePlugin : Plugin { companion object { private const val FEATURE_FLAG_WORKER_API = "com.github.spotbugs.snom.worker" - private const val FEATURE_FLAG_HYBRID_WORKER = "com.github.spotbugs.snom.javaexec-in-worker" private const val DEFAULT_REPORTS_DIR_NAME = "spotbugs" /** diff --git a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt index 59582281..dae3e4f9 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt @@ -16,7 +16,6 @@ package com.github.spotbugs.snom import com.github.spotbugs.snom.internal.SpotBugsHtmlReport import com.github.spotbugs.snom.internal.SpotBugsRunnerForHybrid import com.github.spotbugs.snom.internal.SpotBugsRunnerForJavaExec -import com.github.spotbugs.snom.internal.SpotBugsRunnerForWorker import com.github.spotbugs.snom.internal.SpotBugsSarifReport import com.github.spotbugs.snom.internal.SpotBugsTextReport import com.github.spotbugs.snom.internal.SpotBugsXmlReport @@ -50,7 +49,6 @@ import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.workers.WorkerExecutor import org.slf4j.LoggerFactory -import java.nio.file.Path import javax.inject.Inject /** @@ -263,7 +261,7 @@ abstract class SpotBugsTask : DefaultTask(), VerificationTask { abstract val useAuxclasspathFile: Property @get:Internal - lateinit var auxclasspathFile: Path + abstract val auxclasspathFile: RegularFileProperty /** * Property to specify the target classes to analyse by SpotBugs. @@ -283,7 +281,6 @@ abstract class SpotBugsTask : DefaultTask(), VerificationTask { } private var enableWorkerApi: Boolean = true - private var enableHybridWorker: Boolean = true @get:Internal abstract val pluginJarFiles: ConfigurableFileCollection @@ -328,10 +325,8 @@ abstract class SpotBugsTask : DefaultTask(), VerificationTask { fun init( extension: SpotBugsExtension, enableWorkerApi: Boolean, - enableHybridWorker: Boolean, ) { - // TODO use Property - this.auxclasspathFile = project.layout.buildDirectory.file("spotbugs/auxclasspath/$name").get().asFile.toPath() + this.auxclasspathFile.convention(project.layout.buildDirectory.file("spotbugs/auxclasspath/$name")) ignoreFailures.convention(extension.ignoreFailures) showStackTraces.convention(extension.showStackTraces) @@ -358,9 +353,8 @@ abstract class SpotBugsTask : DefaultTask(), VerificationTask { } this.enableWorkerApi = enableWorkerApi - this.enableHybridWorker = enableHybridWorker - analyseClassFile.set(project.buildDir.resolve(this.name + "-analyse-class-file.txt")) + analyseClassFile.set(project.layout.buildDirectory.file("${this.name}-analyse-class-file.txt")) val pluginConfiguration = project.configurations.getByName(SpotBugsPlugin.PLUGINS_CONFIG_NAME) pluginJarFiles.from( @@ -388,15 +382,12 @@ abstract class SpotBugsTask : DefaultTask(), VerificationTask { @TaskAction fun run() { - if (!enableWorkerApi) { - log.info("Running SpotBugs by JavaExec...") - SpotBugsRunnerForJavaExec(launcher).run(this) - } else if (enableHybridWorker) { + if (enableWorkerApi) { log.info("Running SpotBugs by Gradle no-isolated Worker...") SpotBugsRunnerForHybrid(workerExecutor, launcher).run(this) } else { - log.info("Running SpotBugs by Gradle process-isolated Worker...") - SpotBugsRunnerForWorker(workerExecutor, launcher).run(this) + log.info("Running SpotBugs by JavaExec...") + SpotBugsRunnerForJavaExec(launcher).run(this) } } diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunner.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunner.kt index c7da03ac..7b48b79a 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunner.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunner.kt @@ -117,7 +117,10 @@ abstract class SpotBugsRunner { .map { obj: File -> obj.absolutePath } .collect(Collectors.joining("\n")) try { - val auxClasspathFile = task.auxclasspathFile + val auxClasspathFile = + task.auxclasspathFile.map { + it.asFile.toPath() + }.get() try { Files.createDirectories(auxClasspathFile.parent) if (!Files.exists(auxClasspathFile)) { diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForWorker.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForWorker.kt deleted file mode 100644 index d746a585..00000000 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForWorker.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2021 SpotBugs team - * - *

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 com.github.spotbugs.snom.internal - -import com.github.spotbugs.snom.SpotBugsReport -import com.github.spotbugs.snom.SpotBugsTask -import edu.umd.cs.findbugs.DetectorFactoryCollection -import edu.umd.cs.findbugs.FindBugs -import edu.umd.cs.findbugs.FindBugs2 -import edu.umd.cs.findbugs.TextUICommandLine -import org.gradle.api.GradleException -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.ListProperty -import org.gradle.api.provider.Property -import org.gradle.jvm.toolchain.JavaLauncher -import org.gradle.process.JavaForkOptions -import org.gradle.workers.WorkAction -import org.gradle.workers.WorkParameters -import org.gradle.workers.WorkerExecutor -import org.slf4j.LoggerFactory -import java.io.File -import java.net.URI -import java.nio.file.Path -import java.util.stream.Collectors -import javax.inject.Inject - -@Deprecated("Will be removed in v6 release") -class SpotBugsRunnerForWorker - @Inject - constructor( - private val workerExecutor: WorkerExecutor, - private val javaLauncher: Property, - ) : SpotBugsRunner() { - private val log = LoggerFactory.getLogger(SpotBugsRunnerForWorker::class.java) - - override fun run(task: SpotBugsTask) { - val workerQueue = - workerExecutor.processIsolation { spec -> - spec.classpath.setFrom(task.spotbugsClasspath) - spec.forkOptions { option: JavaForkOptions -> - option.jvmArgs(buildJvmArguments(task)) - val maxHeapSize = task.maxHeapSize.getOrNull() - if (maxHeapSize != null) { - option.maxHeapSize = maxHeapSize - } - if (javaLauncher.isPresent) { - log.info( - "Spotbugs will be executed using Java Toolchain configuration: Vendor: {} | Version: {}", - javaLauncher.get().metadata.vendor, - javaLauncher.get().metadata.languageVersion.asInt(), - ) - option.executable = javaLauncher.get().executablePath.asFile.absolutePath - } - } - } - workerQueue.submit(SpotBugsExecutor::class.java) { params -> - params.getArguments().addAll(buildArguments(task)) - params.getIgnoreFailures().set(task.getIgnoreFailures()) - params.getShowStackTraces().set(task.showStackTraces) - task.getRequiredReports() - .map(SpotBugsReport::getOutputLocation) - .forEach(params.getReports()::add) - } - } - - interface SpotBugsWorkParameters : WorkParameters { - fun getArguments(): ListProperty - - fun getIgnoreFailures(): Property - - fun getShowStackTraces(): Property - - fun getReports(): ListProperty - } - - abstract class SpotBugsExecutor : WorkAction { - private val log = LoggerFactory.getLogger(SpotBugsExecutor::class.java) - - override fun execute() { - val args = parameters.getArguments().get().toTypedArray() - DetectorFactoryCollection.resetInstance(DetectorFactoryCollection()) - - try { - edu.umd.cs.findbugs.Version.printVersion(false) - FindBugs2().use { findBugs2 -> - val commandLine = TextUICommandLine() - FindBugs.processCommandLine(commandLine, args, findBugs2) - findBugs2.execute() - - val message = - buildString { - if (findBugs2.errorCount > 0) { - append(findBugs2.errorCount).append(" SpotBugs errors were found.") - } - if (findBugs2.bugCount > 0) { - if (isNotEmpty()) { - append(' ') - } - append(findBugs2.bugCount) - append(" SpotBugs violations were found.") - } - } - if (message.isNotEmpty()) { - val reportLocation = - buildString { - val reportPaths = - parameters.getReports().get().stream() - .map(RegularFile::getAsFile) - .map(File::toPath) - .map(Path::toUri) - .map(URI::toString) - .collect(Collectors.toList()) - if (reportPaths.isNotEmpty()) { - append("See the report at: ") - append(reportPaths.joinToString(", ")) - } - } - - val e = GradleException(message + reportLocation) - if (parameters.getIgnoreFailures().getOrElse(false)) { - log.warn(message) - log.warn(reportLocation) - if (parameters.getShowStackTraces().getOrElse(false)) { - log.warn("", e) - } - } else { - throw e - } - } - } - } catch (e: GradleException) { - throw e - } catch (e: Exception) { - throw GradleException("Verification failed: SpotBugs execution thrown exception", e) - } - } - } - }