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
17 changes: 16 additions & 1 deletion analyzer/src/main/kotlin/Analyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import org.ossreviewtoolkit.model.AnalyzerResult
import org.ossreviewtoolkit.model.AnalyzerRun
import org.ossreviewtoolkit.model.OrtResult
import org.ossreviewtoolkit.model.Repository
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.VcsInfo
import org.ossreviewtoolkit.model.config.AnalyzerConfiguration
import org.ossreviewtoolkit.model.config.Excludes
import org.ossreviewtoolkit.model.config.RepositoryConfiguration
Expand Down Expand Up @@ -143,11 +145,24 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma

val workingTree = VersionControlSystem.forDirectory(info.absoluteProjectPath)
val vcs = workingTree?.getInfo().orEmpty()
val resolvedRevision = workingTree?.getRevision().orEmpty()
val nestedVcs = workingTree?.getNested()?.filter { (path, _) ->
// Only include nested VCS if they are part of the analyzed directory.
workingTree.getRootPath().resolve(path).startsWith(info.absoluteProjectPath)
}.orEmpty()
val repository = Repository(vcs = vcs, nestedRepositories = nestedVcs, config = info.repositoryConfiguration)

val repository = if (vcs == VcsInfo.EMPTY || resolvedRevision.isEmpty()) {
Repository.EMPTY
} else {
Repository(
provenance = RepositoryProvenance(
vcsInfo = vcs.normalize(),
resolvedRevision = resolvedRevision
),
nestedRepositories = nestedVcs,
config = info.repositoryConfiguration
)
}

