Skip to content

Commit ce7206a

Browse files
committed
feat(advisor): Migrate the advisor to the new plugin API
Migrate the Advisor API and all plugins to the new plugin API. This allows to simplify the code in several places, as the plugin factories and service loader classes do not have to be created by hand anymore. Signed-off-by: Martin Nonnenmacher <[email protected]>
1 parent cd9f93e commit ce7206a

File tree

25 files changed

+129
-109
lines changed

25 files changed

+129
-109
lines changed

advisor/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ plugins {
2424

2525
dependencies {
2626
api(projects.model)
27+
api(projects.plugins.api)
2728
api(projects.utils.commonUtils)
2829

2930
implementation(projects.utils.ortUtils)

advisor/src/main/kotlin/AdviceProvider.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,21 @@ package org.ossreviewtoolkit.advisor
2222
import org.ossreviewtoolkit.model.AdvisorDetails
2323
import org.ossreviewtoolkit.model.AdvisorResult
2424
import org.ossreviewtoolkit.model.Package
25+
import org.ossreviewtoolkit.plugins.api.Plugin
2526

2627
/**
2728
* An abstract class that represents a service that can retrieve any kind of advice information
2829
* for a list of given [Package]s. Examples of such information can be security vulnerabilities, known defects,
2930
* or code analysis results.
3031
*/
31-
abstract class AdviceProvider(val providerName: String) {
32+
interface AdviceProvider : Plugin {
3233
/**
3334
* For a given set of [Package]s, retrieve findings and return a map that associates packages with [AdvisorResult]s.
3435
*/
35-
abstract suspend fun retrievePackageFindings(packages: Set<Package>): Map<Package, AdvisorResult>
36+
suspend fun retrievePackageFindings(packages: Set<Package>): Map<Package, AdvisorResult>
3637

3738
/**
3839
* An object with detail information about this [AdviceProvider].
3940
*/
40-
abstract val details: AdvisorDetails
41+
val details: AdvisorDetails
4142
}

advisor/src/main/kotlin/AdviceProviderFactory.kt

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,16 @@ package org.ossreviewtoolkit.advisor
2121

2222
import java.util.ServiceLoader
2323

24-
import org.ossreviewtoolkit.utils.common.Plugin
25-
import org.ossreviewtoolkit.utils.common.TypedConfigurablePluginFactory
24+
import org.ossreviewtoolkit.plugins.api.PluginFactory
2625

2726
/**
2827
* A common abstract class for use with [ServiceLoader] that all [AdviceProviderFactory] classes need to implement.
2928
*/
30-
abstract class AdviceProviderFactory<CONFIG>(override val type: String) :
31-
TypedConfigurablePluginFactory<CONFIG, AdviceProvider> {
29+
interface AdviceProviderFactory : PluginFactory<AdviceProvider> {
3230
companion object {
3331
/**
3432
* All [advice provider factories][AdviceProviderFactory] available in the classpath, associated by their names.
3533
*/
36-
val ALL by lazy { Plugin.getAll<AdviceProviderFactory<*>>() }
34+
val ALL by lazy { PluginFactory.getAll<AdviceProviderFactory, AdviceProvider>() }
3735
}
38-
39-
/**
40-
* Return the provider's type here to allow Clikt to display something meaningful when listing the advisors which
41-
* are enabled by default via their factories.
42-
*/
43-
override fun toString() = type
4436
}

advisor/src/main/kotlin/Advisor.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ import org.ossreviewtoolkit.model.Identifier
3333
import org.ossreviewtoolkit.model.OrtResult
3434
import org.ossreviewtoolkit.model.Package
3535
import org.ossreviewtoolkit.model.config.AdvisorConfiguration
36+
import org.ossreviewtoolkit.plugins.api.PluginConfig
3637
import org.ossreviewtoolkit.utils.ort.Environment
3738

3839
/**
3940
* The class to manage [AdviceProvider]s. It invokes the configured providers and adds their findings to the current
4041
* [OrtResult].
4142
*/
4243
class Advisor(
43-
private val providerFactories: List<AdviceProviderFactory<*>>,
44+
private val providerFactories: List<AdviceProviderFactory>,
4445
private val config: AdvisorConfiguration
4546
) {
4647
/**
@@ -75,8 +76,8 @@ class Advisor(
7576
logger.info { "There are no packages to give advice for." }
7677
} else {
7778
val providers = providerFactories.map {
78-
val providerConfig = config.config?.get(it.type)
79-
it.create(providerConfig?.options.orEmpty(), providerConfig?.secrets.orEmpty())
79+
val providerConfig = config.config?.get(it.descriptor.className)
80+
it.create(PluginConfig(providerConfig?.options.orEmpty(), providerConfig?.secrets.orEmpty()))
8081
}
8182

8283
providers.map { provider ->
@@ -85,7 +86,7 @@ class Advisor(
8586

8687
logger.info {
8788
"Found ${providerResults.values.flatMap { it.vulnerabilities }.distinct().size} distinct " +
88-
"vulnerabilities via ${provider.providerName}. "
89+
"vulnerabilities via ${provider.descriptor.name}. "
8990
}
9091

9192
providerResults.keys.takeIf { it.isNotEmpty() }?.let { pkgs ->

advisor/src/test/kotlin/AdvisorTest.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import org.ossreviewtoolkit.model.OrtResult
3939
import org.ossreviewtoolkit.model.Package
4040
import org.ossreviewtoolkit.model.Project
4141
import org.ossreviewtoolkit.model.config.AdvisorConfiguration
42+
import org.ossreviewtoolkit.plugins.api.PluginConfig
43+
import org.ossreviewtoolkit.plugins.api.PluginDescriptor
4244

4345
class AdvisorTest : WordSpec({
4446
"retrieveFindings" should {
@@ -117,8 +119,8 @@ private fun createAdvisor(providers: List<AdviceProvider>): Advisor {
117119
val advisorConfig = AdvisorConfiguration()
118120

119121
val factories = providers.map { provider ->
120-
val factory = mockk<AdviceProviderFactory<*>>()
121-
every { factory.create(emptyMap(), emptyMap()) } returns provider
122+
val factory = mockk<AdviceProviderFactory>()
123+
every { factory.create(PluginConfig(emptyMap(), emptyMap())) } returns provider
122124
factory
123125
}
124126

@@ -146,7 +148,7 @@ private fun createPackage(index: Int): Package =
146148

147149
private fun mockkAdviceProvider(): AdviceProvider =
148150
mockk<AdviceProvider>().apply {
149-
every { providerName } returns "provider"
151+
every { descriptor } returns PluginDescriptor("provider", "Provider", "", emptyList())
150152
}
151153

152154
private fun mockkAdvisorResult(): AdvisorResult =

plugins/advisors/nexus-iq/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
plugins {
2121
// Apply precompiled plugins.
2222
id("ort-library-conventions")
23+
24+
// Apply third-party plugins.
25+
alias(libs.plugins.ksp)
2326
}
2427

2528
dependencies {
@@ -29,4 +32,7 @@ dependencies {
2932
implementation(projects.clients.nexusIqClient)
3033
implementation(projects.utils.commonUtils)
3134
implementation(projects.utils.ortUtils)
35+
36+
ksp(projects.advisor)
37+
ksp(projects.plugins.api)
3238
}

plugins/advisors/nexus-iq/src/main/kotlin/NexusIq.kt

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ import org.ossreviewtoolkit.model.utils.PurlType
4444
import org.ossreviewtoolkit.model.utils.getPurlType
4545
import org.ossreviewtoolkit.model.vulnerabilities.Vulnerability
4646
import org.ossreviewtoolkit.model.vulnerabilities.VulnerabilityReference
47-
import org.ossreviewtoolkit.utils.common.Options
47+
import org.ossreviewtoolkit.plugins.api.OrtPlugin
48+
import org.ossreviewtoolkit.plugins.api.PluginDescriptor
4849
import org.ossreviewtoolkit.utils.common.collectMessages
4950
import org.ossreviewtoolkit.utils.common.enumSetOf
5051
import org.ossreviewtoolkit.utils.ort.OkHttpClientHelper
@@ -77,27 +78,17 @@ private val READ_TIMEOUT = Duration.ofSeconds(60)
7778
*
7879
* If not both `username` and `password` are provided, authentication is disabled.
7980
*/
80-
class NexusIq(name: String, private val config: NexusIqConfiguration) : AdviceProvider(name) {
81-
class Factory : AdviceProviderFactory<NexusIqConfiguration>("NexusIQ") {
82-
override fun create(config: NexusIqConfiguration) = NexusIq(type, config)
83-
84-
override fun parseConfig(options: Options, secrets: Options): NexusIqConfiguration {
85-
val serverUrl = options.getValue("serverUrl")
86-
87-
return NexusIqConfiguration(
88-
serverUrl = serverUrl,
89-
browseUrl = options["browseUrl"] ?: serverUrl,
90-
username = secrets["username"],
91-
password = secrets["password"]
92-
)
93-
}
94-
}
95-
96-
override val details: AdvisorDetails = AdvisorDetails(providerName, enumSetOf(AdvisorCapability.VULNERABILITIES))
81+
@OrtPlugin(
82+
name = "Nexus IQ",
83+
description = "An advisor that uses Sonatype's Nexus IQ Server to determine vulnerabilities in dependencies.",
84+
factory = AdviceProviderFactory::class
85+
)
86+
class NexusIq(override val descriptor: PluginDescriptor, private val config: NexusIqConfiguration) : AdviceProvider {
87+
override val details: AdvisorDetails = AdvisorDetails(descriptor.name, enumSetOf(AdvisorCapability.VULNERABILITIES))
9788

9889
private val service by lazy {
9990
NexusIqService.create(
100-
config.serverUrl,
91+
config.serverUrl.orEmpty(),
10192
config.username,
10293
config.password,
10394
OkHttpClientHelper.buildClient {
@@ -141,7 +132,7 @@ class NexusIq(name: String, private val config: NexusIqConfiguration) : AdvicePr
141132
component.packageUrl to ComponentDetails(component, SecurityData(emptyList()))
142133
}
143134

144-
issues += Issue(source = providerName, message = it.collectMessages())
135+
issues += Issue(source = descriptor.name, message = it.collectMessages())
145136
}
146137
}
147138

plugins/advisors/nexus-iq/src/main/kotlin/NexusIqConfiguration.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,19 @@ data class NexusIqConfiguration(
2929
val serverUrl: String,
3030

3131
/**
32-
* A URL to use as a base for browsing vulnerability details. Defaults to the server URL.
32+
* A URL to use as a base for browsing vulnerability details. If not set, the [serverUrl] is used.
3333
*/
34-
val browseUrl: String = serverUrl,
34+
val browseUrl: String?,
3535

3636
/**
3737
* The username to use for authentication. If not both [username] and [password] are provided, authentication is
3838
* disabled.
3939
*/
40-
val username: String? = null,
40+
val username: String?,
4141

4242
/**
4343
* The password to use for authentication. If not both [username] and [password] are provided, authentication is
4444
* disabled.
4545
*/
46-
val password: String? = null
46+
val password: String?
4747
)

plugins/advisors/nexus-iq/src/main/resources/META-INF/services/org.ossreviewtoolkit.advisor.AdviceProviderFactory

Lines changed: 0 additions & 1 deletion
This file was deleted.

plugins/advisors/oss-index/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
plugins {
2121
// Apply precompiled plugins.
2222
id("ort-library-conventions")
23+
24+
// Apply third-party plugins.
25+
alias(libs.plugins.ksp)
2326
}
2427

2528
dependencies {
@@ -30,5 +33,8 @@ dependencies {
3033
implementation(projects.utils.commonUtils)
3134
implementation(projects.utils.ortUtils)
3235

36+
ksp(projects.advisor)
37+
ksp(projects.plugins.api)
38+
3339
testImplementation(libs.wiremock)
3440
}

0 commit comments

Comments
 (0)