Skip to content

Commit 8df9e09

Browse files
author
Kamil Bielecki
committed
feat(service): Extend package service with curation info
Extend packages list for ORT Run by information with curations applied. Signed-off-by: Kamil Bielecki <[email protected]>
1 parent 7847e82 commit 8df9e09

File tree

5 files changed

+136
-23
lines changed

5 files changed

+136
-23
lines changed

api/v1/mapping/src/commonMain/kotlin/Mappings.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ import org.eclipse.apoapsis.ortserver.model.runs.Issue
145145
import org.eclipse.apoapsis.ortserver.model.runs.OrtRuleViolation
146146
import org.eclipse.apoapsis.ortserver.model.runs.PackageFilters
147147
import org.eclipse.apoapsis.ortserver.model.runs.PackageManagerConfiguration
148-
import org.eclipse.apoapsis.ortserver.model.runs.PackageWithShortestDependencyPaths
148+
import org.eclipse.apoapsis.ortserver.model.runs.PackageRunData
149149
import org.eclipse.apoapsis.ortserver.model.runs.ProcessedDeclaredLicense
150150
import org.eclipse.apoapsis.ortserver.model.runs.Project
151151
import org.eclipse.apoapsis.ortserver.model.runs.RemoteArtifact
@@ -857,7 +857,7 @@ fun ShortestDependencyPath.mapToApi() = ApiShortestDependencyPath(
857857
path = path.map { it.mapToApi() }
858858
)
859859

