From 024889467cc751026f8d1b90941eacf4f1ac54f5 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 5 Dec 2023 08:34:05 +0800 Subject: [PATCH] misc: refine Kotlin styles (#1053) * Add editorconfig rules for Kotlin * Reformat * Rearrange --- .editorconfig | 7 + .../com/github/spotbugs/snom/Confidence.kt | 2 +- .../spotbugs/snom/SpotBugsBasePlugin.kt | 6 +- .../github/spotbugs/snom/SpotBugsReport.kt | 173 +++++++++--------- .../com/github/spotbugs/snom/SpotBugsTask.kt | 11 +- .../snom/internal/SpotBugsHtmlReport.kt | 104 +++++------ .../spotbugs/snom/internal/SpotBugsRunner.kt | 6 +- .../snom/internal/SpotBugsRunnerForHybrid.kt | 138 +++++++------- .../internal/SpotBugsRunnerForJavaExec.kt | 140 +++++++------- .../snom/internal/SpotBugsSarifReport.kt | 24 +-- .../snom/internal/SpotBugsTextReport.kt | 30 +-- .../snom/internal/SpotBugsXmlReport.kt | 30 +-- 12 files changed, 327 insertions(+), 344 deletions(-) diff --git a/.editorconfig b/.editorconfig index 203d331c..c8e6cb46 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,13 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true +[*.{kt,kts}] +ij_kotlin_imports_layout = * +ij_kotlin_allow_trailing_comma = true +ij_kotlin_allow_trailing_comma_on_call_site = true +ij_kotlin_packages_to_use_import_on_demand = unset +ktlint_code_style = intellij_idea + [*.md] trim_trailing_whitespace = false diff --git a/src/main/kotlin/com/github/spotbugs/snom/Confidence.kt b/src/main/kotlin/com/github/spotbugs/snom/Confidence.kt index 8e023dd8..dc2fe55c 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/Confidence.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/Confidence.kt @@ -13,8 +13,8 @@ */ package com.github.spotbugs.snom -import org.gradle.api.tasks.Internal import java.util.Optional +import org.gradle.api.tasks.Internal /** * The [Confidence] is used to specify the level to report bugs. Lower level contains more diff --git a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt index 932d0661..7fa4e333 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsBasePlugin.kt @@ -13,6 +13,9 @@ */ package com.github.spotbugs.snom +import java.io.IOException +import java.io.UncheckedIOException +import java.util.Properties import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.ConfigurationContainer @@ -20,9 +23,6 @@ import org.gradle.api.file.Directory import org.gradle.api.plugins.ReportingBasePlugin import org.gradle.api.reporting.ReportingExtension import org.gradle.util.GradleVersion -import java.io.IOException -import java.io.UncheckedIOException -import java.util.Properties class SpotBugsBasePlugin : Plugin { override fun apply(project: Project) { diff --git a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsReport.kt b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsReport.kt index 29bb8126..64474b5f 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsReport.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsReport.kt @@ -14,6 +14,8 @@ package com.github.spotbugs.snom import groovy.lang.Closure +import java.io.File +import javax.inject.Inject import org.gradle.api.Action import org.gradle.api.file.RegularFileProperty import org.gradle.api.model.ObjectFactory @@ -25,109 +27,104 @@ import org.gradle.api.reporting.SingleFileReport import org.gradle.api.resources.TextResource import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal -import java.io.File -import javax.inject.Inject -abstract class SpotBugsReport - @Inject - constructor( - objects: ObjectFactory, - @get:Internal - protected val task: SpotBugsTask, - ) : - SingleFileReport, CustomizableHtmlReport { // to expose CustomizableHtmlReport#setStylesheet to build script - private val destination: RegularFileProperty - private val isRequired: Property - - init { - destination = objects.fileProperty() - isRequired = objects.property(Boolean::class.java).convention(true) - } +abstract class SpotBugsReport @Inject constructor( + objects: ObjectFactory, + @get:Internal + protected val task: SpotBugsTask, +) : SingleFileReport, CustomizableHtmlReport { // to expose CustomizableHtmlReport#setStylesheet to build script + private val destination: RegularFileProperty + private val isRequired: Property + + init { + destination = objects.fileProperty() + isRequired = objects.property(Boolean::class.java).convention(true) + } - abstract fun toCommandLineOption(): String + abstract fun toCommandLineOption(): String - @Internal - @Deprecated("use {@link #getOutputLocation()} instead.") - fun getDestination(): File { - return destination.get().asFile - } + @Internal + @Deprecated("use {@link #getOutputLocation()} instead.") + fun getDestination(): File { + return destination.get().asFile + } - override fun getOutputLocation(): RegularFileProperty { - return destination - } + override fun getOutputLocation(): RegularFileProperty { + return destination + } - @Internal("This property returns always same value") - override fun getOutputType(): Report.OutputType { - return Report.OutputType.FILE - } + @Internal("This property returns always same value") + override fun getOutputType(): Report.OutputType { + return Report.OutputType.FILE + } - @Input - override fun getRequired(): Property { - return isRequired - } + @Input + override fun getRequired(): Property { + return isRequired + } - @get:Deprecated("use {@link #getRequired()} instead.") - @get:Internal - @set:Deprecated("use {@code getRequired().set(value)} instead.") - var isEnabled: Boolean - get() = isRequired.get() - set(b) { - isRequired.set(b) - } - - @Deprecated("use {@code getRequired().set(provider)} instead.") - fun setEnabled(provider: Provider) { - isRequired.set(provider) + @get:Deprecated("use {@link #getRequired()} instead.") + @get:Internal + @set:Deprecated("use {@code getRequired().set(value)} instead.") + var isEnabled: Boolean + get() = isRequired.get() + set(b) { + isRequired.set(b) } - @Deprecated("use {@code getOutputLocation().set(file)} instead.") - override fun setDestination(file: File) { - destination.set(file) - } + @Deprecated("use {@code getRequired().set(provider)} instead.") + fun setEnabled(provider: Provider) { + isRequired.set(provider) + } - @Deprecated("use {@code getOutputLocation().set(provider)} instead.") - fun setDestination(provider: Provider) { - destination.set(task.project.layout.file(provider)) - } + @Deprecated("use {@code getOutputLocation().set(file)} instead.") + override fun setDestination(file: File) { + destination.set(file) + } - override fun configure(closure: Closure): Report { - return configure { report -> - closure.delegate = report - closure.call(report) - } - } + @Deprecated("use {@code getOutputLocation().set(provider)} instead.") + fun setDestination(provider: Provider) { + destination.set(task.project.layout.file(provider)) + } - @Suppress("MemberVisibilityCanBePrivate") - fun configure(action: Action): Report { - action.execute(this) - return this + override fun configure(closure: Closure): Report { + return configure { report -> + closure.delegate = report + closure.call(report) } + } - @Internal("This property provides only a human readable name.") - override fun getDisplayName(): String { - return String.format("%s type report generated by the task %s", name, task.path) - } + @Suppress("MemberVisibilityCanBePrivate") + fun configure(action: Action): Report { + action.execute(this) + return this + } - // TODO adding an @Input triggers 'cannot be serialized' exception - override fun getStylesheet(): TextResource? { - return null - } + @Internal("This property provides only a human readable name.") + override fun getDisplayName(): String { + return String.format("%s type report generated by the task %s", name, task.path) + } - override fun setStylesheet(textResource: TextResource?) { - throw UnsupportedOperationException( - String.format( - "stylesheet property is not available in the %s type report", - name, - ), - ) - } + // TODO adding an @Input triggers 'cannot be serialized' exception + override fun getStylesheet(): TextResource? { + return null + } - open fun setStylesheet(path: String?) { - throw UnsupportedOperationException( - String.format( - "stylesheet property is not available in the %s type report", - name, - ), - ) - } + override fun setStylesheet(textResource: TextResource?) { + throw UnsupportedOperationException( + String.format( + "stylesheet property is not available in the %s type report", + name, + ), + ) + } + + open fun setStylesheet(path: String?) { + throw UnsupportedOperationException( + String.format( + "stylesheet property is not available in the %s type report", + name, + ), + ) } +} diff --git a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt index f59062e1..2f85069e 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/SpotBugsTask.kt @@ -19,6 +19,7 @@ import com.github.spotbugs.snom.internal.SpotBugsRunnerForJavaExec import com.github.spotbugs.snom.internal.SpotBugsSarifReport import com.github.spotbugs.snom.internal.SpotBugsTextReport import com.github.spotbugs.snom.internal.SpotBugsXmlReport +import javax.inject.Inject import org.gradle.api.Action import org.gradle.api.DefaultTask import org.gradle.api.InvalidUserDataException @@ -49,7 +50,6 @@ import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.workers.WorkerExecutor import org.slf4j.LoggerFactory -import javax.inject.Inject /** * The Gradle task to run the SpotBugs analysis. All properties are optional. @@ -272,12 +272,9 @@ abstract class SpotBugsTask : DefaultTask(), VerificationTask { @get:SkipWhenEmpty var classes: FileCollection? = null get() { - return field - ?: ( - classDirs.asFileTree.filter { - it.name.endsWith(".class") - } - ) + return field ?: classDirs.asFileTree.filter { + it.name.endsWith(".class") + } } private var enableWorkerApi: Boolean = true diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.kt index 6ee3f3f6..7b46237b 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.kt @@ -16,76 +16,66 @@ package com.github.spotbugs.snom.internal import com.github.spotbugs.snom.SpotBugsPlugin import com.github.spotbugs.snom.SpotBugsReport import com.github.spotbugs.snom.SpotBugsTask +import javax.inject.Inject import org.gradle.api.InvalidUserDataException import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.Dependency import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.resources.TextResource import org.gradle.api.resources.TextResourceFactory -import javax.inject.Inject -abstract class SpotBugsHtmlReport - @Inject - constructor(objects: ObjectFactory, task: SpotBugsTask) : - SpotBugsReport(objects, task) { - private val stylesheet: Property +abstract class SpotBugsHtmlReport @Inject constructor( + objects: ObjectFactory, + task: SpotBugsTask, +) : SpotBugsReport(objects, task) { + private val stylesheet: Property - init { - // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.html" - outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".html")) - stylesheet = task.project.objects.property(TextResource::class.java) - } + init { + // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.html" + outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".html")) + stylesheet = task.project.objects.property(TextResource::class.java) + } - override fun toCommandLineOption(): String { - return stylesheet.map { - "-html:" + it.asFile().absolutePath - }.getOrElse("-html") - } + override fun toCommandLineOption(): String { + return stylesheet.map { + "-html:" + it.asFile().absolutePath + }.getOrElse("-html") + } - override fun getStylesheet(): TextResource? = stylesheet.orNull + override fun getStylesheet(): TextResource? = stylesheet.orNull - private fun resolve( - path: String, - configuration: Configuration, - textResourceFactory: TextResourceFactory, - ): TextResource { - val spotbugsJar = - configuration.files { dependency: Dependency -> dependency.group == "com.github.spotbugs" && dependency.name == "spotbugs" } - .find { it.isFile } - return if (spotbugsJar != null) { - textResourceFactory - .fromArchiveEntry(spotbugsJar, path) - } else { - throw InvalidUserDataException( - "The dependency on SpotBugs not found in 'spotbugs' configuration", - ) - } + private fun resolve( + path: String, + configuration: Configuration, + textResourceFactory: TextResourceFactory, + ): TextResource { + val spotbugsJar = configuration.files { dependency -> + dependency.group == "com.github.spotbugs" && dependency.name == "spotbugs" + }.find { it.isFile } + return if (spotbugsJar != null) { + textResourceFactory.fromArchiveEntry(spotbugsJar, path) + } else { + throw InvalidUserDataException( + "The dependency on SpotBugs not found in 'spotbugs' configuration", + ) } + } - override fun setStylesheet(textResource: TextResource?) { - stylesheet.set(textResource) - } + override fun setStylesheet(textResource: TextResource?) { + stylesheet.set(textResource) + } - override fun setStylesheet(path: String?) { - if (path == null) { - stylesheet.set(null as TextResource?) - } else { - val configuration = - task - .project - .configurations - .getByName(SpotBugsPlugin.CONFIG_NAME) - val textResourceFactory = - task - .project - .resources - .text - stylesheet.set( - task.project.provider { - resolve(path, configuration, textResourceFactory) - }, - ) - } + override fun setStylesheet(path: String?) { + if (path == null) { + stylesheet.set(null as TextResource?) + } else { + val configuration = task.project.configurations.getByName(SpotBugsPlugin.CONFIG_NAME) + val textResourceFactory = task.project.resources.text + stylesheet.set( + task.project.provider { + resolve(path, configuration, textResourceFactory) + }, + ) } } +} 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 7b48b79a..2776a5d3 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunner.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunner.kt @@ -14,9 +14,6 @@ package com.github.spotbugs.snom.internal import com.github.spotbugs.snom.SpotBugsTask -import org.gradle.api.GradleException -import org.gradle.api.file.FileCollection -import org.slf4j.LoggerFactory import java.io.File import java.io.IOException import java.nio.file.Files @@ -26,6 +23,9 @@ import java.util.stream.Collectors import kotlin.Exception import kotlin.String import kotlin.collections.ArrayList +import org.gradle.api.GradleException +import org.gradle.api.file.FileCollection +import org.slf4j.LoggerFactory abstract class SpotBugsRunner { private val log = LoggerFactory.getLogger(SpotBugsRunner::class.java) diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForHybrid.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForHybrid.kt index c2b2b8cf..abb927a7 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForHybrid.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForHybrid.kt @@ -15,6 +15,11 @@ package com.github.spotbugs.snom.internal import com.github.spotbugs.snom.SpotBugsReport import com.github.spotbugs.snom.SpotBugsTask +import java.io.File +import java.net.URI +import java.nio.file.Path +import java.util.stream.Collectors +import javax.inject.Inject import org.gradle.api.Action import org.gradle.api.GradleException import org.gradle.api.file.ConfigurableFileCollection @@ -28,11 +33,6 @@ 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 /** * A {@link SpotBugsRunner} implementation that runs SpotBugs process from the worker process. This @@ -89,82 +89,78 @@ class SpotBugsRunnerForHybrid( fun getReports(): ListProperty } - abstract class SpotBugsExecutor - @Inject - constructor( - private val execOperations: ExecOperations, - ) : WorkAction { - private val log = LoggerFactory.getLogger(this.javaClass) - private lateinit var stderrOutputScanner: OutputScanner - - override fun execute() { - // TODO print version of SpotBugs and Plugins - val exitValue = - execOperations.javaexec(configureJavaExec(parameters)).rethrowFailure().exitValue - val ignoreFailures = parameters.getIgnoreFailures().getOrElse(false) - if (ignoreMissingClassFlag(exitValue) == 0) { - if (stderrOutputScanner.isFailedToReport && !ignoreFailures) { - throw GradleException("SpotBugs analysis succeeded but report generation failed") - } - return - } - - if (ignoreFailures) { - log.warn("SpotBugs ended with exit code $exitValue") - return + abstract class SpotBugsExecutor @Inject constructor( + private val execOperations: ExecOperations, + ) : WorkAction { + private val log = LoggerFactory.getLogger(this.javaClass) + private lateinit var stderrOutputScanner: OutputScanner + + override fun execute() { + // TODO print version of SpotBugs and Plugins + val exitValue = + execOperations.javaexec(configureJavaExec(parameters)).rethrowFailure().exitValue + val ignoreFailures = parameters.getIgnoreFailures().getOrElse(false) + if (ignoreMissingClassFlag(exitValue) == 0) { + if (stderrOutputScanner.isFailedToReport && !ignoreFailures) { + throw GradleException("SpotBugs analysis succeeded but report generation failed") } + return + } - val errorMessage = - buildString { - append("Verification failed: SpotBugs ended with exit code $exitValue.") - 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(", ")) - } - } - throw GradleException(errorMessage) + if (ignoreFailures) { + log.warn("SpotBugs ended with exit code $exitValue") + return } - private fun ignoreMissingClassFlag(exitValue: Int): Int { - if ((exitValue.and(MISSING_CLASS_FLAG)) == 0) { - return exitValue + val errorMessage = buildString { + append("Verification failed: SpotBugs ended with exit code $exitValue.") + 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(", ")) } - log.debug( - "MISSING_CLASS_FLAG (2) was set to the exit code, but ignore it to keep the task result stable.", - ) - return (exitValue.xor(MISSING_CLASS_FLAG)) } + throw GradleException(errorMessage) + } - private fun configureJavaExec(params: SpotBugsWorkParameters): Action { - return Action { spec -> - spec.jvmArgs = params.getJvmArgs().get() - spec.classpath(params.getClasspath()) - spec.setArgs(params.getArgs().get()) - spec.mainClass.set("edu.umd.cs.findbugs.FindBugs2") - val maxHeapSize = params.getMaxHeapSize().getOrNull() - if (maxHeapSize != null) { - spec.maxHeapSize = maxHeapSize - } - if (params.getJavaToolchainExecutablePath().isPresent) { - log.info( - "Spotbugs will be executed using Java Toolchain configuration: {}", - params.getJavaToolchainExecutablePath().get(), - ) - spec.executable = params.getJavaToolchainExecutablePath().get() - } - spec.setIgnoreExitValue(true) - stderrOutputScanner = OutputScanner(System.err) - spec.setErrorOutput(stderrOutputScanner) + private fun ignoreMissingClassFlag(exitValue: Int): Int { + if ((exitValue.and(MISSING_CLASS_FLAG)) == 0) { + return exitValue + } + log.debug( + "MISSING_CLASS_FLAG (2) was set to the exit code, but ignore it to keep the task result stable.", + ) + return (exitValue.xor(MISSING_CLASS_FLAG)) + } + + private fun configureJavaExec(params: SpotBugsWorkParameters): Action { + return Action { spec -> + spec.jvmArgs = params.getJvmArgs().get() + spec.classpath(params.getClasspath()) + spec.setArgs(params.getArgs().get()) + spec.mainClass.set("edu.umd.cs.findbugs.FindBugs2") + val maxHeapSize = params.getMaxHeapSize().getOrNull() + if (maxHeapSize != null) { + spec.maxHeapSize = maxHeapSize } + if (params.getJavaToolchainExecutablePath().isPresent) { + log.info( + "Spotbugs will be executed using Java Toolchain configuration: {}", + params.getJavaToolchainExecutablePath().get(), + ) + spec.executable = params.getJavaToolchainExecutablePath().get() + } + spec.setIgnoreExitValue(true) + stderrOutputScanner = OutputScanner(System.err) + spec.setErrorOutput(stderrOutputScanner) } } + } companion object { /** diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.kt index b562d7ca..c57e5b3b 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.kt @@ -15,6 +15,10 @@ package com.github.spotbugs.snom.internal import com.github.spotbugs.snom.SpotBugsReport import com.github.spotbugs.snom.SpotBugsTask +import java.io.File +import java.net.URI +import java.nio.file.Path +import javax.inject.Inject import org.gradle.api.Action import org.gradle.api.GradleException import org.gradle.api.file.RegularFileProperty @@ -23,85 +27,77 @@ import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.process.JavaExecSpec import org.gradle.process.internal.ExecException import org.slf4j.LoggerFactory -import java.io.File -import java.net.URI -import java.nio.file.Path -import javax.inject.Inject -class SpotBugsRunnerForJavaExec - @Inject - constructor( - private val javaLauncher: Property, - ) : SpotBugsRunner() { - private val log = LoggerFactory.getLogger(SpotBugsRunnerForJavaExec::class.java) - private lateinit var stderrOutputScanner: OutputScanner +class SpotBugsRunnerForJavaExec @Inject constructor( + private val javaLauncher: Property, +) : SpotBugsRunner() { + private val log = LoggerFactory.getLogger(SpotBugsRunnerForJavaExec::class.java) + private lateinit var stderrOutputScanner: OutputScanner - override fun run(task: SpotBugsTask) { - // TODO print version of SpotBugs and Plugins - try { - task.project.javaexec(configureJavaExec(task)).rethrowFailure().assertNormalExitValue() - if (stderrOutputScanner.isFailedToReport && !task.getIgnoreFailures()) { - throw GradleException("SpotBugs analysis succeeded but report generation failed") - } - } catch (e: ExecException) { - if (task.getIgnoreFailures()) { - log.warn( - "SpotBugs reported failures", - if (task.showStackTraces.get()) { - e - } else { - null - }, - ) - } else { - val errorMessage = - buildString { - append("Verification failed: SpotBugs execution thrown exception.") - val reportPaths = - task.getRequiredReports() - .asSequence() - .map(SpotBugsReport::getOutputLocation) - .map(RegularFileProperty::getAsFile) - .map { - it.get() - } - .map(File::toPath) - .map(Path::toUri) - .map(URI::toString) - .toList() - if (reportPaths.isNotEmpty()) { - append("See the report at: ") - append(reportPaths.joinToString(", ")) - } + override fun run(task: SpotBugsTask) { + // TODO print version of SpotBugs and Plugins + try { + task.project.javaexec(configureJavaExec(task)).rethrowFailure().assertNormalExitValue() + if (stderrOutputScanner.isFailedToReport && !task.getIgnoreFailures()) { + throw GradleException("SpotBugs analysis succeeded but report generation failed") + } + } catch (e: ExecException) { + if (task.getIgnoreFailures()) { + log.warn( + "SpotBugs reported failures", + if (task.showStackTraces.get()) { + e + } else { + null + }, + ) + } else { + val errorMessage = buildString { + append("Verification failed: SpotBugs execution thrown exception.") + val reportPaths = task.getRequiredReports() + .asSequence() + .map(SpotBugsReport::getOutputLocation) + .map(RegularFileProperty::getAsFile) + .map { + it.get() } - throw GradleException(errorMessage, e) + .map(File::toPath) + .map(Path::toUri) + .map(URI::toString) + .toList() + if (reportPaths.isNotEmpty()) { + append("See the report at: ") + append(reportPaths.joinToString(", ")) + } } + throw GradleException(errorMessage, e) } } + } - private fun configureJavaExec(task: SpotBugsTask): Action { - return Action { spec -> - val args = mutableListOf() - args.add("-exitcode") - args.addAll(buildArguments(task)) - spec.classpath(task.spotbugsClasspath) - spec.jvmArgs = buildJvmArguments(task) - spec.mainClass.set("edu.umd.cs.findbugs.FindBugs2") - spec.setArgs(args) - val maxHeapSize = task.maxHeapSize.getOrNull() - if (maxHeapSize != null) { - spec.maxHeapSize = maxHeapSize - } - stderrOutputScanner = OutputScanner(System.err) - spec.setErrorOutput(stderrOutputScanner) - if (javaLauncher.isPresent) { - log.info( - "Spotbugs will be executed using Java Toolchain configuration: Vendor: {} | Version: {}", - javaLauncher.get().metadata.vendor, - javaLauncher.get().metadata.languageVersion.asInt(), - ) - spec.executable = javaLauncher.get().executablePath.asFile.absolutePath - } + private fun configureJavaExec(task: SpotBugsTask): Action { + return Action { spec -> + val args = mutableListOf() + args.add("-exitcode") + args.addAll(buildArguments(task)) + spec.classpath(task.spotbugsClasspath) + spec.jvmArgs = buildJvmArguments(task) + spec.mainClass.set("edu.umd.cs.findbugs.FindBugs2") + spec.setArgs(args) + val maxHeapSize = task.maxHeapSize.getOrNull() + if (maxHeapSize != null) { + spec.maxHeapSize = maxHeapSize + } + stderrOutputScanner = OutputScanner(System.err) + spec.setErrorOutput(stderrOutputScanner) + if (javaLauncher.isPresent) { + log.info( + "Spotbugs will be executed using Java Toolchain configuration: Vendor: {} | Version: {}", + javaLauncher.get().metadata.vendor, + javaLauncher.get().metadata.languageVersion.asInt(), + ) + spec.executable = javaLauncher.get().executablePath.asFile.absolutePath } } } +} diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsSarifReport.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsSarifReport.kt index e1eed850..95662f27 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsSarifReport.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsSarifReport.kt @@ -15,19 +15,19 @@ package com.github.spotbugs.snom.internal import com.github.spotbugs.snom.SpotBugsReport import com.github.spotbugs.snom.SpotBugsTask -import org.gradle.api.model.ObjectFactory import javax.inject.Inject +import org.gradle.api.model.ObjectFactory -abstract class SpotBugsSarifReport - @Inject - constructor(objects: ObjectFactory, task: SpotBugsTask) : - SpotBugsReport(objects, task) { - init { - // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.sarif" - outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".sarif")) - } +abstract class SpotBugsSarifReport @Inject constructor( + objects: ObjectFactory, + task: SpotBugsTask, +) : SpotBugsReport(objects, task) { + init { + // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.sarif" + outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".sarif")) + } - override fun toCommandLineOption(): String { - return "-sarif" - } + override fun toCommandLineOption(): String { + return "-sarif" } +} diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsTextReport.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsTextReport.kt index 692950e3..afb60b20 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsTextReport.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsTextReport.kt @@ -15,23 +15,23 @@ package com.github.spotbugs.snom.internal import com.github.spotbugs.snom.SpotBugsReport import com.github.spotbugs.snom.SpotBugsTask -import org.gradle.api.model.ObjectFactory import javax.inject.Inject +import org.gradle.api.model.ObjectFactory -abstract class SpotBugsTextReport - @Inject - constructor(objects: ObjectFactory, task: SpotBugsTask) : - SpotBugsReport(objects, task) { - init { - // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.txt" - outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".txt")) - } +abstract class SpotBugsTextReport @Inject constructor( + objects: ObjectFactory, + task: SpotBugsTask, +) : SpotBugsReport(objects, task) { + init { + // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.txt" + outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".txt")) + } - override fun toCommandLineOption(): String { - return "-sortByClass" - } + override fun toCommandLineOption(): String { + return "-sortByClass" + } - override fun getDisplayName(): String { - return String.format("Text type report generated by the task %s", task.path) - } + override fun getDisplayName(): String { + return String.format("Text type report generated by the task %s", task.path) } +} diff --git a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsXmlReport.kt b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsXmlReport.kt index 6f64ac3b..ce65ec29 100644 --- a/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsXmlReport.kt +++ b/src/main/kotlin/com/github/spotbugs/snom/internal/SpotBugsXmlReport.kt @@ -15,23 +15,23 @@ package com.github.spotbugs.snom.internal import com.github.spotbugs.snom.SpotBugsReport import com.github.spotbugs.snom.SpotBugsTask -import org.gradle.api.model.ObjectFactory import javax.inject.Inject +import org.gradle.api.model.ObjectFactory -abstract class SpotBugsXmlReport - @Inject - constructor(objects: ObjectFactory, task: SpotBugsTask) : - SpotBugsReport(objects, task) { - init { - // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.xml" - outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".xml")) - } +abstract class SpotBugsXmlReport @Inject constructor( + objects: ObjectFactory, + task: SpotBugsTask, +) : SpotBugsReport(objects, task) { + init { + // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.xml" + outputLocation.convention(task.reportsDir.file(task.getBaseName() + ".xml")) + } - override fun toCommandLineOption(): String { - return "-xml:withMessages" - } + override fun toCommandLineOption(): String { + return "-xml:withMessages" + } - override fun getDisplayName(): String { - return String.format("XML type report generated by the task %s", task.path) - } + override fun getDisplayName(): String { + return String.format("XML type report generated by the task %s", task.path) } +}