Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2026 The ORT Project Copyright Holders <https://github.com/oss-review-toolkit/ort/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.ossreviewtoolkit.clihelper.commands.packageconfig

import com.github.ajalt.clikt.testing.test

import io.kotest.core.spec.style.WordSpec
import io.kotest.engine.spec.tempdir
import io.kotest.engine.spec.tempfile
import io.kotest.matchers.collections.containExactly
import io.kotest.matchers.should
import io.kotest.matchers.shouldBe

import org.ossreviewtoolkit.clihelper.HelperMain
import org.ossreviewtoolkit.model.AnalyzerResult
import org.ossreviewtoolkit.model.AnalyzerRun
import org.ossreviewtoolkit.model.Identifier
import org.ossreviewtoolkit.model.LicenseFinding
import org.ossreviewtoolkit.model.OrtResult
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.ScanResult
import org.ossreviewtoolkit.model.ScanSummary
import org.ossreviewtoolkit.model.ScannerDetails
import org.ossreviewtoolkit.model.TextLocation
import org.ossreviewtoolkit.model.VcsInfo
import org.ossreviewtoolkit.model.VcsType
import org.ossreviewtoolkit.model.config.PackageConfiguration
import org.ossreviewtoolkit.model.readValue
import org.ossreviewtoolkit.model.toYaml
import org.ossreviewtoolkit.scanner.storages.PackageBasedFileStorage
import org.ossreviewtoolkit.utils.ort.storage.LocalFileStorage

class CreateCommandFunTest : WordSpec({
"The package configuration create command" should {
"apply a VCS path curation from an ORT result to a stored scan result" {
val packageId = Identifier("Maven:example:package:1.0")
val repositoryVcs = VcsInfo(VcsType.GIT, "https://example.org/repository.git", "main")

val storageDir = tempdir()
val outputDir = tempdir()
val ortFile = tempfile(suffix = ".yml")

val scanResult = ScanResult(
provenance = RepositoryProvenance(repositoryVcs, "resolved-revision"),
scanner = ScannerDetails("scanner", "1.0", "configuration"),
summary = ScanSummary.EMPTY.copy(
licenseFindings = setOf(
LicenseFinding("MIT", TextLocation("module/src/test/ModuleTest.kt", 1)),
LicenseFinding("MIT", TextLocation("other/src/test/OtherTest.kt", 1))
)
)
)

PackageBasedFileStorage(LocalFileStorage(storageDir)).add(packageId, scanResult).getOrThrow()

val pkg = Package.EMPTY.copy(
id = packageId,
vcs = repositoryVcs,
vcsProcessed = repositoryVcs.copy(path = "module")
)

OrtResult.EMPTY.copy(
analyzer = AnalyzerRun.EMPTY.copy(
result = AnalyzerResult.EMPTY.copy(packages = setOf(pkg))
)
).also { ortFile.writeText(it.toYaml()) }

val result = HelperMain().test(
"package-configuration",
"create",
"--scan-results-storage-dir",
storageDir.absolutePath,
"--package-id",
packageId.toCoordinates(),
"--ort-file",
ortFile.absolutePath,
"--output-dir",
outputDir.absolutePath,
"--generate-path-excludes"
)

result.statusCode shouldBe 0
outputDir.resolve("vcs.yml").readValue<PackageConfiguration>().pathExcludes.map { it.pattern } should
containExactly("module/src/test/**")
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import java.io.File

import org.ossreviewtoolkit.clihelper.utils.OrtHelperCommand
import org.ossreviewtoolkit.clihelper.utils.PathExcludeGenerator
import org.ossreviewtoolkit.clihelper.utils.readOrtResult
import org.ossreviewtoolkit.clihelper.utils.sortPathExcludes
import org.ossreviewtoolkit.clihelper.utils.write
import org.ossreviewtoolkit.model.ArtifactProvenance
Expand All @@ -42,6 +43,7 @@ import org.ossreviewtoolkit.model.config.PackageConfiguration
import org.ossreviewtoolkit.model.config.VcsMatcher
import org.ossreviewtoolkit.model.licenses.LicenseClassifications
import org.ossreviewtoolkit.model.readValue
import org.ossreviewtoolkit.model.utils.filterByVcsPath
import org.ossreviewtoolkit.scanner.storages.PackageBasedFileStorage
import org.ossreviewtoolkit.utils.common.expandTilde
import org.ossreviewtoolkit.utils.common.safeMkdirs
Expand All @@ -67,6 +69,13 @@ internal class CreateCommand : OrtHelperCommand(
).convert { Identifier(it) }
.required()

private val ortFile by option(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a reason to not read an entire OrtFile, when this command was implemented, which still is valid, which is execution performance. E.g. I believe generating a package config should be fast.
Reading an OrtFile makes it much slower.

Question: Could the VCS path also be obtained from the scan results inside scanResultsStorageDir ?

"--ort-file",
help = "An optional ORT result whose processed VCS path is applied to stored scan results."
).convert { it.expandTilde() }
.file(mustExist = true, canBeFile = true, canBeDir = false, mustBeWritable = false, mustBeReadable = true)
.convert { it.absoluteFile.normalize() }

private val outputDir by option(
"--output-dir",
help = "The output directory to write the package configurations to."
Expand Down Expand Up @@ -118,6 +127,9 @@ internal class CreateCommand : OrtHelperCommand(
override fun run() {
outputDir.safeMkdirs()

val vcsPath = ortFile?.let { readOrtResult(it, resolveScopes = false) }
?.getPackage(packageId)?.metadata?.vcsProcessed?.path.orEmpty()

val scanResultsStorage = PackageBasedFileStorage(LocalFileStorage(scanResultsStorageDir))
val scanResults = scanResultsStorage.readForId(id = packageId).getOrThrow().run {
listOfNotNull(
Expand All @@ -127,7 +139,7 @@ internal class CreateCommand : OrtHelperCommand(
}

scanResults.forEach { scanResult ->
createPackageConfiguration(scanResult).writeToFile()
createPackageConfiguration(scanResult.filterByVcsPath(vcsPath)).writeToFile()
}
}

Expand Down
Loading