860-
fun PackageWithShortestDependencyPaths.mapToApi() = ApiPackage(
860+
fun PackageRunData.mapToApi() = ApiPackage(
861861
pkg.identifier.mapToApi(),
862862
pkg.purl,
863863
pkg.cpe,

core/src/main/kotlin/api/RunsRoute.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ import org.eclipse.apoapsis.ortserver.model.authorization.RepositoryPermission
7676
import org.eclipse.apoapsis.ortserver.model.repositories.OrtRunRepository
7777
import org.eclipse.apoapsis.ortserver.model.runs.Issue
7878
import org.eclipse.apoapsis.ortserver.model.runs.OrtRuleViolation
79-
import org.eclipse.apoapsis.ortserver.model.runs.PackageWithShortestDependencyPaths
79+
import org.eclipse.apoapsis.ortserver.model.runs.PackageRunData
8080
import org.eclipse.apoapsis.ortserver.model.runs.Project
8181
import org.eclipse.apoapsis.ortserver.services.IssueService
8282
import org.eclipse.apoapsis.ortserver.services.OrtRunService
@@ -245,7 +245,7 @@ fun Route.runs() = route("runs") {
245245
.listForOrtRunId(ortRun.id, pagingOptions.mapToModel(), filters.mapToModel())
246246

247247
val pagedResponse = packagesForOrtRun
248-
.mapToApi(PackageWithShortestDependencyPaths::mapToApi)
248+
.mapToApi(PackageRunData::mapToApi)
249249
.toSearchResponse(filters)
250250

251251
call.respond(HttpStatusCode.OK, pagedResponse)

model/src/commonMain/kotlin/runs/PackageWithShortestDependencyPaths.kt renamed to model/src/commonMain/kotlin/runs/PackageRunData.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,22 @@
1919

2020
package org.eclipse.apoapsis.ortserver.model.runs
2121

22+
import org.eclipse.apoapsis.ortserver.model.runs.repository.PackageCurationData
23+
2224
/**
2325
* A data class representing a package, and the shortest dependency path that the package is found in (relative to a
2426
* project found in a run).
2527
*/
26-
data class PackageWithShortestDependencyPaths(
28+
data class PackageRunData(
2729
/** A package. */
2830
val pkg: Package,
2931

3032
/** Package ID */
3133
val pkgId: Long,
3234

3335
/** The shortest dependency path for the package. */
34-
val shortestDependencyPaths: List<ShortestDependencyPath>
36+
val shortestDependencyPaths: List<ShortestDependencyPath>,
37+
38+
/** The curations for the package. */
39+
val curations: List<PackageCurationData> = emptyList()
3540
)

services/hierarchy/src/main/kotlin/PackageService.kt

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@ import org.eclipse.apoapsis.ortserver.dao.repositories.analyzerrun.PackagesTable
2929
import org.eclipse.apoapsis.ortserver.dao.repositories.analyzerrun.ProcessedDeclaredLicensesTable
3030
import org.eclipse.apoapsis.ortserver.dao.repositories.analyzerrun.ShortestDependencyPathDao
3131
import org.eclipse.apoapsis.ortserver.dao.repositories.analyzerrun.ShortestDependencyPathsTable
32+
import org.eclipse.apoapsis.ortserver.dao.repositories.repositoryconfiguration.PackageCurationDataDao
33+
import org.eclipse.apoapsis.ortserver.dao.repositories.repositoryconfiguration.PackageCurationDataTable
34+
import org.eclipse.apoapsis.ortserver.dao.repositories.repositoryconfiguration.PackageCurationsTable
35+
import org.eclipse.apoapsis.ortserver.dao.repositories.repositoryconfiguration.RepositoryConfigurationsPackageCurationsTable
36+
import org.eclipse.apoapsis.ortserver.dao.repositories.repositoryconfiguration.RepositoryConfigurationsTable
3237
import org.eclipse.apoapsis.ortserver.dao.tables.shared.IdentifiersTable
3338
import org.eclipse.apoapsis.ortserver.dao.utils.applyFilterNullable
3439
import org.eclipse.apoapsis.ortserver.dao.utils.applyILike
3540
import org.eclipse.apoapsis.ortserver.dao.utils.listCustomQueryCustomOrders
3641
import org.eclipse.apoapsis.ortserver.model.EcosystemStats
3742
import org.eclipse.apoapsis.ortserver.model.runs.PackageFilters
38-
import org.eclipse.apoapsis.ortserver.model.runs.PackageWithShortestDependencyPaths
43+
import org.eclipse.apoapsis.ortserver.model.runs.PackageRunData
3944
import org.eclipse.apoapsis.ortserver.model.util.ListQueryParameters
4045
import org.eclipse.apoapsis.ortserver.model.util.ListQueryResult
4146

@@ -47,8 +52,10 @@ import org.jetbrains.exposed.sql.Op
4752
import org.jetbrains.exposed.sql.ResultRow
4853
import org.jetbrains.exposed.sql.SortOrder
4954
import org.jetbrains.exposed.sql.SqlExpressionBuilder.concat
55+
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
5056
import org.jetbrains.exposed.sql.SqlExpressionBuilder.neq
5157
import org.jetbrains.exposed.sql.and
58+
import org.jetbrains.exposed.sql.andWhere
5259
import org.jetbrains.exposed.sql.stringLiteral
5360

5461
/**
@@ -59,7 +66,7 @@ class PackageService(private val db: Database) {
5966
ortRunId: Long,
6067
parameters: ListQueryParameters = ListQueryParameters.DEFAULT,
6168
filters: PackageFilters = PackageFilters()
62-
): ListQueryResult<PackageWithShortestDependencyPaths> = db.dbQuery {
69+
): ListQueryResult<PackageRunData> = db.dbQuery {
6370
val orders = mutableListOf<Pair<Expression<*>, SortOrder>>()
6471

6572
parameters.sortFields.forEach {
@@ -110,30 +117,46 @@ class PackageService(private val db: Database) {
110117
)
111118
}
112119

113-
val listQueryResult =
114-
listCustomQueryCustomOrders(parameters, orders, ResultRow::toPackageWithShortestDependencyPaths) {
120+
val packages =
121+
listCustomQueryCustomOrders(parameters, orders, ResultRow::toPackageRunData) {
115122
PackagesTable.joinAnalyzerTables()
116123
.innerJoin(IdentifiersTable)
117124
.innerJoin(ProcessedDeclaredLicensesTable)
118125
.select(PackagesTable.columns)
119126
.where { (AnalyzerJobsTable.ortRunId eq ortRunId) and condition }
120127
}
121128

122-
val data = listQueryResult.data.map { pkg ->
123-
val shortestPaths = ShortestDependencyPathsTable
124-
.innerJoin(PackagesTable)
125-
.innerJoin(AnalyzerRunsTable)
126-
.innerJoin(AnalyzerJobsTable)
127-
.select(ShortestDependencyPathsTable.columns)
128-
.where { (AnalyzerJobsTable.ortRunId eq ortRunId) and (PackagesTable.id eq pkg.pkgId) }
129-
.map { ShortestDependencyPathDao.wrapRow(it).mapToModel() }
130-
129+
val curations = RepositoryConfigurationsTable
130+
.innerJoin(RepositoryConfigurationsPackageCurationsTable)
131+
.innerJoin(PackageCurationsTable)
132+
.innerJoin(PackageCurationDataTable)
133+
.innerJoin(IdentifiersTable)
134+
.innerJoin(PackagesTable)
135+
.select(listOf(PackagesTable.id, PackageCurationsTable.id) + PackageCurationDataTable.columns)
136+
.where(RepositoryConfigurationsTable.ortRunId eq ortRunId)
137+
.andWhere { PackagesTable.id inList (packages.data.map { it.pkgId }) }
138+
.distinct()
139+
.groupBy { it[PackagesTable.id].value }
140+
.mapValues { rows -> rows.value.map { PackageCurationDataDao.wrapRow(it).mapToModel() } }
141+
142+
val shortestPaths = ShortestDependencyPathsTable
143+
.innerJoin(PackagesTable)
144+
.innerJoin(AnalyzerRunsTable)
145+
.innerJoin(AnalyzerJobsTable)
146+
.select(ShortestDependencyPathsTable.columns.plus(PackagesTable.id))
147+
.where(AnalyzerJobsTable.ortRunId eq ortRunId)
148+
.andWhere { PackagesTable.id inList (packages.data.map { it.pkgId }) }
149+
.groupBy { it[PackagesTable.id].value }
150+
.mapValues { rows -> rows.value.map { ShortestDependencyPathDao.wrapRow(it).mapToModel() } }
151+
152+
val data = packages.data.map { pkg ->
131153
pkg.copy(
132-
shortestDependencyPaths = shortestPaths
154+
shortestDependencyPaths = shortestPaths.getOrDefault(pkg.pkgId, emptyList()),
155+
curations = curations.getOrDefault(pkg.pkgId, emptyList())
133156
)
134157
}
135158

136-
ListQueryResult(data, parameters, listQueryResult.totalCount)
159+
ListQueryResult(data, parameters, packages.totalCount)
137160
}
138161

139162
/** Count packages found in provided ORT runs. */
@@ -175,8 +198,8 @@ class PackageService(private val db: Database) {
175198
}
176199
}
177200

178-
private fun ResultRow.toPackageWithShortestDependencyPaths(): PackageWithShortestDependencyPaths =
179-
PackageWithShortestDependencyPaths(
201+
private fun ResultRow.toPackageRunData(): PackageRunData =
202+
PackageRunData(
180203
pkg = PackageDao.wrapRow(this).mapToModel(),
181204
pkgId = get(PackagesTable.id).value,
182205
// Temporarily set the shortestDependencyPaths into an empty list, as they will be added in a subsequent step.

services/hierarchy/src/test/kotlin/PackageServiceTest.kt

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import io.kotest.matchers.collections.beEmpty
2424
import io.kotest.matchers.collections.containExactlyInAnyOrder
2525
import io.kotest.matchers.collections.shouldContainInOrder
2626
import io.kotest.matchers.collections.shouldHaveSize
27+
import io.kotest.matchers.nulls.shouldNotBeNull
2728
import io.kotest.matchers.should
2829
import io.kotest.matchers.shouldBe
2930

@@ -39,6 +40,13 @@ import org.eclipse.apoapsis.ortserver.model.runs.ProcessedDeclaredLicense
3940
import org.eclipse.apoapsis.ortserver.model.runs.Project
4041
import org.eclipse.apoapsis.ortserver.model.runs.RemoteArtifact
4142
import org.eclipse.apoapsis.ortserver.model.runs.ShortestDependencyPath
43+
import org.eclipse.apoapsis.ortserver.model.runs.repository.Curations
44+
import org.eclipse.apoapsis.ortserver.model.runs.repository.Excludes
45+
import org.eclipse.apoapsis.ortserver.model.runs.repository.LicenseChoices
46+
import org.eclipse.apoapsis.ortserver.model.runs.repository.PackageCuration
47+
import org.eclipse.apoapsis.ortserver.model.runs.repository.PackageCurationData
48+
import org.eclipse.apoapsis.ortserver.model.runs.repository.RepositoryAnalyzerConfiguration
49+
import org.eclipse.apoapsis.ortserver.model.runs.repository.Resolutions
4250
import org.eclipse.apoapsis.ortserver.model.util.ComparisonOperator
4351
import org.eclipse.apoapsis.ortserver.model.util.FilterOperatorAndValue
4452
import org.eclipse.apoapsis.ortserver.model.util.ListQueryParameters
@@ -316,6 +324,83 @@ class PackageServiceTest : WordSpec() {
316324
}
317325
}
318326

327+
"return package curations" {
328+
val service = PackageService(db)
329+
330+
val project1 = fixtures.getProject()
331+
val project2 = fixtures.getProject(Identifier("Gradle", "", "project2", "1.0"))
332+
333+
val identifier1 = Identifier("Maven", "com.example", "example", "1.0")
334+
val identifier2 = Identifier("Maven", "com.example", "example2", "1.0")
335+
336+
val ortRunId = createAnalyzerRunWithPackages(
337+
projects = setOf(project1, project2),
338+
packages = setOf(
339+
fixtures.generatePackage(identifier1),
340+
fixtures.generatePackage(identifier2)
341+
)
342+
).id
343+
344+
fixtures.repositoryConfigurationRepository.create(
345+
ortRunId = ortRunId,
346+
curations = Curations(
347+
packages = listOf(
348+
PackageCuration(
349+
id = identifier1,
350+
data = PackageCurationData(
351+
comment = "comment1_a",
352+
description = "description1_a",
353+
concludedLicense = "license1_a",
354+
authors = setOf("auth1a_a", "auth1b_a")
355+
)
356+
),
357+
PackageCuration(
358+
id = identifier1,
359+
data = PackageCurationData(
360+
comment = "comment1_b",
361+
description = "description1_b",
362+
concludedLicense = "license1_b",
363+
authors = setOf("auth1a_b", "auth1b_b")
364+
)
365+
)
366+
)
367+
),
368+
analyzerConfig = RepositoryAnalyzerConfiguration(),
369+
excludes = Excludes(),
370+
resolutions = Resolutions(),
371+
packageConfigurations = listOf(),
372+
licenseChoices = LicenseChoices(),
373+
provenanceSnippetChoices = listOf()
374+
)
375+
376+
val results = service.listForOrtRunId(
377+
ortRunId,
378+
ListQueryParameters(listOf(OrderField("purl", OrderDirection.DESCENDING)))
379+
)
380+
381+
results.data shouldHaveSize 2
382+
383+
with(results.data.first()) {
384+
pkg.identifier shouldBe identifier2
385+
curations shouldHaveSize 0
386+
}
387+
388+
with(results.data.last()) {
389+
pkg.identifier shouldBe identifier1
390+
val curr1 = curations.find { it.comment == "comment1_a" }
391+
curr1.shouldNotBeNull()
392+
curr1.comment shouldBe "comment1_a"
393+
curr1.description shouldBe "description1_a"
394+
curr1.concludedLicense shouldBe "license1_a"
395+
396+
val curr2 = curations.find { it.comment == "comment1_b" }
397+
curr2.shouldNotBeNull()
398+
curr2.comment shouldBe "comment1_b"
399+
curr2.description shouldBe "description1_b"
400+
curr2.concludedLicense shouldBe "license1_b"
401+
}
402+
}
403+
319404
"allow filtering by identifier" {
320405
val service = PackageService(db)
321406

0 commit comments

Comments
 (0)