Skip to content

Commit 11f4c9c

Browse files
nnobelismnonnenmacher
authored andcommitted
feat(RepositoryConfiguration): Add a model for path includes
Add model classes for path includes. Path includes can be used to mark files matched by a glob pattern as included. Signed-off-by: Nicolas Nobelis <[email protected]>
1 parent 0db3737 commit 11f4c9c

File tree

8 files changed

+260
-0
lines changed

8 files changed

+260
-0
lines changed

analyzer/src/main/kotlin/PackageManager.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ abstract class PackageManager(val projectType: String) : Plugin {
207207
private fun Excludes.isPathExcluded(root: Path, path: Path): Boolean =
208208
isPathExcluded(root.relativize(path).invariantSeparatorsPathString)
209209

210+
/**
211+
* Check whether the given [path] interpreted relatively against [root] is matched by a path include in this
212+
* [Includes] object.
213+
*/
214+
private fun Includes.isPathIncluded(root: Path, path: Path): Boolean =
215+
isPathIncluded(root.relativize(path).invariantSeparatorsPathString)
216+
210217
/**
211218
* Get a fallback project name from the [definitionFile] path relative to the [analysisRoot]. This function
212219
* should be used if the project name cannot be determined from the project's metadata.

integrations/schemas/repository-configuration-schema.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,34 @@
88
"analyzer": {
99
"$ref": "https://raw.githubusercontent.com/oss-review-toolkit/ort/main/integrations/schemas/repository-configurations/analyzer-configuration-schema.json"
1010
},
11+
"includes": {
12+
"type": "object",
13+
"description": "Defines which parts of a repository should be included.",
14+
"properties": {
15+
"paths": {
16+
"type": "array",
17+
"items": {
18+
"type": "object",
19+
"properties": {
20+
"pattern": {
21+
"description": "A glob to match the path of the project definition file, relative to the root of the repository.",
22+
"type": "string"
23+
},
24+
"reason": {
25+
"$ref": "#/definitions/pathIncludeReason"
26+
},
27+
"comment": {
28+
"type": "string"
29+
}
30+
},
31+
"required": [
32+
"pattern",
33+
"reason"
34+
]
35+
}
36+
}
37+
}
38+
},
1139
"excludes": {
1240
"type": "object",
1341
"description": "Defines which parts of a repository should be excluded.",
@@ -256,6 +284,11 @@
256284
"reason"
257285
]
258286
},
287+
"pathIncludeReason": {
288+
"enum": [
289+
"SOURCE_OF"
290+
]
291+
},
259292
"pathExcludeReason": {
260293
"enum": [
261294
"BUILD_TOOL_OF",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* License-Filename: LICENSE
18+
*/
19+
20+
package org.ossreviewtoolkit.model.config
21+
22+
import com.fasterxml.jackson.annotation.JsonInclude
23+
24+
import org.ossreviewtoolkit.model.OrtResult
25+
import org.ossreviewtoolkit.model.Project
26+
import org.ossreviewtoolkit.model.config.config.PathInclude
27+
28+
class Includes(
29+
/**
30+
* Path includes.
31+
*/
32+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
33+
val paths: List<PathInclude> = emptyList()
34+
) {
35+
companion object {
36+
/**
37+
* A constant for an [Includes] instance that does not contain any includes: if no includes are defined,
38+
* everything is included.
39+
*/
40+
@JvmField
41+
val EMPTY = Includes()
42+
}
43+
44+
/**
45+
* Return the [PathInclude]s matching the [definitionFilePath][Project.definitionFilePath].
46+
*/
47+
fun findPathIncludes(project: Project, ortResult: OrtResult): List<PathInclude> {
48+
val definitionFilePath = ortResult.getDefinitionFilePathRelativeToAnalyzerRoot(project)
49+
return paths.filter { it.matches(definitionFilePath) }
50+
}
51+
52+
/**
53+
* True if any [path include][paths] matches [path] or if there is no path includes.
54+
*/
55+
fun isPathIncluded(path: String) = paths.isEmpty() || paths.any { it.matches(path) }
56+
}

model/src/main/kotlin/config/RepositoryConfiguration.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonInclude
2323

2424
import org.ossreviewtoolkit.model.utils.CurationsFilter
2525
import org.ossreviewtoolkit.model.utils.ExcludesFilter
26+
import org.ossreviewtoolkit.model.utils.IncludesFilter
2627
import org.ossreviewtoolkit.model.utils.LicenseChoicesFilter
2728
import org.ossreviewtoolkit.model.utils.ResolutionsFilter
2829
import org.ossreviewtoolkit.utils.ort.ORT_REPO_CONFIG_FILENAME
@@ -45,6 +46,12 @@ data class RepositoryConfiguration(
4546
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = ExcludesFilter::class)
4647
val excludes: Excludes = Excludes(),
4748

49+
/**
50+
* Defines which parts of the repository will be included.
51+
*/
52+
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = IncludesFilter::class)
53+
val includes: Includes = Includes.EMPTY,
54+
4855
/**
4956
* Defines resolutions for issues with this repository.
5057
*/
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (C) 2017 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* License-Filename: LICENSE
18+
*/
19+
20+
package org.ossreviewtoolkit.model.config.config
21+
22+
import com.fasterxml.jackson.annotation.JsonInclude
23+
24+
import org.ossreviewtoolkit.utils.common.FileMatcher
25+
26+
/**
27+
* Defines paths which should be included. Each file or directory that is matched by the [glob][pattern] is marked as
28+
* included. If a project definition file is matched by the [pattern], the whole project is included. For details about
29+
* the glob syntax see the [FileMatcher] implementation.
30+
*/
31+
data class PathInclude(
32+
/**
33+
* A glob to match the path of the project definition file, relative to the root of the repository.
34+
*/
35+
val pattern: String,
36+
37+
/**
38+
* The reason why the project is included, out of a predefined choice.
39+
*/
40+
val reason: PathIncludeReason,
41+
42+
/**
43+
* A comment to further explain why the [reason] is applicable here.
44+
*/
45+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
46+
val comment: String = ""
47+
) {
48+
/**
49+
* Return true if and only if this [PathInclude] matches the given [path].
50+
*/
51+
fun matches(path: String) =
52+
FileMatcher.matches(
53+
pattern = pattern.removePrefix("./"),
54+
path = path
55+
)
56+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* License-Filename: LICENSE
18+
*/
19+
20+
package org.ossreviewtoolkit.model.config.config
21+
22+
enum class PathIncludeReason {
23+
/**
24+
* The path contains source code used to build distributed build artifacts.
25+
*/
26+
SOURCE_OF,
27+
28+
/**
29+
* Any other reason which cannot be represented by any other element of [PathIncludeReason].
30+
*/
31+
OTHER
32+
}

model/src/main/kotlin/utils/JsonIncludeValueFilters.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package org.ossreviewtoolkit.model.utils
2222
import org.ossreviewtoolkit.model.PackageLinkage
2323
import org.ossreviewtoolkit.model.config.Curations
2424
import org.ossreviewtoolkit.model.config.Excludes
25+
import org.ossreviewtoolkit.model.config.Includes
2526
import org.ossreviewtoolkit.model.config.LicenseChoices
2627
import org.ossreviewtoolkit.model.config.Resolutions
2728

@@ -36,6 +37,11 @@ internal class ExcludesFilter {
3637
override fun equals(other: Any?): Boolean = other is Excludes && other.paths.isEmpty() && other.scopes.isEmpty()
3738
}
3839

40+
@Suppress("EqualsOrHashCode", "EqualsWithHashCodeExist") // The class is not supposed to be used with hashing.
41+
internal class IncludesFilter {
42+
override fun equals(other: Any?): Boolean = other is Includes && other.paths.isEmpty()
43+
}
44+
3945
@Suppress("EqualsOrHashCode", "EqualsWithHashCodeExist") // The class is not supposed to be used with hashing.
4046
internal class LicenseChoicesFilter {
4147
override fun equals(other: Any?): Boolean = other is LicenseChoices && other.isEmpty()

website/docs/configuration/ort-yml.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ The items below can be configured by adding an `.ort.yml` file to the root of th
44
All configurations in this file apply only to this Project's context.
55
Usually, the global context is preferred for an increased degree of automation, and local configurations should only be done if there are good reasons.
66

7+
* [includes](#includes) - Mark [files, directories](#including-paths) as included in released artifacts.
78
* [excludes](#excludes) - Mark [files, directories](#excluding-paths) or [package manager scopes](#excluding-scopes) as not included in released artifacts.
89
* [resolutions](#resolutions) - Resolve any issues or policy rule violations.
910
* [curations](#curations) - Overwrite package metadata, set a concluded license, or correct license findings in the project.
@@ -14,6 +15,60 @@ The sections below explain each in further detail.
1415
Prefer to learn by example?
1516
See the [.ort.yml](https://github.com/oss-review-toolkit/ort/blob/main/.ort.yml) for the OSS Review Toolkit itself.
1617

18+
## Includes
19+
20+
### When to Use Includes
21+
22+
Includes are used to define which OSS is distributed to third parties and which code is only used internally.
23+
24+
Inclusions apply to paths (files/directories) only.
25+
Examples of currently supported inclusions:
26+
27+
* all dependencies defined in `./src/pom.xml` in Maven-based projects.
28+
29+
### Includes Basics
30+
31+
ORT's default philosophy is to analyze and scan everything it can find to build a complete picture of a repository and its dependencies.
32+
33+
However, in some cases, only a subset of the repository is relevant for the analysis, for example, if the repository is a monorepo containing multiple projects.
34+
While [excludes](#excludes) could be used to ignore the irrelevant parts, it is often more convenient to explicitly include only the relevant parts.
35+
36+
To be able to show why a part is included, each include must have an explanation.
37+
The explanation consists of:
38+
39+
* `reason` -- must be selected from a predefined list of options.
40+
* `comment` -- free text that provides an optional explanation.
41+
42+
### Including Paths
43+
44+
Path includes are used to mark a complete path as included.
45+
46+
The code below shows the structure of a path include in the `.ort.yml` file:
47+
48+
```yaml
49+
includes:
50+
paths:
51+
- pattern: "A glob pattern matching files or paths."
52+
reason: "One of PathIncludeReason e.g. SOURCE_OF."
53+
comment: "A comment further explaining why the path is included."
54+
```
55+
56+
Where the list of available options for `reason` is defined in [PathIncludeReason.kt](https://github.com/oss-review-toolkit/ort/blob/main/model/src/main/kotlin/config/PathIncludeReason.kt).
57+
For how to write a glob pattern, please see the [AntPathMatcher documentation](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html).
58+
59+
The path include below has the following effects:
60+
61+
* All projects found below the `src` directory are marked as included.
62+
* License findings in files below the `src` directory are marked as included.
63+
64+
```yaml
65+
excludes:
66+
paths:
67+
- pattern: "src/**"
68+
reason: "SOURCE_OF"
69+
comment: "This directory contains the source code of binaries that are distributed."
70+
```
71+
1772
## Excludes
1873

1974
### When to Use Excludes
@@ -149,6 +204,14 @@ import Yarn from '!!raw-loader!@site/../examples/yarn.ort.yml'
149204
<CodeBlock language="yml" title="Yarn">{Yarn}</CodeBlock>
150205
```
151206

207+
## Interaction between Includes and Excludes
208+
209+
There is no priority when using both includes and excludes.
210+
The includes control what is included and excludes everything else.
211+
Excludes add extra exclusions.
212+
If includes and excludes overlap, excludes are stronger.
213+
This means that if a file is matched by both includes and excludes, it will be excluded.
214+
152215
## Resolutions
153216

154217
### When to Use Resolutions

0 commit comments

Comments
 (0)