Точечные ошибки с помощью Gradle показывают оба отчета

#java #maven #gradle #groovy #spotbugs

Вопрос:

Я использую Spotbugs с Gradle.

Недавно я перешел с Maven на Gradle, а затем понял, что между одним и тем же плагином в обоих инструментах builder много различий…

Например, я хотел бы увидеть графический интерфейс Spotbugs с результатом ошибок… В Maven это очень и очень просто. В Gradle Spotbugs создает две задачи, по одной для каждой папки (основной и тестовой). Вот почему есть два отчета ( main.xml и test.xml ), полностью затрудняющих представление графического интерфейса.

Я делаю некоторое обходное решение, чтобы отобразить два графических интерфейса с обоими результатами отчета. Но у меня возникли некоторые проблемы с вызовом задачи с аргументами внутри другой задачи… То, что я делаю, похоже на это:

 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'
  }
}
 

Но это не работает. Кто-нибудь может мне помочь?

Чтобы показать полную и исчерпывающую работу по обходу spotbugs отсутствия равенства с плагином Maven, ниже я приведу полный обходной путь для этого:

 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'
}
 

Ответ №1:

(пожалуйста, избегайте перекрестной публикации вопросов о Slack и StackOverflow, это контрпродуктивно)

Вы не должны создавать свои задачи подобным образом. Вместо этого ваш плагин должен реагировать на наличие задач Spotbugs, которые могут быть созданы для любого исходного набора (основной, тестовый, функциональный тест, как вы его называете), и создавать для него соответствующую задачу просмотра. Важно правильно объявлять свои входы/выходы и избегать жесткого кодирования значений.

Вы можете заставить это работать с чем-то вроде этого:

 // 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)
        }
    }
}
 

Комментарии:

1. Это отличный ответ… Но он не вызывает оба отчета одновременно. Это только создает задачи в более удобочитаемом и без излишней инженерии виде.