val endTime = Instant.now()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import org.ossreviewtoolkit.model.PackageReference
import org.ossreviewtoolkit.model.Project
import org.ossreviewtoolkit.model.RemoteArtifact
import org.ossreviewtoolkit.model.Repository
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.Scope
import org.ossreviewtoolkit.model.VcsInfo
import org.ossreviewtoolkit.model.VcsType
Expand Down Expand Up @@ -120,7 +121,12 @@ internal class CreateAnalyzerResultFromPackageListCommand : OrtHelperCommand(
environment = Environment()
),
repository = Repository(
vcs = projectVcs.normalize(),
provenance = projectVcs.normalize().let {
RepositoryProvenance(
vcsInfo = it,
resolvedRevision = it.revision
)
},
config = RepositoryConfiguration(
excludes = Excludes(
scopes = listOf(
Expand Down
2 changes: 1 addition & 1 deletion cli-helper/src/main/kotlin/utils/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ internal fun OrtResult.getScanResultFor(packageConfiguration: PackageConfigurati
* tree.
*/
internal fun OrtResult.getRepositoryPaths(): Map<String, Set<String>> {
val result = mutableMapOf(repository.vcsProcessed.url to mutableSetOf(""))
val result = mutableMapOf(repository.provenance.vcsInfo.url to mutableSetOf(""))

repository.nestedRepositories.mapValues { (path, vcsInfo) ->
result.getOrPut(vcsInfo.url) { mutableSetOf() } += path
Expand Down
2 changes: 1 addition & 1 deletion evaluator/src/main/kotlin/ProjectSourceRule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ open class ProjectSourceRule(
/**
* Return the [VcsType] of the project's code repository.
*/
fun projectSourceGetVcsType(): VcsType = ortResult.repository.vcsProcessed.type
fun projectSourceGetVcsType(): VcsType = ortResult.repository.provenance.vcsInfo.type

/**
* Return the file paths matching any of the given [glob expressions][patterns] with its file content matching
Expand Down
2 changes: 1 addition & 1 deletion evaluator/src/main/kotlin/RuleSet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fun ruleSet(
licenseInfoResolver: LicenseInfoResolver = ortResult.createLicenseInfoResolver(),
resolutionProvider: ResolutionProvider = DefaultResolutionProvider.create(),
projectSourceResolver: SourceTreeResolver = SourceTreeResolver.forRemoteRepository(
ortResult.repository.vcsProcessed
ortResult.repository.provenance.vcsInfo
),
configure: RuleSet.() -> Unit = {}
) = RuleSet(ortResult, licenseInfoResolver, resolutionProvider, projectSourceResolver).apply(configure)
7 changes: 6 additions & 1 deletion evaluator/src/test/kotlin/ProjectSourceRuleTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,12 @@ private fun createOrtResult(
}

return OrtResult.EMPTY.copy(
repository = Repository(vcsInfo),
repository = Repository(
provenance = RepositoryProvenance(
vcsInfo = vcsInfo,
resolvedRevision = vcsInfo.revision
)
),
analyzer = AnalyzerRun.EMPTY.copy(
result = AnalyzerResult.EMPTY.copy(
projects = setOf(
Expand Down
3 changes: 1 addition & 2 deletions evaluator/src/testFixtures/kotlin/TestData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import org.ossreviewtoolkit.model.ScannerDetails
import org.ossreviewtoolkit.model.Scope
import org.ossreviewtoolkit.model.TextLocation
import org.ossreviewtoolkit.model.UnknownProvenance
import org.ossreviewtoolkit.model.VcsInfo
import org.ossreviewtoolkit.model.config.AdvisorConfiguration
import org.ossreviewtoolkit.model.config.AnalyzerConfiguration
import org.ossreviewtoolkit.model.config.Excludes
Expand Down Expand Up @@ -179,7 +178,7 @@ val allProjects = setOf(

val ortResult = OrtResult(
repository = Repository(
vcs = VcsInfo.EMPTY,
provenance = Repository.EMPTY.provenance,
config = RepositoryConfiguration(
excludes = Excludes(
paths = listOf(
Expand Down
78 changes: 65 additions & 13 deletions model/src/main/kotlin/Repository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,25 @@
package org.ossreviewtoolkit.model

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.module.kotlin.treeToValue

import org.ossreviewtoolkit.model.config.RepositoryConfiguration
import org.ossreviewtoolkit.utils.ort.ORT_REPO_CONFIG_FILENAME

/**
* A description of the source code repository that was used as input for ORT.
*/
@JsonDeserialize(using = RepositoryDeserializer::class)
data class Repository(
/**
* Original VCS-related information from the working tree containing the analyzer root.
* Provenance wrapper for original VCS information, if present.
*/
val vcs: VcsInfo,

/**
* Processed VCS-related information from the working tree containing the analyzer root that has e.g. common
* mistakes corrected.
*/
val vcsProcessed: VcsInfo = vcs.normalize(),
val provenance: RepositoryProvenance,

/**
* A map of nested repositories, for example Git submodules or Git-Repo modules. The key is the path to the
Expand All @@ -57,24 +58,75 @@ data class Repository(
*/
@JvmField
val EMPTY = Repository(
vcs = VcsInfo.EMPTY,
vcsProcessed = VcsInfo.EMPTY,
provenance = RepositoryProvenance(
vcsInfo = VcsInfo.EMPTY,
resolvedRevision = HashAlgorithm.SHA1.emptyValue
),
nestedRepositories = emptyMap(),
config = RepositoryConfiguration()
)
}

/**
* Return the path of [vcs] relative to [Repository.vcs], or null if [vcs] is neither [Repository.vcs] nor contained
* in [nestedRepositories].
* Return the path of [vcs] relative to [Repository.provenance], or null if [vcs] is neither [Repository.provenance]
* nor contained in [nestedRepositories].
*/
fun getRelativePath(vcs: VcsInfo): String? {
fun VcsInfo.matches(other: VcsInfo) = type == other.type && url == other.url && revision == other.revision

val normalizedVcs = vcs.normalize()

if (vcsProcessed.matches(normalizedVcs)) return ""
if (provenance.vcsInfo.matches(normalizedVcs)) return ""

return nestedRepositories.entries.find { (_, nestedVcs) -> nestedVcs.normalize().matches(normalizedVcs) }?.key
}
}

/**
* A custom deserializer for [Repository] to support the legacy "vcs" and "vcsProcessed" attributes.
*/
private class RepositoryDeserializer : StdDeserializer<Repository>(Repository::class.java) {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Repository {
val node = p.codec.readTree<JsonNode>(p)
val parsedProvenance = when {
node.has("vcs") -> {
// Parse [vcs] and [vcsProcessed] attributes.
val vcs = jsonMapper.treeToValue<VcsInfo>(node["vcs"])
val vcsProcess = jsonMapper.treeToValue<VcsInfo>(node["vcs_processed"])

// Fall back to [vcsProcessed], if [vcs] is empty.
val vcsInfo = vcsProcess

// Get the [vcs]'s revision.
// Fall back to [vcsProcessed], if [vcs] has empty revision.
val resolvedRevision = vcs.revision.ifEmpty {
vcsProcess.revision.ifEmpty {
HashAlgorithm.SHA1.emptyValue
}
}
Comment on lines +100 to +106
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The EvaluatedModelReporterFunTests are currently failing, since the Deserializer can not extract a resolvedRevison from the legacy Repository data structure, as the vcs_processed only references master. See reporter-test-input.yml, which is used as input in the tests.

I assume I would need to iterate over the other nodes in the file and get the resolved_revision from a provenance, e.g. inside the scanner at L542 or the list of provenances at L438.

Since there is a findParent method, I assume it would at least be possible to iterate over other nodes from inside a Deserializer, but I have not confirmed this yet.

@sschuberth @mnonnenmacher Before I continue on this hunch, could you way in on the issue?


// Build a RepositoryProvenance from the parsed VcsInfo fields.
RepositoryProvenance(vcsInfo, resolvedRevision)
}

else -> {
// Parse the [provenance], if no legacy fields are present.
jsonMapper.treeToValue<RepositoryProvenance>(node["provenance"])
}
}

val nestedRepositories = if (node.has("nested_repositories")) {
jsonMapper.treeToValue<Map<String, VcsInfo>>(node["nested_repositories"])
} else {
emptyMap()
}

val config = if (node.has("config")) {
jsonMapper.treeToValue<RepositoryConfiguration>(node["config"])
} else {
RepositoryConfiguration()
}

return Repository(provenance = parsedProvenance, nestedRepositories, config)
}
}
24 changes: 18 additions & 6 deletions model/src/test/kotlin/OrtResultTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ class OrtResultTest : WordSpec({

"getDefinitionFilePathRelativeToAnalyzerRoot()" should {
"use the correct vcs" {
val vcs = VcsInfo(type = VcsType.GIT, url = "https://example.com/git", revision = "")
val vcs = VcsInfo(
type = VcsType.GIT,
url = "https://example.com/git",
revision = HashAlgorithm.SHA1.emptyValue
)
val provenance = RepositoryProvenance(vcsInfo = vcs, resolvedRevision = vcs.revision)
val nestedVcs1 = VcsInfo(type = VcsType.GIT, url = "https://example.com/git1", revision = "")
val nestedVcs2 = VcsInfo(type = VcsType.GIT, url = "https://example.com/git2", revision = "")
val project1 = Project.EMPTY.copy(
Expand All @@ -185,7 +190,7 @@ class OrtResultTest : WordSpec({
)
val ortResult = OrtResult(
Repository(
vcs = vcs,
provenance = provenance,
nestedRepositories = mapOf(
"path/1" to nestedVcs1,
"path/2" to nestedVcs2
Expand All @@ -202,7 +207,12 @@ class OrtResultTest : WordSpec({
}

"fail if no vcs matches" {
val vcs = VcsInfo(type = VcsType.GIT, url = "https://example.com/git", revision = "")
val vcs = VcsInfo(
type = VcsType.GIT,
url = "https://example.com/git",
revision = HashAlgorithm.SHA1.emptyValue
)
val provenance = RepositoryProvenance(vcsInfo = vcs, resolvedRevision = vcs.revision)
val nestedVcs1 = VcsInfo(type = VcsType.GIT, url = "https://example.com/git1", revision = "")
val nestedVcs2 = VcsInfo(type = VcsType.GIT, url = "https://example.com/git2", revision = "")
val project = Project.EMPTY.copy(
Expand All @@ -213,7 +223,7 @@ class OrtResultTest : WordSpec({
)
val ortResult = OrtResult(
Repository(
vcs = vcs,
provenance = provenance,
nestedRepositories = mapOf(
"path/1" to nestedVcs1
)
Expand Down Expand Up @@ -413,8 +423,10 @@ class OrtResultTest : WordSpec({

val ortResult = OrtResult.EMPTY.copy(
repository = Repository.EMPTY.copy(
vcs = vcs,
vcsProcessed = vcs,
provenance = RepositoryProvenance(
vcsInfo = vcs,
resolvedRevision = vcs.revision
),
config = RepositoryConfiguration(
excludes = Excludes(
paths = listOf(
Expand Down
2 changes: 1 addition & 1 deletion model/src/testFixtures/kotlin/TestData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ val scanResults = listOf(

val ortResult = OrtResult(
repository = Repository(
vcs = VcsInfo.EMPTY,
provenance = Repository.EMPTY.provenance,
config = RepositoryConfiguration(
excludes = Excludes(
paths = listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import org.ossreviewtoolkit.model.OrtResult
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.Project
import org.ossreviewtoolkit.model.Repository
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.RootDependencyIndex
import org.ossreviewtoolkit.model.Scope
import org.ossreviewtoolkit.model.VcsInfo
Expand Down Expand Up @@ -165,8 +166,10 @@ private fun createReporterInput(): ReporterInput {
return ReporterInput(
OrtResult(
repository = Repository(
vcs = analyzedVcs,
vcsProcessed = analyzedVcs
provenance = RepositoryProvenance(
vcsInfo = analyzedVcs,
resolvedRevision = analyzedVcs.revision
)
),
analyzer = AnalyzerRun.EMPTY.copy(
result = AnalyzerResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class CycloneDxReporter(
// There is no component type for repositories.
type = Component.Type.FILE

with(input.ortResult.repository.vcsProcessed) {
with(input.ortResult.repository.provenance.vcsInfo) {
bomRef = "$url@$revision"

name = url
Expand All @@ -178,7 +178,7 @@ class CycloneDxReporter(
// distributable), just create a single BOM for all projects in that case for now. As there also is no
// single correct project to pick for adding external references in that case, simply only use the global
// repository VCS information here.
val vcs = input.ortResult.repository.vcsProcessed
val vcs = input.ortResult.repository.provenance.vcsInfo
bom.addExternalReference(
ExternalReference.Type.VCS,
vcs.url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1166,16 +1166,13 @@ statistics:
MIT: 1
execution_duration_in_seconds: 3125
repository:
vcs:
type: ""
url: ""
revision: ""
path: ""
vcs_processed:
type: "Git"
url: "https://github.com/oss-review-toolkit/ort.git"
revision: "master"
path: "analyzer/src/funTest/assets/projects/synthetic/gradle/lib"
provenance:
vcs_info:
type: "Git"
url: "https://github.com/oss-review-toolkit/ort.git"
revision: "master"
path: "analyzer/src/funTest/assets/projects/synthetic/gradle/lib"
resolved_revision: "3dcca3e6ee0dea120922f90495bf04b4e09ae455"
nested_repositories:
sub/module:
type: "Git"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1261,17 +1261,14 @@
"execution_duration_in_seconds" : 3125
},
"repository" : {
"vcs" : {
"type" : "",
"url" : "",
"revision" : "",
"path" : ""
},
"vcs_processed" : {
"type" : "Git",
"url" : "https://github.com/oss-review-toolkit/ort.git",
"revision" : "master",
"path" : "analyzer/src/funTest/assets/projects/synthetic/gradle/lib"
"provenance" : {
"vcs_info" : {
"type" : "Git",
"url" : "https://github.com/oss-review-toolkit/ort.git",
"revision" : "master",
"path" : "analyzer/src/funTest/assets/projects/synthetic/gradle/lib"
},
"resolved_revision" : "3dcca3e6ee0dea120922f90495bf04b4e09ae455"
},
"nested_repositories" : {
"sub/module" : {
Expand Down
Loading
Loading