diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 4ca0e6b7df94a..0d403ed9bc936 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: wagoid/commitlint-github-action@v5 + - uses: wagoid/commitlint-github-action@v6 with: configFile: .commitlintrc.yml code-base-checks: @@ -85,7 +85,7 @@ jobs: with: fetch-depth: 0 - name: Qodana Scan - uses: JetBrains/qodana-action@v2023.3.1 + uses: JetBrains/qodana-action@v2023.3.2 with: post-pr-comment: false use-caches: false diff --git a/.versions b/.versions index 66c6fc6ed8fdb..4545fbc039eae 100644 --- a/.versions +++ b/.versions @@ -27,7 +27,7 @@ PYTHON_VERSION=3.11.8 RUBY_VERSION=3.1.2 RUST_VERSION=1.72.0 SBT_VERSION=1.9.7 -SCANCODE_VERSION=32.0.8 +SCANCODE_VERSION=32.1.0 SWIFT_VERSION=5.9.2 UBUNTU_VERSION=jammy YARN_VERSION=1.22.19 diff --git a/Dockerfile b/Dockerfile index 45ff874608332..dad4f05c9f31b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -151,7 +151,7 @@ ARG PYTHON_INSPECTOR_VERSION=0.10.0 ARG PYTHON_PIPENV_VERSION=2023.10.24 ARG PYTHON_POETRY_VERSION=1.7.0 ARG PIPTOOL_VERSION=23.3.1 -ARG SCANCODE_VERSION=32.0.8 +ARG SCANCODE_VERSION=32.1.0 RUN pip install --no-cache-dir -U \ pip=="$PIPTOOL_VERSION" \ diff --git a/Dockerfile-legacy b/Dockerfile-legacy index 16c4a26e077a8..f28d581eb67be 100644 --- a/Dockerfile-legacy +++ b/Dockerfile-legacy @@ -39,7 +39,7 @@ ARG NUGET_INSPECTOR_VERSION=0.9.12 ARG PYTHON_INSPECTOR_VERSION="0.10.0" # Set this to the ScanCode version to use. -ARG SCANCODE_VERSION="32.0.8" +ARG SCANCODE_VERSION="32.1.0" FROM eclipse-temurin:$JAVA_VERSION-jdk-jammy AS build diff --git a/build.gradle.kts b/build.gradle.kts index 332d6deab74a2..f3345a9692154 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -152,7 +152,7 @@ val checkLicenseHeaders by tasks.registering { val headerLines = LicenseUtils.extractHeader(file) val holders = CopyrightUtils.extractHolders(headerLines) - if (holders.singleOrNull() != CopyrightUtils.expectedHolder) { + if (holders.singleOrNull() != CopyrightUtils.EXPECTED_HOLDER) { hasErrors = true logger.error("Unexpected copyright holder(s) in file '$file': $holders") } diff --git a/buildSrc/src/main/kotlin/LicenseUtils.kt b/buildSrc/src/main/kotlin/LicenseUtils.kt index 7632faa67d3e6..3584c13a459fc 100644 --- a/buildSrc/src/main/kotlin/LicenseUtils.kt +++ b/buildSrc/src/main/kotlin/LicenseUtils.kt @@ -71,10 +71,10 @@ object CopyrightableFiles { } object CopyrightUtils { - const val expectedHolder = + const val EXPECTED_HOLDER = "The ORT Project Authors (see )" - private const val maxCopyrightLines = 50 + private const val MAX_COPYRIGHT_LINES = 50 private val copyrightPrefixRegex = Regex("Copyright .*\\d{2,}(-\\d{2,})? ", RegexOption.IGNORE_CASE) fun extract(file: File): List { @@ -84,7 +84,7 @@ object CopyrightUtils { file.useLines { lines -> lines.forEach { line -> - if (++lineCounter > maxCopyrightLines) return@forEach + if (++lineCounter > MAX_COPYRIGHT_LINES) return@forEach val copyright = line.replaceBefore(" Copyright ", "", "").trim() if (copyright.isNotEmpty() && !copyright.endsWith("\"")) copyrights += copyright } @@ -123,11 +123,11 @@ object LicenseUtils { SPDX-License-Identifier: Apache-2.0 """.trimIndent() - private const val lastHeaderLine = "License-Filename: LICENSE" + private const val LAST_HEADER_LINE = "License-Filename: LICENSE" fun extractHeader(file: File): List { var headerLines = file.useLines { lines -> - lines.takeWhile { !it.endsWith(lastHeaderLine) }.toList() + lines.takeWhile { !it.endsWith(LAST_HEADER_LINE) }.toList() } while (true) { diff --git a/downloader/src/main/kotlin/VcsHost.kt b/downloader/src/main/kotlin/VcsHost.kt index 93db9d31203bb..cc75911cef799 100644 --- a/downloader/src/main/kotlin/VcsHost.kt +++ b/downloader/src/main/kotlin/VcsHost.kt @@ -39,7 +39,7 @@ enum class VcsHost( /** * The hostname of VCS host. */ - protected val hostname: String, + val hostname: String, /** * The VCS types the host supports. diff --git a/downloader/src/main/kotlin/VersionControlSystem.kt b/downloader/src/main/kotlin/VersionControlSystem.kt index 1bdb034cf3cb0..ced80cea2412a 100644 --- a/downloader/src/main/kotlin/VersionControlSystem.kt +++ b/downloader/src/main/kotlin/VersionControlSystem.kt @@ -207,7 +207,7 @@ abstract class VersionControlSystem( /** * Return true if this [VersionControlSystem] is available for use. */ - fun isAvailable(): Boolean = commandLineTool?.isInPath() ?: true + fun isAvailable(): Boolean = commandLineTool?.isInPath() != false /** * Test - in a way specific to this [VersionControlSystem] - whether it can be used to download from the provided diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fb95fb3d29aae..35793be6be162 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,11 @@ [versions] -dependencyAnalysisPlugin = "1.30.0" -detektPlugin = "1.23.5" -dokkatooPlugin = "2.2.0" +dependencyAnalysisPlugin = "1.31.0" +detektPlugin = "1.23.6" +dokkatooPlugin = "2.3.0" downloadPlugin = "5.6.0" gitSemverPlugin = "0.12.6" graalVmNativeImagePlugin = "0.10.1" -graphQlPlugin = "6.6.0" +graphQlPlugin = "6.7.0" ideaExtPlugin = "1.1.8" kotlinPlugin = "1.9.23" mavenPublishPlugin = "0.28.0" @@ -13,13 +13,13 @@ versionsPlugin = "0.51.0" asciidoctorj = "2.5.12" asciidoctorjPdf = "2.3.15" -clikt = "4.2.2" +clikt = "4.3.0" commonsCompress = "1.26.1" cvssCalculator = "1.4.2" cyclonedx = "8.0.3" diffUtils = "4.12" diskLruCache = "2.0.2" -exposed = "0.48.0" +exposed = "0.49.0" flexmark = "0.64.8" freemarker = "2.3.32" greenmail = "2.0.1" @@ -48,9 +48,9 @@ mockk = "1.13.10" mordant = "2.4.0" okhttp = "4.12.0" postgres = "42.7.3" -postgresEmbedded = "1.0.2" +postgresEmbedded = "1.0.3" reflections = "0.10.2" -retrofit = "2.10.0" +retrofit = "2.11.0" s3 = "2.25.0" saxonHe = "12.4" scanoss = "1.1.6" @@ -59,7 +59,7 @@ slf4j = "2.0.12" springCore = "5.3.33" svnkit = "1.10.11" sw360Client = "17.0.1-m2" -wiremock = "3.4.2" +wiremock = "3.5.2" xz = "1.9" [plugins] diff --git a/helper-cli/src/funTest/kotlin/commands/CreateAnalyzerResultFromPackageListCommandFunTest.kt b/helper-cli/src/funTest/kotlin/commands/CreateAnalyzerResultFromPackageListCommandFunTest.kt index 09f2c11c119ab..079515fb815b6 100644 --- a/helper-cli/src/funTest/kotlin/commands/CreateAnalyzerResultFromPackageListCommandFunTest.kt +++ b/helper-cli/src/funTest/kotlin/commands/CreateAnalyzerResultFromPackageListCommandFunTest.kt @@ -22,6 +22,7 @@ package org.ossreviewtoolkit.helper.commands import com.github.ajalt.clikt.testing.test import io.kotest.core.spec.style.WordSpec +import io.kotest.engine.spec.tempdir import io.kotest.matchers.shouldBe import org.ossreviewtoolkit.helper.HelperMain @@ -29,14 +30,13 @@ import org.ossreviewtoolkit.model.OrtResult import org.ossreviewtoolkit.model.ResolvedConfiguration import org.ossreviewtoolkit.model.readValue import org.ossreviewtoolkit.utils.ort.Environment -import org.ossreviewtoolkit.utils.ort.createOrtTempDir import org.ossreviewtoolkit.utils.test.getAssetFile class CreateAnalyzerResultFromPackageListCommandFunTest : WordSpec({ "The command" should { "generate the expected analyzer result file" { val inputFile = getAssetFile("package-list.yml") - val outputFile = createOrtTempDir().resolve("analyzer-result.yml") + val outputFile = tempdir().resolve("analyzer-result.yml") val expectedOutputFile = getAssetFile("create-analyzer-result-from-pkg-list-expected-output.yml") HelperMain().test( diff --git a/helper-cli/src/main/kotlin/commands/VerifySourceArtifactCurationsCommand.kt b/helper-cli/src/main/kotlin/commands/VerifySourceArtifactCurationsCommand.kt index 82d14f88f2dbc..bf345446ae6ed 100644 --- a/helper-cli/src/main/kotlin/commands/VerifySourceArtifactCurationsCommand.kt +++ b/helper-cli/src/main/kotlin/commands/VerifySourceArtifactCurationsCommand.kt @@ -78,7 +78,7 @@ internal class VerifySourceArtifactCurationsCommand : CliktCommand( } finally { tempDir.safeDeleteRecursively(force = true) } - } ?: true + } != false } println("\n-----") diff --git a/integrations/completions/ort-completion.bash b/integrations/completions/ort-completion.bash index 3de1707f4dc9a..ec7b053b2fe69 100644 --- a/integrations/completions/ort-completion.bash +++ b/integrations/completions/ort-completion.bash @@ -906,6 +906,12 @@ _ort_migrate() { [[ ${i} -gt COMP_CWORD ]] && in_param='--nuget-ids' || in_param='' continue ;; + --pub-ids) + __skip_opt_eq + (( i = i + 1 )) + [[ ${i} -gt COMP_CWORD ]] && in_param='--pub-ids' || in_param='' + continue + ;; -h|--help) __skip_opt_eq in_param='' @@ -923,7 +929,7 @@ _ort_migrate() { done local word="${COMP_WORDS[$COMP_CWORD]}" if [[ "${word}" =~ ^[-] ]]; then - COMPREPLY=($(compgen -W '--hocon-to-yaml --nuget-ids -h --help' -- "${word}")) + COMPREPLY=($(compgen -W '--hocon-to-yaml --nuget-ids --pub-ids -h --help' -- "${word}")) return fi @@ -939,6 +945,9 @@ _ort_migrate() { --nuget-ids) COMPREPLY=($(compgen -o default -- "${word}")) ;; + --pub-ids) + COMPREPLY=($(compgen -o default -- "${word}")) + ;; --help) ;; esac diff --git a/integrations/completions/ort-completion.fish b/integrations/completions/ort-completion.fish index 19004c25b81ac..83ed6a1b072c1 100644 --- a/integrations/completions/ort-completion.fish +++ b/integrations/completions/ort-completion.fish @@ -34,7 +34,7 @@ complete -c ort -n "__fish_seen_subcommand_from advise" -s h -l help -d 'Show th complete -c ort -f -n __fish_use_subcommand -a analyze -d 'Determine dependencies of a software project.' ## Options for analyze -complete -c ort -n "__fish_seen_subcommand_from analyze" -l input-dir -s i -r -F -d 'The project directory to analyze. As a special case, if only one package manager is enabled, this may point to a definition file for that package manager to only analyze that single project.' +complete -c ort -n "__fish_seen_subcommand_from analyze" -l input-dir -s i -r -F -d 'The project directory to analyze. May point to a definition file if only a single package manager is enabled.' complete -c ort -n "__fish_seen_subcommand_from analyze" -l output-dir -s o -r -F -d 'The directory to write the ORT result file with analyzer results to.' complete -c ort -n "__fish_seen_subcommand_from analyze" -l output-formats -s f -r -fa "JSON XML YAML" -d 'The list of output formats to be used for the ORT result file(s).' complete -c ort -n "__fish_seen_subcommand_from analyze" -l repository-configuration-file -r -F -d 'A file containing the repository configuration. If set, overrides any repository configuration contained in a \'.ort.yml\' file in the repository.' @@ -119,6 +119,7 @@ complete -c ort -f -n __fish_use_subcommand -a migrate -d 'Assist with migrating ## Options for migrate complete -c ort -n "__fish_seen_subcommand_from migrate" -l hocon-to-yaml -r -F -d 'Perform a simple conversion of the given HOCON configuration file to YAML and print the result.' complete -c ort -n "__fish_seen_subcommand_from migrate" -l nuget-ids -r -F -d 'Convert NuGet package IDs in curations and configurations to the new format that includes a namespace.' +complete -c ort -n "__fish_seen_subcommand_from migrate" -l pub-ids -r -F -d 'Convert Pub package IDs in curations and configurations to the new format that has no namespace.' complete -c ort -n "__fish_seen_subcommand_from migrate" -s h -l help -d 'Show this message and exit' diff --git a/integrations/completions/ort-completion.zsh b/integrations/completions/ort-completion.zsh index abe80d4314b5b..df61c37f7c81d 100644 --- a/integrations/completions/ort-completion.zsh +++ b/integrations/completions/ort-completion.zsh @@ -2,7 +2,9 @@ # Command completion for ort # Generated by Clikt -autoload bashcompinit +autoload -Uz compinit +compinit +autoload -Uz bashcompinit bashcompinit __skip_opt_eq() { @@ -909,6 +911,12 @@ _ort_migrate() { [[ ${i} -gt COMP_CWORD ]] && in_param='--nuget-ids' || in_param='' continue ;; + --pub-ids) + __skip_opt_eq + (( i = i + 1 )) + [[ ${i} -gt COMP_CWORD ]] && in_param='--pub-ids' || in_param='' + continue + ;; -h|--help) __skip_opt_eq in_param='' @@ -926,7 +934,7 @@ _ort_migrate() { done local word="${COMP_WORDS[$COMP_CWORD]}" if [[ "${word}" =~ ^[-] ]]; then - COMPREPLY=($(compgen -W '--hocon-to-yaml --nuget-ids -h --help' -- "${word}")) + COMPREPLY=($(compgen -W '--hocon-to-yaml --nuget-ids --pub-ids -h --help' -- "${word}")) return fi @@ -942,6 +950,9 @@ _ort_migrate() { --nuget-ids) COMPREPLY=($(compgen -o default -- "${word}")) ;; + --pub-ids) + COMPREPLY=($(compgen -o default -- "${word}")) + ;; --help) ;; esac diff --git a/integrations/schemas/package-managers-schema.json b/integrations/schemas/package-managers-schema.json index 563f05578f5e3..9bef2d75aaf74 100644 --- a/integrations/schemas/package-managers-schema.json +++ b/integrations/schemas/package-managers-schema.json @@ -4,6 +4,7 @@ "title": "ORT Package Managers", "description": "A list of package managers supported by the OSS Review Toolkit (ORT). A full list of all supported package managers can ve found at https://github.com/oss-review-toolkit/ort/blob/main/analyzer/src/main/resources/META-INF/services/org.ossreviewtoolkit.analyzer.PackageManagerFactory.", "enum": [ + "Bazel", "Bower", "Bundler", "Cargo", @@ -26,6 +27,7 @@ "SBT", "SpdxDocumentFile", "Stack", + "SwiftPM", "Unmanaged", "Yarn", "Yarn2" diff --git a/model/src/main/kotlin/OrtResult.kt b/model/src/main/kotlin/OrtResult.kt index 1a051cf81e8b1..4abeb5d97d1e3 100644 --- a/model/src/main/kotlin/OrtResult.kt +++ b/model/src/main/kotlin/OrtResult.kt @@ -559,7 +559,7 @@ data class OrtResult( * * Return `false` if there is no dependency on this [id]. */ - fun isPackageExcluded(id: Identifier): Boolean = packages[id]?.isExcluded ?: false + fun isPackageExcluded(id: Identifier): Boolean = packages[id]?.isExcluded == true /** * Return `true` if the [Project] with the given [id] is excluded. @@ -570,7 +570,7 @@ data class OrtResult( * * Return `false` if no project with the given [id] is found. */ - fun isProjectExcluded(id: Identifier): Boolean = projects[id]?.isExcluded ?: false + fun isProjectExcluded(id: Identifier): Boolean = projects[id]?.isExcluded == true /** * Return true if and only if the given [id] denotes a [Package] contained in this [OrtResult]. diff --git a/model/src/main/kotlin/PackageCuration.kt b/model/src/main/kotlin/PackageCuration.kt index 9c7108dd9956e..fddb190f412e2 100644 --- a/model/src/main/kotlin/PackageCuration.kt +++ b/model/src/main/kotlin/PackageCuration.kt @@ -74,7 +74,7 @@ data class PackageCuration( // `Semver.satisfies(String)` requires a valid version range to work as expected, see: // https://github.com/semver4j/semver4j/issues/132. val range = RangesListFactory.create(id.version) - require(range.get().size > 0) { + require(range.get().isNotEmpty()) { "'${id.version}' is not a valid version range." } diff --git a/model/src/main/kotlin/ScanSummary.kt b/model/src/main/kotlin/ScanSummary.kt index 3df7b44151957..1aec1b3497d65 100644 --- a/model/src/main/kotlin/ScanSummary.kt +++ b/model/src/main/kotlin/ScanSummary.kt @@ -128,7 +128,7 @@ data class ScanSummary( licenseFindings = licenseFindings.filterTo(mutableSetOf()) { it.location.matchesPaths() }, copyrightFindings = copyrightFindings.filterTo(mutableSetOf()) { it.location.matchesPaths() }, snippetFindings = snippetFindings.filterTo(mutableSetOf()) { it.sourceLocation.matchesPaths() }, - issues = issues.filter { it.affectedPath?.matchesPaths() ?: true } + issues = issues.filter { it.affectedPath?.matchesPaths() != false } ) } diff --git a/model/src/main/kotlin/utils/ConfigurationResolver.kt b/model/src/main/kotlin/utils/ConfigurationResolver.kt index f82d44a70b8a2..0df7a9b2d0969 100644 --- a/model/src/main/kotlin/utils/ConfigurationResolver.kt +++ b/model/src/main/kotlin/utils/ConfigurationResolver.kt @@ -65,9 +65,11 @@ object ConfigurationResolver { curationProvider.getCurationsFor(packages) } + // While every provider is supposed to only return applicable curations, filter to be on the safe side and + // only embed applicable curations in the ORT result. val (applicableCurations, nonApplicableCurations) = curations.partition { curation -> packages.any { pkg -> curation.isApplicable(pkg.id) } - }.let { it.first to it.second } + } if (nonApplicableCurations.isNotEmpty()) { logger.warn { diff --git a/model/src/main/kotlin/utils/DependencyGraphBuilder.kt b/model/src/main/kotlin/utils/DependencyGraphBuilder.kt index ea0c3e08699ff..c2eb2c17647f6 100644 --- a/model/src/main/kotlin/utils/DependencyGraphBuilder.kt +++ b/model/src/main/kotlin/utils/DependencyGraphBuilder.kt @@ -327,7 +327,7 @@ class DependencyGraphBuilder( if (!dependencies2.keys.containsAll(dependencies1)) return false return ref.dependencies.all { refDep -> - dependencies2[dependencyIds[refDep.pkg]]?.let { dependencyTreeEquals(refDep, it) } ?: false + dependencies2[dependencyIds[refDep.pkg]]?.let { dependencyTreeEquals(refDep, it) } == true } } diff --git a/model/src/main/kotlin/utils/DependencyGraphConverter.kt b/model/src/main/kotlin/utils/DependencyGraphConverter.kt index 01e4aaf541e8b..2394a6d86af40 100644 --- a/model/src/main/kotlin/utils/DependencyGraphConverter.kt +++ b/model/src/main/kotlin/utils/DependencyGraphConverter.kt @@ -111,7 +111,7 @@ object DependencyGraphConverter { * their dependencies in a scope structure. */ private fun AnalyzerResult.projectsWithScopes(): Set = - projects.filterTo(mutableSetOf()) { it.scopeDependencies?.isNotEmpty() ?: false } + projects.filterTo(mutableSetOf()) { it.scopeDependencies?.isNotEmpty() == true } /** * Convert the dependency representation used by this [Project] to the dependency graph format, i.e. a set of diff --git a/model/src/main/kotlin/utils/FindingsMatcher.kt b/model/src/main/kotlin/utils/FindingsMatcher.kt index 749d6506dbbb3..53800ee89a53a 100644 --- a/model/src/main/kotlin/utils/FindingsMatcher.kt +++ b/model/src/main/kotlin/utils/FindingsMatcher.kt @@ -287,7 +287,7 @@ fun associateLicensesWithExceptions( * licenses. Orphan license exceptions will get associated by [SpdxConstants.NOASSERTION]. Return a new expression that * does not contain stand-alone license exceptions anymore. */ -internal fun associateLicensesWithExceptions(license: SpdxExpression): SpdxExpression { +fun associateLicensesWithExceptions(license: SpdxExpression): SpdxExpression { // If this is not a compound expression, there can be no stand-alone license exceptions with belonging licenses. if (license !is SpdxCompoundExpression) return license diff --git a/plugins/advisors/github/src/main/kotlin/GitHubDefects.kt b/plugins/advisors/github/src/main/kotlin/GitHubDefects.kt index 227f477f95ae0..8cb28a530b6b2 100644 --- a/plugins/advisors/github/src/main/kotlin/GitHubDefects.kt +++ b/plugins/advisors/github/src/main/kotlin/GitHubDefects.kt @@ -164,7 +164,7 @@ class GitHubDefects(name: String, config: GitHubDefectsConfiguration) : AdvicePr if (tags.size == 1) return releases.find { it.tagName == tags.first() } val revision = "/${pkg.vcsProcessed.revision}" - return releases.find { it.tagCommit?.commitUrl?.endsWith(revision) ?: false } + return releases.find { it.tagCommit?.commitUrl?.endsWith(revision) == true } } /** @@ -259,7 +259,7 @@ class GitHubDefects(name: String, config: GitHubDefectsConfiguration) : AdvicePr private fun List.applyLabelFilters(): List = filter { issue -> val labels = issue.labels() - labelFilters.find { it.matches(labels) }?.including ?: false + labelFilters.find { it.matches(labels) }?.including == true } } diff --git a/plugins/package-configuration-providers/dir/src/main/kotlin/DirPackageConfigurationProvider.kt b/plugins/package-configuration-providers/dir/src/main/kotlin/DirPackageConfigurationProvider.kt index 97c564c672797..3b50ed09f99bc 100644 --- a/plugins/package-configuration-providers/dir/src/main/kotlin/DirPackageConfigurationProvider.kt +++ b/plugins/package-configuration-providers/dir/src/main/kotlin/DirPackageConfigurationProvider.kt @@ -54,7 +54,7 @@ open class DirPackageConfigurationProviderFactory : override fun parseConfig(options: Options, secrets: Options) = DirPackageConfigurationProviderConfig( path = File(options.getValue("path")), - mustExist = options["mustExist"]?.toBooleanStrict() ?: true + mustExist = options["mustExist"]?.toBooleanStrict() != false ) } diff --git a/plugins/package-curation-providers/file/src/main/kotlin/FilePackageCurationProvider.kt b/plugins/package-curation-providers/file/src/main/kotlin/FilePackageCurationProvider.kt index e48f94387ce3a..60cc2d6540493 100644 --- a/plugins/package-curation-providers/file/src/main/kotlin/FilePackageCurationProvider.kt +++ b/plugins/package-curation-providers/file/src/main/kotlin/FilePackageCurationProvider.kt @@ -54,7 +54,7 @@ open class FilePackageCurationProviderFactory : PackageCurationProviderFactory): Set { val modGraphProcess = run("mod", "graph", "--output", "json", workingDir = projectDir) val node = JSON.decodeFromString(modGraphProcess.stdout) - val devDeps = node.dependencies.filter { depDirectives[it.key]?.devDependency ?: false }.toSet() + val devDeps = node.dependencies.filter { depDirectives[it.key]?.devDependency == true }.toSet() val mainDeps = node.dependencies.toSet() - devDeps return setOf( diff --git a/plugins/package-managers/bazel/src/main/kotlin/StarlarkParser.kt b/plugins/package-managers/bazel/src/main/kotlin/StarlarkParser.kt index f1b14384715ae..b76bb98c7d0a6 100644 --- a/plugins/package-managers/bazel/src/main/kotlin/StarlarkParser.kt +++ b/plugins/package-managers/bazel/src/main/kotlin/StarlarkParser.kt @@ -200,7 +200,7 @@ internal class Parser(input: String) { return BazelDepDirective( name = params["name"] ?: throw IllegalArgumentException("Missing name in 'bazel_dep' directive"), version = params["version"] ?: throw IllegalArgumentException("Missing version in 'bazel_dep' directive"), - devDependency = params["dev_dependency"]?.toBoolean() ?: false + devDependency = params["dev_dependency"]?.toBoolean() == true ) } diff --git a/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt b/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt index 363755fcef659..b4dd4a963b134 100644 --- a/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt +++ b/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt @@ -136,7 +136,7 @@ class Cargo( PATH_DEPENDENCY_REGEX.matchEntire(id)?.groups?.get(1)?.let { match -> val packageDir = File(match.value) packageDir.startsWith(analysisRoot) - } ?: false + } == true private fun buildDependencyTree( name: String, diff --git a/plugins/package-managers/conan/src/main/kotlin/Conan.kt b/plugins/package-managers/conan/src/main/kotlin/Conan.kt index e66ec1df16c19..2fe9c9dc8ae37 100644 --- a/plugins/package-managers/conan/src/main/kotlin/Conan.kt +++ b/plugins/package-managers/conan/src/main/kotlin/Conan.kt @@ -154,7 +154,7 @@ class Conan( // TODO: Support lockfiles which are located in a different directory than the definition file. val lockfileName = options[OPTION_LOCKFILE_NAME] - requireLockfile(workingDir) { lockfileName?.let { hasLockfile(workingDir.resolve(it).path) } ?: false } + requireLockfile(workingDir) { lockfileName?.let { hasLockfile(workingDir.resolve(it).path) } == true } val jsonFile = createOrtTempDir().resolve("info.json") if (lockfileName != null) { diff --git a/plugins/package-managers/gradle-plugin/src/main/kotlin/OrtModelBuilder.kt b/plugins/package-managers/gradle-plugin/src/main/kotlin/OrtModelBuilder.kt index e8a5f770ad6b3..cbf0c9cd477a7 100644 --- a/plugins/package-managers/gradle-plugin/src/main/kotlin/OrtModelBuilder.kt +++ b/plugins/package-managers/gradle-plugin/src/main/kotlin/OrtModelBuilder.kt @@ -198,7 +198,13 @@ internal class OrtModelBuilder : ToolingModelBuilder { null } - val modelBuildingResult = poms.getValue(id.toString()) + val modelBuildingResult = poms[id.toString()] + if (modelBuildingResult == null && id !in visitedDependencies) { + val message = "No POM found for $id." + logger.warn(message) + warnings += message + } + val dependencies = if (id in visitedDependencies) { // Cut the graph on cyclic dependencies. emptyList() @@ -212,18 +218,20 @@ internal class OrtModelBuilder : ToolingModelBuilder { artifactId = id.module, version = id.version, classifier = "", - extension = modelBuildingResult.effectiveModel.packaging, + extension = modelBuildingResult?.effectiveModel?.packaging.orEmpty(), dependencies = dependencies, error = null, warning = null, pomFile = pomFile, - mavenModel = OrtMavenModelImpl( - licenses = modelBuildingResult.effectiveModel.collectLicenses(), - authors = modelBuildingResult.effectiveModel.collectAuthors(), - description = modelBuildingResult.effectiveModel.description.orEmpty(), - homepageUrl = modelBuildingResult.effectiveModel.url.orEmpty(), - vcs = modelBuildingResult.getVcsModel() - ), + mavenModel = modelBuildingResult?.run { + OrtMavenModelImpl( + licenses = effectiveModel.collectLicenses(), + authors = effectiveModel.collectAuthors(), + description = effectiveModel.description.orEmpty(), + homepageUrl = effectiveModel.url.orEmpty(), + vcs = getVcsModel() + ) + }, localPath = null ) } diff --git a/plugins/package-managers/pub/src/main/kotlin/utils/PubCacheReader.kt b/plugins/package-managers/pub/src/main/kotlin/utils/PubCacheReader.kt index 4c9ed26e26678..f54a4ffb1711b 100644 --- a/plugins/package-managers/pub/src/main/kotlin/utils/PubCacheReader.kt +++ b/plugins/package-managers/pub/src/main/kotlin/utils/PubCacheReader.kt @@ -71,7 +71,7 @@ internal class PubCacheReader { val url = description["url"].textValueOrEmpty() val resolvedRef = description["resolved-ref"].textValueOrEmpty() val resolvedPath = description["path"].textValueOrEmpty() - val isPathRelative = description["relative"]?.booleanValue() ?: false + val isPathRelative = description["relative"]?.booleanValue() == true if (type == "path" && resolvedPath.isNotEmpty()) { // For "path" packages, the path should be the absolute resolved path diff --git a/plugins/package-managers/python/src/funTest/assets/projects/external/example-python-flask-expected-output.yml b/plugins/package-managers/python/src/funTest/assets/projects/external/example-python-flask-expected-output.yml index 040ce8dacfcd0..ae51accba4aba 100644 --- a/plugins/package-managers/python/src/funTest/assets/projects/external/example-python-flask-expected-output.yml +++ b/plugins/package-managers/python/src/funTest/assets/projects/external/example-python-flask-expected-output.yml @@ -25,7 +25,7 @@ project: - id: "PyPI::jinja2:2.8.1" dependencies: - id: "PyPI::markupsafe:2.1.5" - - id: "PyPI::werkzeug:3.0.1" + - id: "PyPI::werkzeug:3.0.2" dependencies: - id: "PyPI::markupsafe:2.1.5" - id: "PyPI::gunicorn:19.6.0" @@ -227,8 +227,8 @@ packages: url: "https://github.com/pallets/markupsafe.git" revision: "" path: "" -- id: "PyPI::werkzeug:3.0.1" - purl: "pkg:pypi/werkzeug@3.0.1" +- id: "PyPI::werkzeug:3.0.2" + purl: "pkg:pypi/werkzeug@3.0.2" declared_licenses: - "BSD License" declared_licenses_processed: @@ -237,14 +237,14 @@ packages: description: "The comprehensive WSGI web application library." homepage_url: "" binary_artifact: - url: "https://files.pythonhosted.org/packages/c3/fc/254c3e9b5feb89ff5b9076a23218dafbc99c96ac5941e900b71206e6313b/werkzeug-3.0.1-py3-none-any.whl" + url: "https://files.pythonhosted.org/packages/e3/23/c9843d7550092ae7ad380611c238f44afef66f58f76c1dab7dcf313e4339/werkzeug-3.0.2-py3-none-any.whl" hash: - value: "90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10" + value: "3aac3f5da756f93030740bc235d3e09449efcf65f2f55e3602e1d851b8f48795" algorithm: "SHA-256" source_artifact: - url: "https://files.pythonhosted.org/packages/0d/cc/ff1904eb5eb4b455e442834dabf9427331ac0fa02853bf83db817a7dd53d/werkzeug-3.0.1.tar.gz" + url: "https://files.pythonhosted.org/packages/0f/84/00f7193d7bd88ced26cd5f868903e431054424610dc7c041bbe87d2a4d66/werkzeug-3.0.2.tar.gz" hash: - value: "507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc" + value: "e39b645a6ac92822588e7b39a692e7828724ceae0b0d702ef96701f90e70128d" algorithm: "SHA-256" vcs: type: "" diff --git a/plugins/reporters/fossid/src/main/kotlin/FossIdSnippetReporter.kt b/plugins/reporters/fossid/src/main/kotlin/FossIdSnippetReporter.kt index 43d96a40f012d..55bb2facb9d20 100644 --- a/plugins/reporters/fossid/src/main/kotlin/FossIdSnippetReporter.kt +++ b/plugins/reporters/fossid/src/main/kotlin/FossIdSnippetReporter.kt @@ -37,7 +37,7 @@ class FossIdSnippetReporter : Reporter by delegateReporter { override val type = "FossIdSnippet" override fun generateReport(input: ReporterInput, outputDir: File, config: PluginConfiguration): List { - val hasFossIdResults = input.ortResult.scanner?.scanResults?.any { it.scanner.name == "FossId" } ?: false + val hasFossIdResults = input.ortResult.scanner?.scanResults?.any { it.scanner.name == "FossId" } == true require(hasFossIdResults) { "No FossID scan results have been found." } val extendedOptions = config.copy( diff --git a/plugins/reporters/freemarker/src/main/kotlin/FreemarkerTemplateProcessor.kt b/plugins/reporters/freemarker/src/main/kotlin/FreemarkerTemplateProcessor.kt index 3b4f8b6d347f4..6d63e174effd4 100644 --- a/plugins/reporters/freemarker/src/main/kotlin/FreemarkerTemplateProcessor.kt +++ b/plugins/reporters/freemarker/src/main/kotlin/FreemarkerTemplateProcessor.kt @@ -220,7 +220,7 @@ class FreemarkerTemplateProcessor( @Suppress("UNUSED") // This function is used in the templates. fun filterForCategory(licenses: Collection, category: String): List = licenses.filter { resolvedLicense -> - input.licenseClassifications[resolvedLicense.license]?.contains(category) ?: true + input.licenseClassifications[resolvedLicense.license]?.contains(category) != false } /** @@ -285,7 +285,7 @@ class FreemarkerTemplateProcessor( @Suppress("UNUSED") // This function is used in the templates. fun hasUnresolvedRuleViolations(threshold: Severity = input.ortConfig.severeRuleViolationThreshold) = input.ortResult.getRuleViolations(omitResolved = true, minSeverity = threshold).any { violation -> - violation.pkg?.let { input.ortResult.isExcluded(it) } ?: false + violation.pkg?.let { input.ortResult.isExcluded(it) } == true } /** @@ -343,7 +343,7 @@ class FreemarkerTemplateProcessor( capability = capability, minSeverity = severity ) - )?.isNotEmpty() ?: false + )?.isNotEmpty() == true /** * Return the subset of the available advisor results produced by an advisor with the given [capability] that diff --git a/plugins/scanners/fossid/src/main/kotlin/FossId.kt b/plugins/scanners/fossid/src/main/kotlin/FossId.kt index 0339317a49e24..2dbc2b51be0ea 100644 --- a/plugins/scanners/fossid/src/main/kotlin/FossId.kt +++ b/plugins/scanners/fossid/src/main/kotlin/FossId.kt @@ -428,7 +428,7 @@ class FossId internal constructor( defaultBranch: String? = null ): List { val scans = filter { - val isArchived = it.isArchived ?: false + val isArchived = it.isArchived == true // The scans in the server contain the url with the credentials, so we have to remove it for the // comparison. If we don't, the scans won't be matched if the password changes! val urlWithoutCredentials = it.gitRepoUrl?.replaceCredentialsInUri() @@ -441,7 +441,7 @@ class FossId internal constructor( } scans.filter { scan -> - defaultBranch?.let { scan.comment == defaultBranch } ?: false + defaultBranch?.let { scan.comment == defaultBranch } == true }.ifEmpty { logger.warn { "No recent default branch scan found. Falling back to old behavior." } diff --git a/plugins/scanners/fossid/src/main/kotlin/FossIdConfig.kt b/plugins/scanners/fossid/src/main/kotlin/FossIdConfig.kt index c202ff9dc8ea9..f5f0ae632e947 100644 --- a/plugins/scanners/fossid/src/main/kotlin/FossIdConfig.kt +++ b/plugins/scanners/fossid/src/main/kotlin/FossIdConfig.kt @@ -172,18 +172,18 @@ data class FossIdConfig( val apiKey = secrets[API_KEY_PROPERTY] ?: throw IllegalArgumentException("No FossID API Key configuration found.") - val waitForResult = options[WAIT_FOR_RESULT_PROPERTY]?.toBoolean() ?: true + val waitForResult = options[WAIT_FOR_RESULT_PROPERTY]?.toBoolean() != false - val keepFailedScans = options[KEEP_FAILED_SCANS_PROPERTY]?.toBoolean() ?: false - val deltaScans = options[DELTA_SCAN_PROPERTY]?.toBoolean() ?: false + val keepFailedScans = options[KEEP_FAILED_SCANS_PROPERTY]?.toBoolean() == true + val deltaScans = options[DELTA_SCAN_PROPERTY]?.toBoolean() == true val deltaScanLimit = options[DELTA_SCAN_LIMIT_PROPERTY]?.toInt() ?: Int.MAX_VALUE - val detectLicenseDeclarations = options[DETECT_LICENSE_DECLARATIONS_PROPERTY]?.toBoolean() ?: false - val detectCopyrightStatements = options[DETECT_COPYRIGHT_STATEMENTS_PROPERTY]?.toBoolean() ?: false + val detectLicenseDeclarations = options[DETECT_LICENSE_DECLARATIONS_PROPERTY]?.toBoolean() == true + val detectCopyrightStatements = options[DETECT_COPYRIGHT_STATEMENTS_PROPERTY]?.toBoolean() == true val timeout = options[TIMEOUT]?.toInt() ?: DEFAULT_TIMEOUT - val fetchSnippetMatchedLines = options[FETCH_SNIPPET_MATCHED_LINES]?.toBoolean() ?: false + val fetchSnippetMatchedLines = options[FETCH_SNIPPET_MATCHED_LINES]?.toBoolean() == true require(deltaScanLimit > 0) { "deltaScanLimit must be > 0, current value is $deltaScanLimit." diff --git a/plugins/scanners/scancode/src/funTest/kotlin/ScanCodeScannerFunTest.kt b/plugins/scanners/scancode/src/funTest/kotlin/ScanCodeScannerFunTest.kt index a1f4e74f260a0..d63ab30bf0d8a 100644 --- a/plugins/scanners/scancode/src/funTest/kotlin/ScanCodeScannerFunTest.kt +++ b/plugins/scanners/scancode/src/funTest/kotlin/ScanCodeScannerFunTest.kt @@ -19,6 +19,7 @@ package org.ossreviewtoolkit.plugins.scanners.scancode +import io.kotest.engine.spec.tempdir import io.kotest.matchers.should import io.kotest.matchers.shouldBe import io.kotest.matchers.string.endWith @@ -28,7 +29,6 @@ import org.ossreviewtoolkit.model.LicenseFinding import org.ossreviewtoolkit.model.TextLocation import org.ossreviewtoolkit.scanner.AbstractPathScannerWrapperFunTest import org.ossreviewtoolkit.scanner.ScannerWrapperConfig -import org.ossreviewtoolkit.utils.ort.createOrtTempDir import org.ossreviewtoolkit.utils.spdx.getLicenseText import org.ossreviewtoolkit.utils.test.ExpensiveTag @@ -36,15 +36,13 @@ class ScanCodeScannerFunTest : AbstractPathScannerWrapperFunTest(setOf(Expensive override val scanner = ScanCode("ScanCode", ScanCodeConfig.DEFAULT, ScannerWrapperConfig.EMPTY) override val expectedFileLicenses = listOf( - LicenseFinding("Apache-2.0", TextLocation("LICENSE", 1, 187), 100.0f), - LicenseFinding("Apache-2.0", TextLocation("LICENSE", 191, 201), 100.0f) + LicenseFinding("Apache-2.0", TextLocation("LICENSE", 1, 201), 100.0f) ) override val expectedDirectoryLicenses = listOf( - LicenseFinding("Apache-2.0", TextLocation("COPYING", 1, 201), 99.18f), - LicenseFinding("Apache-2.0", TextLocation("LICENCE", 1, 201), 99.18f), - LicenseFinding("Apache-2.0", TextLocation("LICENSE", 1, 187), 100.0f), - LicenseFinding("Apache-2.0", TextLocation("LICENSE", 191, 201), 100.0f) + LicenseFinding("Apache-2.0", TextLocation("COPYING", 1, 201), 99.43f), + LicenseFinding("Apache-2.0", TextLocation("LICENCE", 1, 201), 99.43f), + LicenseFinding("Apache-2.0", TextLocation("LICENSE", 1, 201), 100.0f) ) init { @@ -66,7 +64,7 @@ class ScanCodeScannerFunTest : AbstractPathScannerWrapperFunTest(setOf(Expensive val id = "LicenseRef-scancode-here-proprietary" val text = "x\ny\n" - val outputDir = createOrtTempDir().apply { resolve(id).writeText(text) } + val outputDir = tempdir().apply { resolve(id).writeText(text) } getLicenseText(id, true, listOf(outputDir)) shouldBe getLicenseText(id, true) } diff --git a/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModel.kt b/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModel.kt index a926a066fad6c..d73f286aba0bb 100644 --- a/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModel.kt +++ b/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModel.kt @@ -139,6 +139,7 @@ sealed interface LicenseEntry { val startLine: Int val endLine: Int val score: Float + val matchedText: String? @Serializable data class Version1( @@ -147,7 +148,8 @@ sealed interface LicenseEntry { val spdxLicenseKey: String? = null, // This might be explicitly set to null in JSON. override val startLine: Int, override val endLine: Int, - val matchedRule: LicenseRule + val matchedRule: LicenseRule, + override val matchedText: String? = null ) : LicenseEntry { override val licenseExpression = matchedRule.licenseExpression } @@ -157,7 +159,10 @@ sealed interface LicenseEntry { override val score: Float, override val startLine: Int, override val endLine: Int, - override val licenseExpression: String + override val licenseExpression: String, + val spdxLicenseExpression: String? = null, // This might be missing in JSON. + val fromFile: String? = null, // This might be missing in JSON. + override val matchedText: String? = null ) : LicenseEntry } diff --git a/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModelMapper.kt b/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModelMapper.kt index d4206e35eb3fe..d064c8fa7c009 100644 --- a/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModelMapper.kt +++ b/plugins/scanners/scancode/src/main/kotlin/ScanCodeResultModelMapper.kt @@ -64,6 +64,7 @@ fun ScanCodeResult.toScanSummary(preferFileLicense: Boolean = false): ScanSummar val issues = mutableListOf() val header = headers.single() + val inputName = header.options.input.first().substringAfterLast('/') val outputFormatVersion = header.outputFormatVersion?.let { Semver(it) } if (outputFormatVersion != null && outputFormatVersion.major > MAX_SUPPORTED_OUTPUT_FORMAT_MAJOR_VERSION) { @@ -82,9 +83,16 @@ fun ScanCodeResult.toScanSummary(preferFileLicense: Boolean = false): ScanSummar ?: files.flatMap { it.scanCodeKeyToSpdxIdMappings }.toMap() filesOfTypeFile.forEach { file -> + val licensesWithoutReferences = file.licenses.filter { + // Note that "fromFile" contains the name of the input directory, see + // https://github.com/nexB/scancode-toolkit/issues/3712. + it !is LicenseEntry.Version3 || it.fromFile == null || it.fromFile == "$inputName/${file.path}" + || it.fromFile == inputName // Input is a single file. + } + // ScanCode creates separate license entries for each license in an expression. Deduplicate these by grouping by // the same expression. - val licenses = file.licenses.groupBy { + val licenses = licensesWithoutReferences.groupBy { LicenseMatch(it.licenseExpression, it.startLine, it.endLine, it.score) }.map { // Arbitrarily take the first of the duplicate license entries. @@ -104,7 +112,12 @@ fun ScanCodeResult.toScanSummary(preferFileLicense: Boolean = false): ScanSummar } else { licenses.mapTo(licenseFindings) { license -> // ScanCode uses its own license keys as identifiers in license expressions. - val spdxLicenseExpression = license.licenseExpression.mapLicense(scanCodeKeyToSpdxIdMappings) + val spdxLicenseExpression = when { + license is LicenseEntry.Version3 && license.spdxLicenseExpression != null -> { + license.spdxLicenseExpression + } + else -> license.licenseExpression.mapLicense(scanCodeKeyToSpdxIdMappings) + } LicenseFinding( license = spdxLicenseExpression, diff --git a/plugins/scanners/scancode/src/test/assets/scancode-32.1.0_from_file-reference.json b/plugins/scanners/scancode/src/test/assets/scancode-32.1.0_from_file-reference.json new file mode 100644 index 0000000000000..a0136d29869b4 --- /dev/null +++ b/plugins/scanners/scancode/src/test/assets/scancode-32.1.0_from_file-reference.json @@ -0,0 +1,585 @@ +{ + "headers": [ + { + "tool_name": "scancode-toolkit", + "tool_version": "32.1.0", + "options": { + "input": [ + "/home/sebastian/Downloads/files" + ], + "--copyright": true, + "--info": true, + "--json-pp": "scancode-result.json", + "--license": true, + "--strip-root": true, + "--timeout": "300.0" + }, + "notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "start_timestamp": "2024-03-28T110041.376392", + "end_timestamp": "2024-03-28T110044.147354", + "output_format_version": "3.1.0", + "duration": 2.770972490310669, + "message": null, + "errors": [], + "warnings": [], + "extra_data": { + "system_environment": { + "operating_system": "linux", + "cpu_architecture": "64", + "platform": "Linux-6.7.10-200.fc39.x86_64-x86_64-with-glibc2.38", + "platform_version": "#1 SMP PREEMPT_DYNAMIC Mon Mar 18 18:56:52 UTC 2024", + "python_version": "3.12.2 (main, Feb 21 2024, 00:00:00) [GCC 13.2.1 20231205 (Red Hat 13.2.1-6)]" + }, + "spdx_license_list_version": "3.23", + "files_count": 2 + } + } + ], + "license_detections": [ + { + "identifier": "lgpl_2_1-9de8e5f7-3171-8985-b4d6-a1ffddf63f3a", + "license_expression": "lgpl-2.1", + "license_expression_spdx": "LGPL-2.1-only", + "detection_count": 1, + "reference_matches": [ + { + "license_expression": "lgpl-2.1", + "license_expression_spdx": "LGPL-2.1-only", + "from_file": "files/COPYING.LGPLv2.1", + "start_line": 1, + "end_line": 502, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 4288, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1.LICENSE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/lgpl-2.1.LICENSE" + } + ] + }, + { + "identifier": "public_domain_and_lgpl_2_1_plus_and_gpl_2_0_plus_and__public_domain_and_gpl_2_0_plus_and_gpl_3_0_plus__and__other_permissive_and_other_copyleft__and_public_domain_disclaimer_and_lgpl_2_1-4b11d70c-b401-ad7e-7036-9e3ec1ab19a9", + "license_expression": "public-domain AND lgpl-2.1-plus AND gpl-2.0-plus AND (public-domain AND gpl-2.0-plus AND gpl-3.0-plus) AND (other-permissive AND other-copyleft) AND public-domain-disclaimer AND lgpl-2.1", + "license_expression_spdx": "LicenseRef-scancode-public-domain AND LGPL-2.1-or-later AND GPL-2.0-or-later AND (LicenseRef-scancode-public-domain AND GPL-2.0-or-later AND GPL-3.0-or-later) AND (LicenseRef-scancode-other-permissive AND LicenseRef-scancode-other-copyleft) AND LicenseRef-scancode-public-domain-disclaimer AND LGPL-2.1-only", + "detection_count": 1, + "reference_matches": [ + { + "license_expression": "public-domain", + "license_expression_spdx": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 9, + "end_line": 9, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_285.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_285.RULE" + }, + { + "license_expression": "public-domain", + "license_expression_spdx": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 11, + "end_line": 12, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 8, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_431.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_431.RULE" + }, + { + "license_expression": "lgpl-2.1-plus", + "license_expression_spdx": "LGPL-2.1-or-later", + "from_file": "files/COPYING", + "start_line": 13, + "end_line": 14, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 9, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1-plus_393.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/lgpl-2.1-plus_393.RULE" + }, + { + "license_expression": "gpl-2.0-plus", + "license_expression_spdx": "GPL-2.0-or-later", + "from_file": "files/COPYING", + "start_line": 17, + "end_line": 18, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 9, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "gpl-2.0-plus_991.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/gpl-2.0-plus_991.RULE" + }, + { + "license_expression": "public-domain", + "license_expression_spdx": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 21, + "end_line": 22, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 10, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_428.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_428.RULE" + }, + { + "license_expression": "public-domain", + "license_expression_spdx": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 24, + "end_line": 24, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 7, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_429.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_429.RULE" + }, + { + "license_expression": "public-domain AND gpl-2.0-plus AND gpl-3.0-plus", + "license_expression_spdx": "LicenseRef-scancode-public-domain AND GPL-2.0-or-later AND GPL-3.0-or-later", + "from_file": "files/COPYING", + "start_line": 26, + "end_line": 27, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 17, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_and_gpl-2.0-plus_and_gpl-3.0-plus_1.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_and_gpl-2.0-plus_and_gpl-3.0-plus_1.RULE" + }, + { + "license_expression": "public-domain", + "license_expression_spdx": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 31, + "end_line": 31, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_305.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_305.RULE" + }, + { + "license_expression": "public-domain", + "license_expression_spdx": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 33, + "end_line": 33, + "matcher": "2-aho", + "score": 70.0, + "matched_length": 2, + "match_coverage": 100.0, + "rule_relevance": 70, + "rule_identifier": "public-domain_bare_words.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_bare_words.RULE" + }, + { + "license_expression": "other-permissive AND other-copyleft", + "license_expression_spdx": "LicenseRef-scancode-other-permissive AND LicenseRef-scancode-other-copyleft", + "from_file": "files/COPYING", + "start_line": 33, + "end_line": 34, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 8, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "other-permissive_and_other-copyleft_4.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/other-permissive_and_other-copyleft_4.RULE" + }, + { + "license_expression": "public-domain-disclaimer", + "license_expression_spdx": "LicenseRef-scancode-public-domain-disclaimer", + "from_file": "files/COPYING", + "start_line": 36, + "end_line": 50, + "matcher": "3-seq", + "score": 96.69, + "matched_length": 117, + "match_coverage": 96.69, + "rule_relevance": 100, + "rule_identifier": "public-domain-disclaimer_72.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain-disclaimer_72.RULE" + }, + { + "license_expression": "lgpl-2.1 AND gpl-2.0 AND gpl-3.0", + "license_expression_spdx": "LGPL-2.1-only AND GPL-2.0-only AND GPL-3.0-only", + "from_file": "files/COPYING", + "start_line": 52, + "end_line": 55, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 37, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1_and_gpl-2.0_and_gpl-3.0_3.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/lgpl-2.1_and_gpl-2.0_and_gpl-3.0_3.RULE" + }, + { + "license_expression": "public-domain", + "license_expression_spdx": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 59, + "end_line": 59, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 12, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_427.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_427.RULE" + }, + { + "license_expression": "lgpl-2.1", + "license_expression_spdx": "LGPL-2.1-only", + "from_file": "files/COPYING.LGPLv2.1", + "start_line": 1, + "end_line": 502, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 4288, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1.LICENSE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/lgpl-2.1.LICENSE" + } + ] + } + ], + "files": [ + { + "path": "COPYING", + "type": "file", + "name": "COPYING", + "base_name": "COPYING", + "extension": "", + "size": 2775, + "date": "2024-01-29", + "sha1": "66933e63e70616b43f1dc60340491f8e050eedfd", + "md5": "97d554a32881fee0aa283d96e47cb24a", + "sha256": "bcb02973ef6e87ea73d331b3a80df7748407f17efdb784b61b47e0e610d3bb5c", + "mime_type": "text/plain", + "file_type": "ASCII text", + "programming_language": null, + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "is_source": false, + "is_script": false, + "detected_license_expression": "public-domain AND lgpl-2.1-plus AND gpl-2.0-plus AND (public-domain AND gpl-2.0-plus AND gpl-3.0-plus) AND (other-permissive AND other-copyleft) AND public-domain-disclaimer AND lgpl-2.1", + "detected_license_expression_spdx": "LicenseRef-scancode-public-domain AND LGPL-2.1-or-later AND GPL-2.0-or-later AND (LicenseRef-scancode-public-domain AND GPL-2.0-or-later AND GPL-3.0-or-later) AND (LicenseRef-scancode-other-permissive AND LicenseRef-scancode-other-copyleft) AND LicenseRef-scancode-public-domain-disclaimer AND LGPL-2.1-only", + "license_detections": [ + { + "license_expression": "public-domain AND lgpl-2.1-plus AND gpl-2.0-plus AND (public-domain AND gpl-2.0-plus AND gpl-3.0-plus) AND (other-permissive AND other-copyleft) AND public-domain-disclaimer AND lgpl-2.1", + "license_expression_spdx": "LicenseRef-scancode-public-domain AND LGPL-2.1-or-later AND GPL-2.0-or-later AND (LicenseRef-scancode-public-domain AND GPL-2.0-or-later AND GPL-3.0-or-later) AND (LicenseRef-scancode-other-permissive AND LicenseRef-scancode-other-copyleft) AND LicenseRef-scancode-public-domain-disclaimer AND LGPL-2.1-only", + "matches": [ + { + "license_expression": "public-domain", + "spdx_license_expression": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 9, + "end_line": 9, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_285.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_285.RULE" + }, + { + "license_expression": "public-domain", + "spdx_license_expression": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 11, + "end_line": 12, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 8, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_431.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_431.RULE" + }, + { + "license_expression": "lgpl-2.1-plus", + "spdx_license_expression": "LGPL-2.1-or-later", + "from_file": "files/COPYING", + "start_line": 13, + "end_line": 14, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 9, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1-plus_393.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/lgpl-2.1-plus_393.RULE" + }, + { + "license_expression": "gpl-2.0-plus", + "spdx_license_expression": "GPL-2.0-or-later", + "from_file": "files/COPYING", + "start_line": 17, + "end_line": 18, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 9, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "gpl-2.0-plus_991.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/gpl-2.0-plus_991.RULE" + }, + { + "license_expression": "public-domain", + "spdx_license_expression": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 21, + "end_line": 22, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 10, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_428.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_428.RULE" + }, + { + "license_expression": "public-domain", + "spdx_license_expression": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 24, + "end_line": 24, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 7, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_429.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_429.RULE" + }, + { + "license_expression": "public-domain AND gpl-2.0-plus AND gpl-3.0-plus", + "spdx_license_expression": "LicenseRef-scancode-public-domain AND GPL-2.0-or-later AND GPL-3.0-or-later", + "from_file": "files/COPYING", + "start_line": 26, + "end_line": 27, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 17, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_and_gpl-2.0-plus_and_gpl-3.0-plus_1.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_and_gpl-2.0-plus_and_gpl-3.0-plus_1.RULE" + }, + { + "license_expression": "public-domain", + "spdx_license_expression": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 31, + "end_line": 31, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_305.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_305.RULE" + }, + { + "license_expression": "public-domain", + "spdx_license_expression": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 33, + "end_line": 33, + "matcher": "2-aho", + "score": 70.0, + "matched_length": 2, + "match_coverage": 100.0, + "rule_relevance": 70, + "rule_identifier": "public-domain_bare_words.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_bare_words.RULE" + }, + { + "license_expression": "other-permissive AND other-copyleft", + "spdx_license_expression": "LicenseRef-scancode-other-permissive AND LicenseRef-scancode-other-copyleft", + "from_file": "files/COPYING", + "start_line": 33, + "end_line": 34, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 8, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "other-permissive_and_other-copyleft_4.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/other-permissive_and_other-copyleft_4.RULE" + }, + { + "license_expression": "public-domain-disclaimer", + "spdx_license_expression": "LicenseRef-scancode-public-domain-disclaimer", + "from_file": "files/COPYING", + "start_line": 36, + "end_line": 50, + "matcher": "3-seq", + "score": 96.69, + "matched_length": 117, + "match_coverage": 96.69, + "rule_relevance": 100, + "rule_identifier": "public-domain-disclaimer_72.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain-disclaimer_72.RULE" + }, + { + "license_expression": "lgpl-2.1 AND gpl-2.0 AND gpl-3.0", + "spdx_license_expression": "LGPL-2.1-only AND GPL-2.0-only AND GPL-3.0-only", + "from_file": "files/COPYING", + "start_line": 52, + "end_line": 55, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 37, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1_and_gpl-2.0_and_gpl-3.0_3.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/lgpl-2.1_and_gpl-2.0_and_gpl-3.0_3.RULE" + }, + { + "license_expression": "public-domain", + "spdx_license_expression": "LicenseRef-scancode-public-domain", + "from_file": "files/COPYING", + "start_line": 59, + "end_line": 59, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 12, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "public-domain_427.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/public-domain_427.RULE" + }, + { + "license_expression": "lgpl-2.1", + "spdx_license_expression": "LGPL-2.1-only", + "from_file": "files/COPYING.LGPLv2.1", + "start_line": 1, + "end_line": 502, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 4288, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1.LICENSE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/lgpl-2.1.LICENSE" + } + ], + "identifier": "public_domain_and_lgpl_2_1_plus_and_gpl_2_0_plus_and__public_domain_and_gpl_2_0_plus_and_gpl_3_0_plus__and__other_permissive_and_other_copyleft__and_public_domain_disclaimer_and_lgpl_2_1-4b11d70c-b401-ad7e-7036-9e3ec1ab19a9", + "detection_log": [ + "unknown-reference-to-local-file" + ] + } + ], + "license_clues": [], + "percentage_of_license_text": 58.99, + "copyrights": [], + "holders": [], + "authors": [], + "files_count": 0, + "dirs_count": 0, + "size_count": 0, + "scan_errors": [] + }, + { + "path": "COPYING.LGPLv2.1", + "type": "file", + "name": "COPYING.LGPLv2.1", + "base_name": "COPYING.LGPLv2", + "extension": ".1", + "size": 26530, + "date": "2024-01-29", + "sha1": "01a6b4bf79aca9b556822601186afab86e8c4fbf", + "md5": "4fbd65380cdd255951079008b364516c", + "sha256": "dc626520dcd53a22f727af3ee42c770e56c97a64fe3adb063799d8ab032fe551", + "mime_type": "text/plain", + "file_type": "ASCII text", + "programming_language": null, + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "is_source": false, + "is_script": false, + "detected_license_expression": "lgpl-2.1", + "detected_license_expression_spdx": "LGPL-2.1-only", + "license_detections": [ + { + "license_expression": "lgpl-2.1", + "license_expression_spdx": "LGPL-2.1-only", + "matches": [ + { + "license_expression": "lgpl-2.1", + "spdx_license_expression": "LGPL-2.1-only", + "from_file": "files/COPYING.LGPLv2.1", + "start_line": 1, + "end_line": 502, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 4288, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "lgpl-2.1.LICENSE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/lgpl-2.1.LICENSE" + } + ], + "identifier": "lgpl_2_1-9de8e5f7-3171-8985-b4d6-a1ffddf63f3a" + } + ], + "license_clues": [], + "percentage_of_license_text": 100.0, + "copyrights": [ + { + "copyright": "Copyright (c) 1991, 1999 Free Software Foundation, Inc.", + "start_line": 4, + "end_line": 4 + }, + { + "copyright": "copyrighted by the Free Software Foundation", + "start_line": 429, + "end_line": 429 + } + ], + "holders": [ + { + "holder": "Free Software Foundation, Inc.", + "start_line": 4, + "end_line": 4 + }, + { + "holder": "the Free Software Foundation", + "start_line": 429, + "end_line": 429 + } + ], + "authors": [], + "files_count": 0, + "dirs_count": 0, + "size_count": 0, + "scan_errors": [] + } + ] +} \ No newline at end of file diff --git a/plugins/scanners/scancode/src/test/kotlin/ScanCodeResultParserTest.kt b/plugins/scanners/scancode/src/test/kotlin/ScanCodeResultParserTest.kt index 45e08d4d4b3e4..e55c939b58e0e 100644 --- a/plugins/scanners/scancode/src/test/kotlin/ScanCodeResultParserTest.kt +++ b/plugins/scanners/scancode/src/test/kotlin/ScanCodeResultParserTest.kt @@ -103,6 +103,87 @@ class ScanCodeResultParserTest : FreeSpec({ } } + "for ScanCode 32.1.0 should" - { + "contain findings that stem from referenced files" { + val resultFile = getAssetFile("scancode-32.1.0_from_file-reference.json") + + val summary = parseResult(resultFile).toScanSummary() + + summary.licenseFindings should containExactlyInAnyOrder( + LicenseFinding( + license = "LicenseRef-scancode-public-domain", + location = TextLocation("COPYING", 9), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain", + location = TextLocation("COPYING", 11, 12), + score = 100.0f + ), + LicenseFinding( + license = "LGPL-2.1-or-later", + location = TextLocation("COPYING", 13, 14), + score = 100.0f + ), + LicenseFinding( + license = "GPL-2.0-or-later", + location = TextLocation("COPYING", 17, 18), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain", + location = TextLocation("COPYING", 21, 22), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain", + location = TextLocation("COPYING", 24), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain AND GPL-2.0-or-later AND GPL-3.0-or-later", + location = TextLocation("COPYING", 26, 27), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain", + location = TextLocation("COPYING", 31), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain", + location = TextLocation("COPYING", 33), + score = 70.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-other-permissive AND LicenseRef-scancode-other-copyleft", + location = TextLocation("COPYING", 33, 34), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain-disclaimer", + location = TextLocation("COPYING", 36, 50), + score = 96.69f + ), + LicenseFinding( + license = "LGPL-2.1-only AND GPL-2.0-only AND GPL-3.0-only", + location = TextLocation("COPYING", 52, 55), + score = 100.0f + ), + LicenseFinding( + license = "LicenseRef-scancode-public-domain", + location = TextLocation("COPYING", 59), + score = 100.0f + ), + LicenseFinding( + license = "LGPL-2.1-only", + location = TextLocation("COPYING.LGPLv2.1", 1, 502), + score = 100.0f + ) + ) + } + } + for (version in 1..MAX_SUPPORTED_OUTPUT_FORMAT_MAJOR_VERSION) { val resultFile = getAssetFile("scancode-output-format-$version.0.0_mime-types-2.1.18.json") val summary = parseResult(resultFile).toScanSummary() diff --git a/scanner/src/main/kotlin/ScanController.kt b/scanner/src/main/kotlin/ScanController.kt index 7c71f4cbb4b5f..e5d7031caf25c 100644 --- a/scanner/src/main/kotlin/ScanController.kt +++ b/scanner/src/main/kotlin/ScanController.kt @@ -304,7 +304,7 @@ internal class ScanController( * Return true if [ScanResult]s for the complete [NestedProvenance] of the package are available. */ fun hasCompleteScanResult(scanner: ScannerWrapper, pkg: Package): Boolean = - getNestedProvenance(pkg.id)?.allProvenances?.all { provenance -> hasScanResult(scanner, provenance) } ?: false + getNestedProvenance(pkg.id)?.allProvenances?.all { provenance -> hasScanResult(scanner, provenance) } == true /** * Return true if a [ScanResult] for the provided [scanner] and [provenance] is available. diff --git a/scanner/src/test/kotlin/utils/FileListResolverTest.kt b/scanner/src/test/kotlin/utils/FileListResolverTest.kt index 30ebfd911ae5f..430ac89f2c75a 100644 --- a/scanner/src/test/kotlin/utils/FileListResolverTest.kt +++ b/scanner/src/test/kotlin/utils/FileListResolverTest.kt @@ -37,7 +37,6 @@ import org.ossreviewtoolkit.model.RemoteArtifact import org.ossreviewtoolkit.model.toYaml import org.ossreviewtoolkit.model.utils.FileProvenanceFileStorage import org.ossreviewtoolkit.model.utils.ProvenanceFileStorage -import org.ossreviewtoolkit.utils.ort.createOrtTempDir import org.ossreviewtoolkit.utils.ort.storage.LocalFileStorage class FileListResolverTest : StringSpec({ @@ -81,7 +80,7 @@ class FileListResolverTest : StringSpec({ }) private fun Spec.createTempDirWithFiles(vararg paths: String) = - createOrtTempDir().apply { + tempdir().apply { paths.forEachIndexed { index, path -> resolve(path).apply { parentFile.mkdirs() diff --git a/utils/common/src/main/kotlin/Extensions.kt b/utils/common/src/main/kotlin/Extensions.kt index 56e5d12a83cfa..20ebc2e3f4e58 100644 --- a/utils/common/src/main/kotlin/Extensions.kt +++ b/utils/common/src/main/kotlin/Extensions.kt @@ -352,12 +352,12 @@ fun String.fileSystemEncode() = /** * Return true if the string represents a false value, otherwise return false. */ -fun String?.isFalse() = this?.toBoolean()?.not() ?: false +fun String?.isFalse() = this?.toBoolean()?.not() == true /** * Return true if the string represents a true value, otherwise return false. */ -fun String?.isTrue() = this?.toBoolean() ?: false +fun String?.isTrue() = this?.toBoolean() == true /** * True if the string is a valid [URI], false otherwise. diff --git a/utils/ort/src/main/kotlin/Utils.kt b/utils/ort/src/main/kotlin/Utils.kt index e227dca15fa63..c2ea223377885 100644 --- a/utils/ort/src/main/kotlin/Utils.kt +++ b/utils/ort/src/main/kotlin/Utils.kt @@ -79,7 +79,7 @@ fun filterVersionNames(version: String, names: List, project: String? = // for version "3.3.1" accept "3.3.1-npm-packages" but not "3.3.1.0". val hasIgnorableSuffixOnly = name.withoutPrefix(versionVariant.name)?.let { tail -> tail.firstOrNull() !in versionVariant.separators - } ?: false + } == true // Allow to ignore prefixes in names that are separated by something else than the current separator, e.g. // for version "0.10" accept "docutils-0.10" but not "1.0.10". @@ -97,7 +97,7 @@ fun filterVersionNames(version: String, names: List, project: String? = || (last in currentSeparators && (forelast == null || !forelast.isDigit())) // The prefix ends with 'v' and the forelast character is a separator. || (last == 'v' && (forelast == null || forelast in currentSeparators)) - } ?: false + } == true hasIgnorableSuffixOnly || hasIgnorablePrefixOnly }