-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(services): Implement a service for handling Issues
Signed-off-by: Marcel Bochtler <marcel.bochtler@bosch.com>
- Loading branch information
1 parent
b4996ce
commit 42adab3
Showing
3 changed files
with
481 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright (C) 2024 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* License-Filename: LICENSE | ||
*/ | ||
|
||
package org.eclipse.apoapsis.ortserver.model | ||
|
||
import org.eclipse.apoapsis.ortserver.model.runs.Identifier | ||
import org.eclipse.apoapsis.ortserver.model.runs.Issue | ||
|
||
/** | ||
* A union data class to associate an [Issue] with an [Identifier]. | ||
*/ | ||
data class IssueWithIdentifier( | ||
val issue: Issue, | ||
val identifier: Identifier? | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/* | ||
* Copyright (C) 2024 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* License-Filename: LICENSE | ||
*/ | ||
|
||
package org.eclipse.apoapsis.ortserver.services | ||
|
||
import org.eclipse.apoapsis.ortserver.dao.dbQuery | ||
import org.eclipse.apoapsis.ortserver.dao.tables.AdvisorJobsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.AnalyzerJobsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.OrtRunsIssuesTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.ScanResultsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.ScanSummariesIssuesTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.ScanSummariesTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.ScannerJobsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.advisor.AdvisorResultsIssuesTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.advisor.AdvisorResultsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.advisor.AdvisorRunsIdentifiersTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.advisor.AdvisorRunsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.analyzer.AnalyzerRunsIdentifiersIssuesTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.analyzer.AnalyzerRunsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.scanner.ScannerRunsScanResultsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.scanner.ScannerRunsScannersTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.scanner.ScannerRunsTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IdentifiersIssuesTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IdentifiersTable | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IssueDao | ||
import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IssuesTable | ||
import org.eclipse.apoapsis.ortserver.dao.utils.listCustomQuery | ||
import org.eclipse.apoapsis.ortserver.model.IssueWithIdentifier | ||
import org.eclipse.apoapsis.ortserver.model.runs.Identifier | ||
import org.eclipse.apoapsis.ortserver.model.runs.Issue | ||
import org.eclipse.apoapsis.ortserver.model.util.ListQueryParameters | ||
import org.eclipse.apoapsis.ortserver.model.util.ListQueryResult | ||
|
||
import org.jetbrains.exposed.sql.Database | ||
import org.jetbrains.exposed.sql.Op | ||
import org.jetbrains.exposed.sql.Query | ||
import org.jetbrains.exposed.sql.ResultRow | ||
import org.jetbrains.exposed.sql.alias | ||
import org.jetbrains.exposed.sql.innerJoin | ||
import org.jetbrains.exposed.sql.selectAll | ||
import org.jetbrains.exposed.sql.union | ||
|
||
/** | ||
* A service to manage and get information about issues. | ||
*/ | ||
class IssueService(private val db: Database) { | ||
suspend fun listForOrtRunId( | ||
ortRunId: Long, | ||
parameters: ListQueryParameters = ListQueryParameters.DEFAULT | ||
): ListQueryResult<IssueWithIdentifier> = db.dbQuery { | ||
val ortRunIssuesQuery = createOrtRunIssuesQuery(ortRunId) | ||
val analyzerIssuesQuery = createAnalyzerIssuesQuery(ortRunId) | ||
val advisorIssuesQuery = createAdvisorIssuesQuery(ortRunId) | ||
val scannerIssuesQuery = createScannerIssuesQuery(ortRunId) | ||
|
||
val combinedQuery = | ||
ortRunIssuesQuery.union(analyzerIssuesQuery).union(advisorIssuesQuery).union(scannerIssuesQuery) | ||
|
||
val subQueryAlias = combinedQuery.alias("combined_query").selectAll() | ||
|
||
val modifiedParameters = parameters.copy( | ||
sortFields = parameters.sortFields.map { sortField -> | ||
sortField.copy(name = "combined_query.${sortField.name}") | ||
} | ||
) | ||
|
||
// FIXME: listCustomQuery currently doesn't work with a custom query, because it doesn't support aliases, and | ||
// checks if the column is sortable. | ||
val result = IssueDao.listCustomQuery(modifiedParameters, ResultRow::toIssueWithIdentifier) { | ||
subQueryAlias | ||
} | ||
|
||
result | ||
} | ||
|
||
private fun createOrtRunIssuesQuery(ortRunId: Long) = (IssuesTable innerJoin OrtRunsIssuesTable).select( | ||
IssuesTable.timestamp, | ||
IssuesTable.issueSource, | ||
IssuesTable.message, | ||
IssuesTable.severity, | ||
IssuesTable.affectedPath, | ||
Op.nullOp<Unit>().alias("type"), | ||
Op.nullOp<Unit>().alias("namespace"), | ||
Op.nullOp<Unit>().alias("name"), | ||
Op.nullOp<Unit>().alias("version") | ||
).where { OrtRunsIssuesTable.ortRunId eq ortRunId } | ||
|
||
private fun createAnalyzerIssuesQuery(ortRunId: Long): Query { | ||
val analyzerIssuesIdentifiersJoin = ( | ||
IssuesTable innerJoin | ||
IdentifiersIssuesTable innerJoin | ||
AnalyzerRunsIdentifiersIssuesTable innerJoin | ||
AnalyzerRunsTable innerJoin | ||
AnalyzerJobsTable innerJoin | ||
IdentifiersTable | ||
) | ||
|
||
return analyzerIssuesIdentifiersJoin.select( | ||
IssuesTable.timestamp, | ||
IssuesTable.issueSource, | ||
IssuesTable.message, | ||
IssuesTable.severity, | ||
IssuesTable.affectedPath, | ||
IdentifiersTable.type, | ||
IdentifiersTable.name, | ||
IdentifiersTable.namespace, | ||
IdentifiersTable.version | ||
).where { AnalyzerJobsTable.ortRunId eq ortRunId } | ||
} | ||
|
||
private fun createAdvisorIssuesQuery(ortRunId: Long): Query { | ||
val advisorIssuesIdentifiersJoin = IssuesTable | ||
.innerJoin(AdvisorResultsIssuesTable, { IssuesTable.id }, { issueId }) | ||
.innerJoin(AdvisorResultsTable, { AdvisorResultsIssuesTable.advisorResultId }, { AdvisorResultsTable.id }) | ||
.innerJoin(AdvisorRunsTable, { AdvisorResultsTable.advisorRunIdentifierId }, { AdvisorRunsTable.id }) | ||
.innerJoin(AdvisorJobsTable, { AdvisorRunsTable.advisorJobId }, { AdvisorJobsTable.id }) | ||
.innerJoin(AdvisorRunsIdentifiersTable, { AdvisorRunsTable.id }, { advisorRunId }) | ||
.innerJoin(IdentifiersTable, { AdvisorRunsIdentifiersTable.identifierId }, { IdentifiersTable.id }) | ||
|
||
return advisorIssuesIdentifiersJoin.select( | ||
IssuesTable.timestamp, | ||
IssuesTable.issueSource, | ||
IssuesTable.message, | ||
IssuesTable.severity, | ||
IssuesTable.affectedPath, | ||
IdentifiersTable.type, | ||
IdentifiersTable.name, | ||
IdentifiersTable.namespace, | ||
IdentifiersTable.version | ||
).where { AdvisorJobsTable.ortRunId eq ortRunId } | ||
} | ||
|
||
private fun createScannerIssuesQuery(ortRunId: Long): Query { | ||
val scannerIssuesIdentifiersJoin = ( | ||
IssuesTable innerJoin | ||
ScanSummariesIssuesTable innerJoin | ||
ScanSummariesTable innerJoin | ||
ScanResultsTable innerJoin | ||
ScannerRunsScanResultsTable innerJoin | ||
ScannerRunsTable innerJoin | ||
ScannerJobsTable innerJoin | ||
ScannerRunsScannersTable innerJoin | ||
IdentifiersTable | ||
) | ||
|
||
return scannerIssuesIdentifiersJoin.select( | ||
IssuesTable.timestamp, | ||
IssuesTable.issueSource, | ||
IssuesTable.message, | ||
IssuesTable.severity, | ||
IssuesTable.affectedPath, | ||
IdentifiersTable.type, | ||
IdentifiersTable.name, | ||
IdentifiersTable.namespace, | ||
IdentifiersTable.version | ||
).where { ScannerJobsTable.ortRunId eq ortRunId } | ||
} | ||
} | ||
|
||
private fun ResultRow.toIssueWithIdentifier(): IssueWithIdentifier { | ||
val issue = Issue( | ||
timestamp = this[IssuesTable.timestamp], | ||
source = this[IssuesTable.issueSource], | ||
message = this[IssuesTable.message], | ||
severity = this[IssuesTable.severity], | ||
affectedPath = this[IssuesTable.affectedPath] | ||
) | ||
|
||
val identifier = this.getOrNull(IdentifiersTable.type)?.let { | ||
Identifier( | ||
type = this[IdentifiersTable.type], | ||
namespace = this[IdentifiersTable.namespace], | ||
name = this[IdentifiersTable.name], | ||
version = this[IdentifiersTable.version] | ||
) | ||
} | ||
|
||
return IssueWithIdentifier(issue, identifier) | ||
} |
Oops, something went wrong.