diff --git a/model/src/main/kotlin/OrtResult.kt b/model/src/main/kotlin/OrtResult.kt index fdd012951e0c4..634585556bfce 100644 --- a/model/src/main/kotlin/OrtResult.kt +++ b/model/src/main/kotlin/OrtResult.kt @@ -153,6 +153,29 @@ data class OrtResult( resolvedConfiguration.packageConfigurations.orEmpty().groupBy { it.id } } + private val excludedAffectedPathIssuesForId: Map> by lazy { + buildMap> { + scanner?.getAllScanResults().orEmpty().forEach { (id, scanResults) -> + scanResults.forEach { scanResult -> + val pathExcludes = getPathExcludes(id, scanResult.provenance) + + scanResult.summary.issues.forEach { issue -> + if (issue.affectedPath != null && pathExcludes.any { it.matches(issue.affectedPath) }) { + getOrPut(id, { mutableSetOf() }) += issue + } + } + } + } + } + } + + private fun getPathExcludes(id: Identifier, provenance: Provenance) = + if (isProject(id)) { + repository.config.excludes.paths + } else { + getPackageConfigurations(id, provenance).flatMapTo(mutableSetOf()) { it.pathExcludes } + } + /** * A map of projects and their excluded state. Calculating this map once brings massive performance improvements * when querying projects in large analyzer results. @@ -264,7 +287,9 @@ data class OrtResult( if (omitExcluded && isExcluded(id)) return@mapNotNull null val filteredIssues = issues.filterTo(mutableSetOf()) { - (!omitResolved || !isResolved(it)) && it.severity >= minSeverity + (!omitResolved || !isResolved(it)) + && it.severity >= minSeverity + && it !in excludedAffectedPathIssuesForId[id].orEmpty() } filteredIssues.takeUnless { it.isEmpty() }?.let { id to it } diff --git a/model/src/test/kotlin/OrtResultTest.kt b/model/src/test/kotlin/OrtResultTest.kt index 35234fc696cd2..c5065a38cd65a 100644 --- a/model/src/test/kotlin/OrtResultTest.kt +++ b/model/src/test/kotlin/OrtResultTest.kt @@ -21,6 +21,7 @@ package org.ossreviewtoolkit.model import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.WordSpec +import io.kotest.matchers.collections.beEmpty import io.kotest.matchers.collections.containExactlyInAnyOrder import io.kotest.matchers.collections.haveSize import io.kotest.matchers.collections.shouldContain @@ -247,6 +248,79 @@ class OrtResultTest : WordSpec({ openIssues.map { it.message } shouldHaveSingleElement "Included issue" } + + "omit scan issues with excluded affected path" { + val projectId = Identifier("Maven:org.oss-review-toolkit:example-project:1.0") + val vcs = VcsInfo( + type = VcsType.GIT, + url = "https:/github.com/example.project.git", + revision = "0000000000000000000000000000000000000000", + path = "" + ) + + val ortResult = OrtResult.EMPTY.copy( + repository = Repository.EMPTY.copy( + vcs = vcs, + vcsProcessed = vcs, + config = RepositoryConfiguration( + excludes = Excludes( + paths = listOf( + PathExclude( + pattern = "test/**", + reason = PathExcludeReason.TEST_OF + ) + ) + ) + ) + ), + analyzer = AnalyzerRun.EMPTY.copy( + result = AnalyzerResult.EMPTY.copy( + projects = setOf( + Project.EMPTY.copy( + id = projectId, + definitionFilePath = "pom.xml", + declaredLicenses = emptySet(), + vcsProcessed = vcs + ) + ) + ) + ), + scanner = ScannerRun.EMPTY.copy( + scanners = mapOf(projectId to setOf("ScanCode")), + provenances = setOf( + ProvenanceResolutionResult( + id = projectId, + packageProvenance = RepositoryProvenance( + vcsInfo = vcs, + resolvedRevision = vcs.revision + ) + ) + ), + scanResults = setOf( + ScanResult( + provenance = RepositoryProvenance( + vcsInfo = vcs, + resolvedRevision = vcs.revision + ), + scanner = ScannerDetails.EMPTY.copy(name = "ScanCode"), + summary = ScanSummary.EMPTY.copy( + issues = listOf( + Issue( + message = "Included issue", + source = "ScanCode", + affectedPath = "test/assets/asset.json" + ) + ) + ) + ) + ) + ) + ) + + val issues = ortResult.getOpenIssues() + + issues should beEmpty() + } } "dependencyNavigator" should {