Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reporter API enhancements #8910

Merged
merged 3 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions plugins/commands/reporter/src/main/kotlin/ReporterCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ class ReporterCommand : OrtCommand(

reporter to measureTimedValue {
val options = reportConfigMap[reporter.type] ?: PluginConfiguration.EMPTY
runCatching { reporter.generateReport(input, outputDir, options) }
reporter.generateReport(input, outputDir, options)
}
}
}.awaitAll()
Expand All @@ -300,18 +300,20 @@ class ReporterCommand : OrtCommand(

reportDurationMap.value.forEach { (reporter, timedValue) ->
val name = reporter.type
val fileResults = timedValue.value

timedValue.value.onSuccess { files ->
val fileList = files.joinToString { "'$it'" }
echo("Successfully created '$name' report(s) at $fileList in ${timedValue.duration}.")
}.onFailure { e ->
e.showStackTrace()
fileResults.forEach { fileResult ->
fileResult.onSuccess { file ->
echo("Successfully created '$name' report at $file in ${timedValue.duration}.")
}.onFailure { e ->
e.showStackTrace()

logger.error {
"Could not create '$name' report in ${timedValue.duration}: ${e.collectMessages()}"
}
logger.error {
"Could not create '$name' report in ${timedValue.duration}: ${e.collectMessages()}"
}

++failureCount
++failureCount
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class DocBookTemplateReporterFunTest : StringSpec({
"DocBook report is created from default template" {
val expectedResultFile = getAssetFile("docbook-template-reporter-expected-result.xml")

val reportContent =
DocBookTemplateReporter().generateReport(ReporterInput(ORT_RESULT), tempdir()).single().readText()
val reportContent = DocBookTemplateReporter().generateReport(ReporterInput(ORT_RESULT), tempdir())
.single().getOrThrow().readText()

reportContent should matchExpectedResult(
expectedResultFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class HtmlTemplateReporterFunTest : StringSpec({
val expectedResultFile = getAssetFile("html-template-reporter-expected-result.html")

val reporter = HtmlTemplateReporter()
val reportContent = reporter.generateReport(ReporterInput(ORT_RESULT), tempdir()).single().readText()
val reportContent = reporter.generateReport(ReporterInput(ORT_RESULT), tempdir())
.single().getOrThrow().readText()

reportContent.patchAsciiDocTemplateResult() shouldBe patchExpectedResult(
expectedResultFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class ManPageTemplateReporterFunTest : StringSpec({
val expectedResultFile = getAssetFile("manpage-template-reporter-expected-result.1")
val reporter = ManPageTemplateReporter()

val reportContent = reporter.generateReport(ReporterInput(ORT_RESULT), tempdir()).single().readText()
val reportContent = reporter.generateReport(ReporterInput(ORT_RESULT), tempdir())
.single().getOrThrow().readText()

reportContent should matchExpectedResult(
expectedResultFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ package org.ossreviewtoolkit.plugins.reporters.asciidoc
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.StringSpec
import io.kotest.engine.spec.tempdir
import io.kotest.matchers.collections.contain
import io.kotest.matchers.collections.shouldBeSingleton
import io.kotest.matchers.collections.shouldContainAll
import io.kotest.matchers.longs.beInRange
import io.kotest.matchers.result.shouldBeSuccess
import io.kotest.matchers.should
import io.kotest.matchers.shouldBe

Expand All @@ -34,15 +36,19 @@ import org.ossreviewtoolkit.reporter.ReporterInput

class PdfTemplateReporterFunTest : StringSpec({
"The report is created successfully from an existing result and default template" {
val report = PdfTemplateReporter().generateReport(ReporterInput(ORT_RESULT), tempdir()).single()
val reportFileResults = PdfTemplateReporter().generateReport(ReporterInput(ORT_RESULT), tempdir())

report.reader().use {
val header = CharArray(4)
it.read(header) shouldBe header.size
String(header) shouldBe "%PDF"
}
reportFileResults.shouldBeSingleton {
it shouldBeSuccess { reportFile ->
reportFile.reader().use { stream ->
val header = CharArray(4)
stream.read(header) shouldBe header.size
String(header) shouldBe "%PDF"
}

report.length() should beInRange(111000L..115000L)
reportFile.length() should beInRange(111000L..115000L)
}
}
}

"Report generation is aborted when path to non-existing PDF theme file is given" {
Expand All @@ -66,14 +72,12 @@ class PdfTemplateReporterFunTest : StringSpec({
}

"Advisor reports are generated if the result contains an advisor section" {
val reports =
PdfTemplateReporter().generateReport(
ReporterInput(ORT_RESULT_WITH_VULNERABILITIES),
tempdir()
)
val reportFileResults = PdfTemplateReporter().generateReport(
ReporterInput(ORT_RESULT_WITH_VULNERABILITIES),
tempdir()
)

val reportFileNames = reports.map { it.name }
reportFileNames should contain("AsciiDoc_vulnerability_report.pdf")
reportFileNames should contain("AsciiDoc_defect_report.pdf")
val reportFileNames = reportFileResults.mapNotNull { it.getOrNull()?.name }
reportFileNames.shouldContainAll("AsciiDoc_vulnerability_report.pdf", "AsciiDoc_defect_report.pdf")
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,21 @@ open class AsciiDocTemplateReporter(private val backend: String, override val ty
protected open fun processTemplateOptions(outputDir: File, options: MutableMap<String, String>): Attributes =
Attributes.builder().build()

final override fun generateReport(input: ReporterInput, outputDir: File, config: PluginConfiguration): List<File> {
final override fun generateReport(
input: ReporterInput,
outputDir: File,
config: PluginConfiguration
): List<Result<File>> {
val asciiDocOutputDir = createOrtTempDir("asciidoc")

val templateOptions = config.options.toMutableMap()
val asciidoctorAttributes = processTemplateOptions(asciiDocOutputDir, templateOptions)
val asciiDocFiles = generateAsciiDocFiles(input, asciiDocOutputDir, templateOptions)
val reports = processAsciiDocFiles(input, outputDir, asciiDocFiles, asciidoctorAttributes)
val asciiDocFileResults = generateAsciiDocFiles(input, asciiDocOutputDir, templateOptions)
val reportFileResults = processAsciiDocFiles(input, outputDir, asciiDocFileResults, asciidoctorAttributes)

asciiDocOutputDir.safeDeleteRecursively()

return reports
return reportFileResults
}

/**
Expand All @@ -88,7 +92,7 @@ open class AsciiDocTemplateReporter(private val backend: String, override val ty
input: ReporterInput,
outputDir: File,
options: MutableMap<String, String>
): List<File> {
): List<Result<File>> {
if (FreemarkerTemplateProcessor.OPTION_TEMPLATE_PATH !in options) {
options.putIfAbsent(
FreemarkerTemplateProcessor.OPTION_TEMPLATE_ID,
Expand All @@ -106,31 +110,28 @@ open class AsciiDocTemplateReporter(private val backend: String, override val ty
}

/**
* Generate the reports for the [asciiDocFiles] using Asciidoctor in [outputDir] applying the
* Generate the reports for the [asciiDocFileResults] using Asciidoctor in [outputDir] applying the
* [asciidoctorAttributes].
*/
protected open fun processAsciiDocFiles(
input: ReporterInput,
outputDir: File,
asciiDocFiles: List<File>,
asciiDocFileResults: List<Result<File>>,
asciidoctorAttributes: Attributes
): List<File> {
): List<Result<File>> {
val optionsBuilder = Options.builder()
.attributes(asciidoctorAttributes)
.backend(backend)
.safe(SafeMode.UNSAFE)

val outputFiles = mutableListOf<File>()

asciiDocFiles.forEach { file ->
val outputFile = outputDir.resolve("${file.nameWithoutExtension}.$backend")

val options = optionsBuilder.toFile(outputFile).build()
asciidoctor.convertFile(file, options)

outputFiles += outputFile
return asciiDocFileResults.map { fileResult ->
// This implicitly passes through any failure from generating the Asciidoc file.
fileResult.mapCatching { file ->
outputDir.resolve("${file.nameWithoutExtension}.$backend").also { outputFile ->
val options = optionsBuilder.toFile(outputFile).build()
asciidoctor.convertFile(file, options)
}
}
}

return outputFiles
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ package org.ossreviewtoolkit.plugins.reporters.ctrlx

import io.kotest.core.spec.style.StringSpec
import io.kotest.engine.spec.tempdir
import io.kotest.matchers.collections.containExactly
import io.kotest.matchers.collections.haveSize
import io.kotest.matchers.collections.shouldBeSingleton
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.result.shouldBeSuccess
import io.kotest.matchers.should

import kotlinx.serialization.json.decodeFromStream
Expand All @@ -47,6 +48,8 @@ class CtrlXAutomationReporterFunTest : StringSpec({
val outputDir = tempdir()
val reportFiles = CtrlXAutomationReporter().generateReport(ReporterInput(ORT_RESULT), outputDir)

reportFiles.map { it.name } should containExactly(REPORT_FILENAME)
reportFiles.shouldBeSingleton {
it shouldBeSuccess outputDir.resolve(REPORT_FILENAME)
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ class CtrlXAutomationReporter : Reporter {

override val type = "CtrlXAutomation"

override fun generateReport(input: ReporterInput, outputDir: File, config: PluginConfiguration): List<File> {
val reportFile = outputDir.resolve(REPORT_FILENAME)

override fun generateReport(
input: ReporterInput,
outputDir: File,
config: PluginConfiguration
): List<Result<File>> {
val packages = input.ortResult.getPackages(omitExcluded = true)
val components = packages.mapTo(mutableListOf()) { (pkg, _) ->
val qualifiedName = when (pkg.id.type) {
Expand Down Expand Up @@ -88,9 +90,14 @@ class CtrlXAutomationReporter : Reporter {
)
}

val info = FossInfo(components = components)
reportFile.outputStream().use { JSON.encodeToStream(info, it) }
val reportFileResult = runCatching {
val info = FossInfo(components = components)

outputDir.resolve(REPORT_FILENAME).apply {
outputStream().use { JSON.encodeToStream(info, it) }
}
}

return listOf(reportFile)
return listOf(reportFileResult)
}
}
Loading
Loading