Skip to content

Commit

Permalink
refactor(asciidoc)!: Use a plugin config class
Browse files Browse the repository at this point in the history
Add config classes for the reporters and use them instead of the options
passed to the `generateReport` function.

Signed-off-by: Martin Nonnenmacher <martin.nonnenmacher@bosch.com>
  • Loading branch information
mnonnenmacher committed Nov 9, 2024
1 parent 27f0dae commit 88aa4a0
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 88 deletions.
11 changes: 3 additions & 8 deletions cli/src/funTest/kotlin/ExamplesFunTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import org.ossreviewtoolkit.model.PackageCuration
import org.ossreviewtoolkit.model.Severity
import org.ossreviewtoolkit.model.config.CopyrightGarbage
import org.ossreviewtoolkit.model.config.NotifierConfiguration
import org.ossreviewtoolkit.model.config.PluginConfiguration
import org.ossreviewtoolkit.model.config.RepositoryConfiguration
import org.ossreviewtoolkit.model.config.Resolutions
import org.ossreviewtoolkit.model.config.SendMailConfiguration
Expand Down Expand Up @@ -131,13 +130,9 @@ class ExamplesFunTest : StringSpec({

takeExampleFile("asciidoctor-pdf-theme.yml")

val report = reporter.create(PluginConfig()).generateReport(
ReporterInput(OrtResult.EMPTY),
outputDir,
PluginConfiguration(
mapOf("pdf.theme.file" to examplesDir.resolve("asciidoctor-pdf-theme.yml").path)
)
)
val report = reporter.create(
PluginConfig(options = mapOf("pdf.theme.file" to examplesDir.resolve("asciidoctor-pdf-theme.yml").path))
).generateReport(ReporterInput(OrtResult.EMPTY), outputDir)

report shouldHaveSize 1
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import io.kotest.matchers.should

import java.time.LocalDate

import org.ossreviewtoolkit.plugins.api.PluginConfig
import org.ossreviewtoolkit.reporter.ORT_RESULT
import org.ossreviewtoolkit.reporter.ReporterInput
import org.ossreviewtoolkit.utils.test.getAssetFile
Expand All @@ -34,7 +35,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())
val reportContent = DocBookTemplateReporterFactory().create(PluginConfig())
.generateReport(ReporterInput(ORT_RESULT), tempdir())
.single().getOrThrow().readText()

reportContent should matchExpectedResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import io.kotest.core.spec.style.StringSpec
import io.kotest.engine.spec.tempdir
import io.kotest.matchers.shouldBe

import org.ossreviewtoolkit.plugins.api.PluginConfig
import org.ossreviewtoolkit.reporter.ORT_RESULT
import org.ossreviewtoolkit.reporter.ReporterInput
import org.ossreviewtoolkit.utils.test.getAssetFile
Expand All @@ -32,7 +33,7 @@ class HtmlTemplateReporterFunTest : StringSpec({
"HTML report is created from default template" {
val expectedResultFile = getAssetFile("html-template-reporter-expected-result.html")

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import io.kotest.matchers.should

import java.time.LocalDate

import org.ossreviewtoolkit.plugins.api.PluginConfig
import org.ossreviewtoolkit.reporter.ORT_RESULT
import org.ossreviewtoolkit.reporter.ReporterInput
import org.ossreviewtoolkit.utils.test.getAssetFile
Expand All @@ -33,7 +34,7 @@ import org.ossreviewtoolkit.utils.test.matchExpectedResult
class ManPageTemplateReporterFunTest : StringSpec({
"ManPage report is created from default template" {
val expectedResultFile = getAssetFile("manpage-template-reporter-expected-result.1")
val reporter = ManPageTemplateReporter()
val reporter = ManPageTemplateReporterFactory().create(PluginConfig())

val reportContent = reporter.generateReport(ReporterInput(ORT_RESULT), tempdir())
.single().getOrThrow().readText()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ import io.kotest.matchers.result.shouldBeSuccess
import io.kotest.matchers.should
import io.kotest.matchers.shouldBe

import org.ossreviewtoolkit.model.config.PluginConfiguration
import org.ossreviewtoolkit.plugins.api.PluginConfig
import org.ossreviewtoolkit.reporter.ORT_RESULT
import org.ossreviewtoolkit.reporter.ORT_RESULT_WITH_VULNERABILITIES
import org.ossreviewtoolkit.reporter.ReporterInput
import org.ossreviewtoolkit.utils.common.Options

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

reportFileResults.shouldBeSingleton {
it shouldBeSuccess { reportFile ->
Expand All @@ -53,26 +54,20 @@ class PdfTemplateReporterFunTest : StringSpec({

"Report generation is aborted when path to non-existing PDF theme file is given" {
shouldThrow<IllegalArgumentException> {
PdfTemplateReporter().generateReport(
ReporterInput(ORT_RESULT),
tempdir(),
PluginConfiguration(mapOf("pdf.theme.file" to "dummy.file"))
)
createReporter(mapOf("pdf.theme.file" to "dummy.file"))
.generateReport(ReporterInput(ORT_RESULT), tempdir())
}
}

"Report generation is aborted when a non-existent PDF fonts directory is given" {
shouldThrow<IllegalArgumentException> {
PdfTemplateReporter().generateReport(
ReporterInput(ORT_RESULT),
tempdir(),
PluginConfiguration(mapOf("pdf.fonts.dir" to "fake.path"))
)
createReporter(mapOf("pdf.fonts.dir" to "fake.path"))
.generateReport(ReporterInput(ORT_RESULT), tempdir())
}
}

"Advisor reports are generated if the result contains an advisor section" {
val reportFileResults = PdfTemplateReporter().generateReport(
val reportFileResults = createReporter().generateReport(
ReporterInput(ORT_RESULT_WITH_VULNERABILITIES),
tempdir()
)
Expand All @@ -81,3 +76,6 @@ class PdfTemplateReporterFunTest : StringSpec({
reportFileNames.shouldContainAll("AsciiDoc_vulnerability_report.pdf", "AsciiDoc_defect_report.pdf")
}
})

private fun createReporter(options: Options = emptyMap()) =
PdfTemplateReporterFactory().create(PluginConfig(options = options))
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,29 @@ import org.asciidoctor.Options
import org.asciidoctor.SafeMode

import org.ossreviewtoolkit.model.config.PluginConfiguration
import org.ossreviewtoolkit.plugins.api.OrtPluginOption
import org.ossreviewtoolkit.plugins.reporters.freemarker.FreemarkerTemplateProcessor
import org.ossreviewtoolkit.plugins.reporters.freemarker.FreemarkerTemplateProcessor.Companion.OPTION_TEMPLATE_ID
import org.ossreviewtoolkit.plugins.reporters.freemarker.FreemarkerTemplateProcessor.Companion.OPTION_TEMPLATE_PATH
import org.ossreviewtoolkit.reporter.Reporter
import org.ossreviewtoolkit.reporter.ReporterInput
import org.ossreviewtoolkit.utils.common.safeDeleteRecursively
import org.ossreviewtoolkit.utils.ort.createOrtTempDir

data class AsciiDocTemplateReporterConfig(
/**
* A comma-separated list of IDs of templates provided by ORT.
* If no template id or path is provided, the "disclosure_document" template is used, and if the ORT result contains
* an advisor run, the "vulnerability_report" and "defect_report" templates are used as well.
*/
@OrtPluginOption(aliases = ["templateId"])
val templateIds: List<String>?,

/**
* A comma-separated list of paths to template files provided by the user.
*/
@OrtPluginOption(aliases = ["templatePath"])
val templatePaths: List<String>?
)

/**
* An abstract [Reporter] that uses [Apache Freemarker][1] templates and [AsciiDoc][2] with [AsciidoctorJ][3] to create
* reports for the supported [AsciiDoc converters][4], using the specified Asciidoctor [backend].
Expand All @@ -44,7 +59,7 @@ import org.ossreviewtoolkit.utils.ort.createOrtTempDir
* [3]: https://github.com/asciidoctor/asciidoctorj
* [4]: https://docs.asciidoctor.org/asciidoctor/latest/convert/available
*/
abstract class AsciiDocTemplateReporter : Reporter {
abstract class AsciiDocTemplateReporter(private val config: AsciiDocTemplateReporterConfig) : Reporter {
companion object {
private const val ASCII_DOC_FILE_PREFIX = "AsciiDoc_"
private const val ASCII_DOC_FILE_EXTENSION = "adoc"
Expand All @@ -66,11 +81,9 @@ abstract class AsciiDocTemplateReporter : Reporter {
internal val asciidoctor by lazy { Asciidoctor.Factory.create() }

/**
* Turn recognized [options] into [Attributes] and remove them from [options] afterwards to mark them as processed.
* By default no [options] are processed and the returned [Attributes] are empty.
* Subclasses can override this function to add additional AsciiDoc attributes. By default, no attributes are added.
*/
protected open fun processTemplateOptions(outputDir: File, options: MutableMap<String, String>): Attributes =
Attributes.builder().build()
protected open fun generateAsciiDocAttributes(outputDir: File): Attributes = Attributes.builder().build()

final override fun generateReport(
input: ReporterInput,
Expand All @@ -79,9 +92,8 @@ abstract class AsciiDocTemplateReporter : Reporter {
): List<Result<File>> {
val asciiDocOutputDir = createOrtTempDir("asciidoc")

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

asciiDocOutputDir.safeDeleteRecursively()
Expand All @@ -90,31 +102,28 @@ abstract class AsciiDocTemplateReporter : Reporter {
}

/**
* Generate the AsciiDoc files from the templates defined in [options] in [outputDir].
* Generate the AsciiDoc files from the templates defined in [config] in [outputDir].
*/
private fun generateAsciiDocFiles(
input: ReporterInput,
outputDir: File,
options: MutableMap<String, String>
): List<Result<File>> {
if (FreemarkerTemplateProcessor.OPTION_TEMPLATE_PATH !in options) {
options.putIfAbsent(
FreemarkerTemplateProcessor.OPTION_TEMPLATE_ID,
buildString {
append(DISCLOSURE_TEMPLATE_ID)

if (input.ortResult.getAdvisorResults().isNotEmpty()) {
append(",$VULNERABILITY_TEMPLATE_ID,$DEFECT_TEMPLATE_ID")
}
private fun generateAsciiDocFiles(input: ReporterInput, outputDir: File): List<Result<File>> {
val actualConfig = config.takeIf {
it.templateIds?.isNotEmpty() == true || it.templatePaths?.isNotEmpty() == true
} ?: AsciiDocTemplateReporterConfig(
templateIds = buildList {
add(DISCLOSURE_TEMPLATE_ID)

if (input.ortResult.getAdvisorResults().isNotEmpty()) {
add(VULNERABILITY_TEMPLATE_ID)
add(DEFECT_TEMPLATE_ID)
}
)
}
},
templatePaths = null
)

return templateProcessor.processTemplates(
input,
outputDir,
options[OPTION_TEMPLATE_ID]?.split(',').orEmpty(),
options[OPTION_TEMPLATE_PATH]?.split(',').orEmpty()
actualConfig.templateIds.orEmpty(),
actualConfig.templatePaths.orEmpty()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ import org.ossreviewtoolkit.reporter.ReporterFactory
description = "Generates DocBook from AsciiDoc files from Apache Freemarker templates.",
factory = ReporterFactory::class
)
class DocBookTemplateReporter(override val descriptor: PluginDescriptor = DocBookTemplateReporterFactory.descriptor) :
AsciiDocTemplateReporter() {
class DocBookTemplateReporter(
override val descriptor: PluginDescriptor = DocBookTemplateReporterFactory.descriptor,
config: AsciiDocTemplateReporterConfig
) : AsciiDocTemplateReporter(config) {
override val backend = "docbook"
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ import org.ossreviewtoolkit.reporter.ReporterFactory
description = "Generates HTML from AsciiDoc files from Apache Freemarker templates.",
factory = ReporterFactory::class
)
class HtmlTemplateReporter(override val descriptor: PluginDescriptor = HtmlTemplateReporterFactory.descriptor) :
AsciiDocTemplateReporter() {
class HtmlTemplateReporter(
override val descriptor: PluginDescriptor = HtmlTemplateReporterFactory.descriptor,
config: AsciiDocTemplateReporterConfig
) : AsciiDocTemplateReporter(config) {
override val backend = "html"
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ import org.ossreviewtoolkit.reporter.ReporterFactory
description = "Generates manpages from AsciiDoc files from Apache Freemarker templates.",
factory = ReporterFactory::class
)
class ManPageTemplateReporter(override val descriptor: PluginDescriptor = ManPageTemplateReporterFactory.descriptor) :
AsciiDocTemplateReporter() {
class ManPageTemplateReporter(
override val descriptor: PluginDescriptor = ManPageTemplateReporterFactory.descriptor,
config: AsciiDocTemplateReporterConfig
) : AsciiDocTemplateReporter(config) {
override val backend = "manpage"
}
65 changes: 44 additions & 21 deletions plugins/reporters/asciidoc/src/main/kotlin/PdfTemplateReporter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,39 @@ import java.io.File
import org.asciidoctor.Attributes

import org.ossreviewtoolkit.plugins.api.OrtPlugin
import org.ossreviewtoolkit.plugins.api.OrtPluginOption
import org.ossreviewtoolkit.plugins.api.PluginDescriptor
import org.ossreviewtoolkit.reporter.Reporter
import org.ossreviewtoolkit.reporter.ReporterFactory

data class PdfTemplateReporterConfig(
/**
* A comma-separated list of IDs of templates provided by ORT.
* If no template id or path is provided, the "disclosure_document" template is used, and if the ORT result contains
* an advisor run, the "vulnerability_report" and "defect_report" templates are used as well.
*/
@OrtPluginOption(aliases = ["templateId"])
val templateIds: List<String>?,

/**
* A comma-separated list of paths to template files provided by the user.
*/
@OrtPluginOption(aliases = ["templatePath"])
val templatePaths: List<String>?,

/**
* The path to an AsciiDoc PDF theme file.
*/
@OrtPluginOption(aliases = ["pdf.theme.file"], defaultValue = "uri:classloader:/pdf-theme/pdf-theme.yml")
val pdfThemeFile: String,

/**
* The path to a directory containing custom fonts.
*/
@OrtPluginOption(aliases = ["pdf.fonts.dir"], defaultValue = "uri:classloader:/fonts")
val pdfFontsDir: String
)

/**
* A [Reporter] that creates PDF files using a combination of [Apache Freemarker][1] templates and [AsciiDoc][2]
* with [AsciidoctorJ][3] as Java interface and [AsciidoctorJ PDF][4] as PDF file generator.
Expand All @@ -42,13 +71,6 @@ import org.ossreviewtoolkit.reporter.ReporterFactory
* Note that only one theme can be set that is used for all given templates. If no theme is given, a default built-in
* theme of AsciidoctorJ PDF is used.
*
* This reporter supports the following options:
* - *template.id*: A comma-separated list of IDs of templates provided by ORT. Currently, the "disclosure_document" and
* "vulnerability_report" templates are available.
* - *template.path*: A comma-separated list of paths to template files provided by the user.
* - *pdf.theme.file*: A path to an AsciiDoc PDF theme file. Only used with the "pdf" backend.
* - *pdf.fonts.dir*: A path to a directory containing custom fonts. Only used with the "pdf" backend.
*
* [1]: https://freemarker.apache.org
* [2]: https://asciidoc.org/
* [3]: https://github.com/asciidoctor/asciidoctorj
Expand All @@ -60,30 +82,31 @@ import org.ossreviewtoolkit.reporter.ReporterFactory
description = "Generates PDF from AsciiDoc files from Apache Freemarker templates.",
factory = ReporterFactory::class
)
class PdfTemplateReporter(override val descriptor: PluginDescriptor = PdfTemplateReporterFactory.descriptor) :
AsciiDocTemplateReporter() {
companion object {
private const val OPTION_PDF_THEME_FILE = "pdf.theme.file"
private const val OPTION_PDF_FONTS_DIR = "pdf.fonts.dir"
}

class PdfTemplateReporter(
override val descriptor: PluginDescriptor = PdfTemplateReporterFactory.descriptor,
private val config: PdfTemplateReporterConfig
) : AsciiDocTemplateReporter(AsciiDocTemplateReporterConfig(config.templateIds, config.templatePaths)) {
override val backend = "pdf"

override fun processTemplateOptions(outputDir: File, options: MutableMap<String, String>): Attributes =
override fun generateAsciiDocAttributes(outputDir: File): Attributes =
Attributes.builder().apply {
val pdfTheme = options.remove(OPTION_PDF_THEME_FILE)?.let { option ->
File(option).absoluteFile.also {
val pdfTheme = if (config.pdfThemeFile.startsWith("uri:")) {
config.pdfThemeFile
} else {
File(config.pdfThemeFile).absoluteFile.also {
require(it.isFile) { "Could not find PDF theme file at '$it'." }
}.path
} ?: "uri:classloader:/pdf-theme/pdf-theme.yml"
}

attribute("pdf-theme", pdfTheme)

val pdfFontsDir = options.remove(OPTION_PDF_FONTS_DIR)?.let { option ->
File(option).absoluteFile.also {
val pdfFontsDir = if (config.pdfFontsDir.startsWith("uri:")) {
config.pdfFontsDir
} else {
File(config.pdfFontsDir).absoluteFile.also {
require(it.isDirectory) { "Could not find PDF fonts directory at '$it'." }
}.path
} ?: "uri:classloader:/fonts"
}

attribute("pdf-fontsdir", "$pdfFontsDir,GEM_FONTS_DIR")
}.build()
Expand Down
Loading

0 comments on commit 88aa4a0

Please sign in to comment.