Skip to content

Commit

Permalink
feat(analyzer): Enhance environment setup
Browse files Browse the repository at this point in the history
Implement a new `setUpEnvironment` function to merge the
`EnvironmentConfig` from the `.ort.env.yml` file in the repository with
the `AnalyzerJobConfiguration`. This change ensures that overlapping
entries are correctly merged, with entries from the
`AnalyzerJobConfiguration` taking priority over those in the
`.ort.env.yml` file.

Signed-off-by: Onur Demirci <onur.demirci@bosch.io>
  • Loading branch information
bs-ondem authored and mnonnenmacher committed Sep 10, 2024
1 parent 9f3b4a3 commit 2c1dec7
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 42 deletions.
8 changes: 6 additions & 2 deletions workers/analyzer/src/main/kotlin/analyzer/AnalyzerWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,12 @@ internal class AnalyzerWorker(
ortRun.path.orEmpty()
)

val resolvedEnvConfig = envConfigFromJob?.let { environmentService.setUpEnvironment(context, it) }
?: environmentService.setUpEnvironment(context, sourcesDir, repositoryService)
val resolvedEnvConfig = environmentService.setUpEnvironment(
context,
sourcesDir,
envConfigFromJob,
repositoryService
)
val ortResult = runner.run(context, sourcesDir, job.configuration, resolvedEnvConfig)

