rios0rios0
rios0rios0

Reputation: 925

Spotbugs with Gradle show the both reports

I'm using Spotbugs with Gradle.

I moved from Maven to Gradle recently, then I realized that there're many differences between the same plugin in both builder tools...

For example, I would like to see Spotbugs GUI with the result of bugs... In Maven it's very very simple. In Gradle, Spotbugs generates two tasks, one for each folder (main and test). That's why there are two reports (main.xml and test.xml), difficulting completely the exhibition of GUI.

I'm doing some workaround to display two GUIs with both report results. But I'm facing some trouble to call a task with arguments inside another task... What I'm doing seems like this:

task spotbugsViewReports {
  def reports = ['main', 'test']
  for(String report : reports) {
    def name = "spotbugsView_${report}"
    task (name)(type: Exec) {
      commandLine "java", "-jar", "${buildDir}/unpacked/dist/spotbugs-4.4.0/lib/spotbugs.jar"
      args '-loadBugs', "${buildDir}/reports/spotbugs/${report}.xml"
    }
  }
  doLast {
    dependsOn 'spotbugsView_main'
    dependsOn 'spotbugsView_test'
  }
}

But it doesn't work. Could someone help me?

To show the complete and exhaustive work to workaround spotbugs absent equality with the Maven plugin, below I there's the complete workaround to do this:

task spotbugsGui {
  finalizedBy 'spotbugsUnzip'
}

task spotbugsUnzip(type: Copy) {
  def zipFile = file(project.configurations.artifact.find {
    it.name.startsWith("spotbugs")
  })
  def outputDir = file("${buildDir}/unpacked/dist")

  from zipTree(zipFile)
  into outputDir

  finalizedBy 'spotbugsRegisterGui'
}

task spotbugsRegisterGui {
  def reports = ['main', 'test']
  for(String report : reports) {
    tasks.create("spotbugsExecGui_${report}", Exec) {
      commandLine "java", "-jar", "${buildDir}/unpacked/dist/spotbugs-4.4.0/lib/spotbugs.jar"
      args '-loadBugs', "${buildDir}/reports/spotbugs/${report}.xml"
    }
  }

  finalizedBy 'spotbugsExecGui'
}

task spotbugsExecGui {
  dependsOn 'spotbugsExecGui_main'
  dependsOn 'spotbugsExecGui_test'
}

Upvotes: 0

Views: 989

Answers (1)

melix
melix

Reputation: 1530

(please avoid cross posting questions on Slack and StackOverflow, that's counter productive)

You shouldn't create your tasks like that. Instead, your plugin should react on the presence of Spotbugs tasks, which can be created for any source set (main, test, functional test, you name it) and create an appropriate view task for it. It's important to declare your inputs/outputs properly and avoid hardcoding values.

You can make it work with something like this:

// For each SpotBugsTask, we want to create a GUI task
tasks.withType(SpotBugsTask) { spotbugs ->
    tasks.register("${spotbugs.name}View", SpotBugsView) {
        dependsOn spotbugs
        description = "Opens the Spotbugs UI for ${spotbugs.name}"
        spotBugsClasspath.from(spotbugs.spotbugsClasspath)
        reportsDir = spotbugs.reportsDir
    }
}


abstract class SpotBugsView extends DefaultTask {
    @InputFiles
    abstract ConfigurableFileCollection getSpotBugsClasspath()

    @InputDirectory
    abstract DirectoryProperty getReportsDir()

    @javax.inject.Inject
    abstract ExecOperations getExecOperations()

    @TaskAction
    void execute() {
        String reportPaths = reportsDir.asFileTree
                .files
                .stream()
                .map(File::getAbsolutePath)
                .collect(Collectors.joining(","))
        execOperations.javaexec {
            it.classpath(spotBugsClasspath)
            it.mainClass.set("edu.umd.cs.findbugs.LaunchAppropriateUI")
            it.args("-loadBugs", reportPaths)
        }
    }
}

Upvotes: 2

Related Questions