ortRunService.storeRepositoryInformation(ortRun.id, ortResult.repository)
Expand Down
2 changes: 1 addition & 1 deletion workers/analyzer/src/test/kotlin/AnalyzerEndpointTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ class AnalyzerEndpointTest : KoinTest, StringSpec() {
val environmentService by inject<EnvironmentService>()

withSystemProperties(properties, mode = OverrideMode.SetOrOverride) {
environmentService.setUpEnvironment(context, repositoryFolder, null)
environmentService.setUpEnvironment(context, repositoryFolder, null, null)
}

block(homeFolder)
Expand Down
19 changes: 10 additions & 9 deletions workers/analyzer/src/test/kotlin/AnalyzerWorkerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class AnalyzerWorkerTest : StringSpec({
every { findInfrastructureServiceForRepository(context) } returns infrastructureService
coEvery { generateNetRcFile(context, listOf(infrastructureService)) } just runs
coEvery {
setUpEnvironment(context, projectDir, infrastructureService)
setUpEnvironment(context, projectDir, null, infrastructureService)
} returns ResolvedEnvironmentConfig()
}

Expand All @@ -171,7 +171,7 @@ class AnalyzerWorkerTest : StringSpec({
coVerifyOrder {
envService.generateNetRcFile(context, listOf(infrastructureService))
downloader.downloadRepository(repository.url, ortRun.revision)
envService.setUpEnvironment(context, projectDir, infrastructureService)
envService.setUpEnvironment(context, projectDir, null, infrastructureService)
}
}
}
Expand Down Expand Up @@ -203,7 +203,7 @@ class AnalyzerWorkerTest : StringSpec({

val envService = mockk<EnvironmentService> {
every { findInfrastructureServiceForRepository(context) } returns null
coEvery { setUpEnvironment(context, projectDir, null) } returns ResolvedEnvironmentConfig()
coEvery { setUpEnvironment(context, projectDir, null, null) } returns ResolvedEnvironmentConfig()
}

val worker = AnalyzerWorker(
Expand All @@ -229,7 +229,7 @@ class AnalyzerWorkerTest : StringSpec({
}

coVerify {
envService.setUpEnvironment(context, projectDir, null)
envService.setUpEnvironment(context, projectDir, null, null)
}
}
}
Expand Down Expand Up @@ -264,7 +264,7 @@ class AnalyzerWorkerTest : StringSpec({
val envService = mockk<EnvironmentService> {
every { findInfrastructureServiceForRepository(context) } returns null
every { findInfrastructureServiceForRepository(context, envConfig) } returns null
coEvery { setUpEnvironment(context, envConfig) } returns ResolvedEnvironmentConfig()
coEvery { setUpEnvironment(context, projectDir, envConfig, null) } returns ResolvedEnvironmentConfig()
}

val worker = AnalyzerWorker(
Expand All @@ -286,7 +286,7 @@ class AnalyzerWorkerTest : StringSpec({
}

coVerify {
envService.setUpEnvironment(context, envConfig)
envService.setUpEnvironment(context, projectDir, envConfig, null)
}
}
}
Expand Down Expand Up @@ -319,7 +319,7 @@ class AnalyzerWorkerTest : StringSpec({
val envService = mockk<EnvironmentService> {
every { findInfrastructureServiceForRepository(context) } returns null
every { findInfrastructureServiceForRepository(context, envConfig) } returns null
coEvery { setUpEnvironment(context, envConfig) } returns resolvedEnvConfig
coEvery { setUpEnvironment(context, projectDir, envConfig, null) } returns resolvedEnvConfig
}

val testException = IllegalStateException("AnalyzerRunner test exception")
Expand Down Expand Up @@ -367,7 +367,8 @@ class AnalyzerWorkerTest : StringSpec({
val resolvedEnvConfig = mockk<ResolvedEnvironmentConfig>()
val envService = mockk<EnvironmentService> {
every { findInfrastructureServiceForRepository(context) } returns null
coEvery { setUpEnvironment(context, projectDir, null) } returns resolvedEnvConfig
every { findInfrastructureServiceForRepository(context, any()) } returns null
coEvery { setUpEnvironment(context, projectDir, null, null) } returns resolvedEnvConfig
}

val testException = IllegalStateException("AnalyzerRunner test exception")
Expand Down Expand Up @@ -464,7 +465,7 @@ class AnalyzerWorkerTest : StringSpec({

val envService = mockk<EnvironmentService> {
every { findInfrastructureServiceForRepository(context) } returns null
coEvery { setUpEnvironment(context, projectDir, null) } returns ResolvedEnvironmentConfig()
coEvery { setUpEnvironment(context, projectDir, null, null) } returns ResolvedEnvironmentConfig()
}

val runnerMock = spyk(AnalyzerRunner(ConfigFactory.empty())) {
Expand Down
55 changes: 40 additions & 15 deletions workers/common/src/main/kotlin/common/env/EnvironmentService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ import org.eclipse.apoapsis.ortserver.workers.common.env.config.EnvironmentConfi
import org.eclipse.apoapsis.ortserver.workers.common.env.config.ResolvedEnvironmentConfig
import org.eclipse.apoapsis.ortserver.workers.common.env.definition.EnvironmentServiceDefinition

import org.slf4j.LoggerFactory

private val logger = LoggerFactory.getLogger(EnvironmentService::class.java)

/**
* A service class providing functionality for setting up the build environment when running a worker.
*
Expand Down Expand Up @@ -87,31 +91,21 @@ class EnvironmentService(
/**
* Set up the analysis environment for the current repository defined by the given [context] that has been
* checked out to the given [repositoryFolder]. The credentials of this repository - if any - are defined by the
* given [repositoryService].
* given [repositoryService]. If an optional [config] is provided, it will be merged with the parsed configuration.
* In case of overlapping entries, the provided [config] will take priority over the parsed configuration.
*/
suspend fun setUpEnvironment(
context: WorkerContext,
repositoryFolder: File,
config: EnvironmentConfig?,
repositoryService: InfrastructureService?
): ResolvedEnvironmentConfig {
val resolvedConfig = configLoader.resolve(configLoader.parse(repositoryFolder), context.hierarchy)
val mergedConfig = configLoader.parse(repositoryFolder).merge(config)
val resolvedConfig = configLoader.resolve(mergedConfig, context.hierarchy)

return setUpEnvironmentForConfig(context, resolvedConfig, repositoryService)
}

/**
* Set up the analysis environment for the current repository defined by the given [context] using the provided
* [config]. This function can be used if the environment configuration was passed when the run was triggered.
*/
suspend fun setUpEnvironment(
context: WorkerContext,
config: EnvironmentConfig
): ResolvedEnvironmentConfig {
val resolvedConfig = configLoader.resolve(config, context.hierarchy)

return setUpEnvironmentForConfig(context, resolvedConfig, null)
}

/**
* Set up the analysis environment based on the given resolved [config]. Use the given [context]. If the repository
* has credentials, as defined by the given optional [repositoryService], take them into account as well.
Expand Down Expand Up @@ -185,3 +179,34 @@ class EnvironmentService(
}
}
}

/**
* Merge this [EnvironmentConfig] with another [EnvironmentConfig]. The merging process ensures that:
* - Overlapping infrastructure services are overridden by the ones from the [other] config.
* - Environment definitions are combined, with values from both configs being flattened.
* - Environment variables with the same name are overridden by the ones from the [other] config.
*/
internal fun EnvironmentConfig.merge(other: EnvironmentConfig?): EnvironmentConfig {
if (other == null) return this

val (overridden, unreferenced) = infrastructureServices
.partition { service -> other.infrastructureServices.any { it.name == service.name } }

if (overridden.isNotEmpty()) {
logger.info(
"The following infrastructure services have been overridden: ${overridden.joinToString { it.name }}."
)
}

val mergedInfrastructureService = unreferenced + other.infrastructureServices
val mergedEnvironmentDefinitions =
(environmentDefinitions.asSequence() + other.environmentDefinitions.asSequence())
.groupBy({ it.key }, { it.value })
.mapValues { (_, values) -> values.flatten() }
val mergedEnvironmentVariables = (environmentVariables + other.environmentVariables)
.associateBy { it.name }
.values
.toList()

return EnvironmentConfig(mergedInfrastructureService, mergedEnvironmentDefinitions, mergedEnvironmentVariables)
}
Loading

0 comments on commit 2c1dec7

Please sign in to comment.