Skip to content

Commit f837543

Browse files
authored
Assign dependency scopes based on include/exclude filters (#105)
- Introduces a simple mechanism to control 'runtime' scope based on configuration filters - Adds the ability to exclude dependency configurations based on filters. Previously could only include. - Added a new report to `SimpleDependencyGraphPlugin` to assist with dependency version upgrades.
2 parents 7f93238 + bf01462 commit f837543

File tree

12 files changed

+499
-203
lines changed

12 files changed

+499
-203
lines changed

README.md

+31-4
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,38 @@ eg: Env var `DEPENDENCY_GRAPH_REPORT_DIR` can be set with `-DDEPENDENCY_GRAPH_RE
4545
If you do not want to include every dependency configuration in every project in your build, you can limit the
4646
dependency extraction to a subset of these.
4747

48-
To restrict which Gradle subprojects contribute to the report, specify which projects to include via a regular expression.
49-
You can provide this value via the `DEPENDENCY_GRAPH_INCLUDE_PROJECTS` environment variable or system property.
48+
The following parameters control the set of projects and configurations that contribute dependencies.
49+
Each of these is a regular expression value, and can set either as an environment variable or as a system property on the command line.
5050

51-
To restrict which Gradle configurations contribute to the report, you can filter configurations by name using a regular expression.
52-
You can provide this value via the `DEPENDENCY_GRAPH_INCLUDE_CONFIGURATIONS` environment variable or system property.
51+
| Property | Description | Default |
52+
|-----------------------------------------|---------------------------|---------------------------------|
53+
| DEPENDENCY_GRAPH_INCLUDE_PROJECTS | Projects to include | All projects are included |
54+
| DEPENDENCY_GRAPH_EXCLUDE_PROJECTS | Projects to exclude | No projects are included |
55+
| DEPENDENCY_GRAPH_INCLUDE_CONFIGURATIONS | Configurations to include | All configurations are included |
56+
| DEPENDENCY_GRAPH_EXCLUDE_CONFIGURATIONS | Configurations to exclude | No configurations are included |
57+
58+
### Controlling the scope of dependencies in the dependency graph
59+
60+
The GitHub dependency graph allows a scope to be assigned to each reported dependency.
61+
The only permissible values for scope are 'runtime' and 'development'.
62+
63+
The following parameters control the set of projects and configurations that provide 'runtime' scoped dependencies.
64+
Any dependency resolution that does not match these parameters will be scoped 'development'.
65+
66+
Each of these parameters is a regular expression value, and can set either as an environment variable or as a system property on the command line.
67+
68+
| Property | Description | Default |
69+
|-------------------------------------------------|-----------------------------------------------------------|---------------------------------|
70+
| DEPENDENCY_GRAPH_RUNTIME_INCLUDE_PROJECTS | Projects that can provide 'runtime' dependencies | All projects are included |
71+
| DEPENDENCY_GRAPH_RUNTIME_EXCLUDE_PROJECTS | Projects that do not provide 'runtime' dependencies | No projects are included |
72+
| DEPENDENCY_GRAPH_RUNTIME_INCLUDE_CONFIGURATIONS | Configurations that contain 'runtime' dependencies | All configurations are included |
73+
| DEPENDENCY_GRAPH_RUNTIME_EXCLUDE_CONFIGURATIONS | Configurations that do not contain 'runtime' dependencies | No configurations are included |
74+
75+
By default, no scope is assigned to dependencies in the graph. To enable scopes in the generated dependency graph,
76+
at least one of these parameters must be configured.
77+
78+
For dependencies that are resolved in multiple projects and/or multiple configurations, only a single 'runtime' scoped resolution
79+
is required for that dependency to be scoped 'runtime'.
5380

5481
### Gradle compatibility
5582

plugin-test/src/test/groovy/org/gradle/github/dependencygraph/BaseExtractorTest.groovy

+11
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ abstract class BaseExtractorTest extends Specification {
113113
}
114114
apply plugin: GitHubDependencyGraphPlugin
115115
""".stripMargin()
116+
resetArguments()
117+
}
118+
119+
protected SimpleGradleExecuter resetArguments() {
116120
getExecuter().withArguments("--init-script", "init.gradle")
117121
}
118122

@@ -194,6 +198,12 @@ abstract class BaseExtractorTest extends Specification {
194198
return (manifestData.file as Map).source_location
195199
}
196200

201+
def assertResolved(List<String> expectedResolved) {
202+
def resolved = manifestData.resolved as Map<String, Map>
203+
assert resolved.keySet() == expectedResolved as Set
204+
return true
205+
}
206+
197207
def assertResolved(Map<String, Map> expectedResolved = [:]) {
198208
def resolved = manifestData.resolved as Map<String, Map>
199209

@@ -208,6 +218,7 @@ abstract class BaseExtractorTest extends Specification {
208218
}
209219
assert actual.relationship == (expected.relationship ?: "direct")
210220
assert actual.dependencies == (expected.dependencies ?: [])
221+
assert actual.scope == expected.scope
211222
}
212223

213224
return true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
package org.gradle.github.dependencygraph
2+
3+
4+
import org.gradle.test.fixtures.maven.MavenModule
5+
6+
class ConfigurationFilterDependencyExtractorTest extends BaseExtractorTest {
7+
private MavenModule foo
8+
private MavenModule bar
9+
private MavenModule baz
10+
11+
private File settingsFile
12+
private File buildFile
13+
14+
def setup() {
15+
applyDependencyGraphPlugin()
16+
establishEnvironmentVariables()
17+
18+
foo = mavenRepo.module("org.test", "foo", "1.0").publish()
19+
bar = mavenRepo.module("org.test", "bar", "1.0").publish()
20+
baz = mavenRepo.module("org.test", "baz", "1.0").dependsOn(bar).publish()
21+
22+
settingsFile = file("settings.gradle") << """
23+
rootProject.name = 'parent'
24+
"""
25+
26+
buildFile = file("build.gradle") << """
27+
allprojects {
28+
group "org.test"
29+
version "1.0"
30+
31+
repositories {
32+
maven { url "${mavenRepo.uri}" }
33+
}
34+
}
35+
"""
36+
}
37+
38+
def "can filter projects to extract dependencies"() {
39+
given:
40+
settingsFile << "include 'a', 'b', 'c'"
41+
42+
buildFile << """
43+
project(':a') {
44+
apply plugin: 'java-library'
45+
dependencies {
46+
api 'org.test:foo:1.0'
47+
}
48+
}
49+
project(':b') {
50+
apply plugin: 'java-library'
51+
dependencies {
52+
api 'org.test:bar:1.0'
53+
}
54+
}
55+
project(':c') {
56+
apply plugin: 'java-library'
57+
dependencies {
58+
api 'org.test:baz:1.0'
59+
}
60+
}
61+
"""
62+
63+
when:
64+
executer.withArgument("-DDEPENDENCY_GRAPH_INCLUDE_PROJECTS=:b")
65+
run()
66+
67+
then:
68+
gitHubManifest().assertResolved(["org.test:bar:1.0"])
69+
70+
when:
71+
resetArguments()
72+
executer.withArgument("-DDEPENDENCY_GRAPH_INCLUDE_PROJECTS=:[ab]")
73+
run()
74+
75+
then:
76+
gitHubManifest().assertResolved(["org.test:foo:1.0", "org.test:bar:1.0"])
77+
78+
when:
79+
resetArguments()
80+
executer.withArgument("-DDEPENDENCY_GRAPH_EXCLUDE_PROJECTS=:[bc]")
81+
run()
82+
83+
then:
84+
gitHubManifest().assertResolved(["org.test:foo:1.0"])
85+
86+
when:
87+
resetArguments()
88+
executer.withArgument("-DDEPENDENCY_GRAPH_INCLUDE_PROJECTS=:[ab]")
89+
executer.withArgument("-DDEPENDENCY_GRAPH_EXCLUDE_PROJECTS=:b")
90+
run()
91+
92+
then:
93+
gitHubManifest().assertResolved(["org.test:foo:1.0"])
94+
}
95+
96+
def "can filter configurations to extract dependencies"() {
97+
given:
98+
settingsFile << "include 'a', 'b'"
99+
100+
buildFile << """
101+
project(':a') {
102+
apply plugin: 'java-library'
103+
dependencies {
104+
api 'org.test:foo:1.0'
105+
testImplementation 'org.test:baz:1.0'
106+
}
107+
}
108+
project(':b') {
109+
apply plugin: 'java-library'
110+
dependencies {
111+
implementation 'org.test:bar:1.0'
112+
testImplementation 'org.test:baz:1.0'
113+
}
114+
}
115+
"""
116+
117+
when:
118+
executer.withArgument("-DDEPENDENCY_GRAPH_INCLUDE_CONFIGURATIONS=compileClasspath")
119+
run()
120+
121+
then:
122+
gitHubManifest().assertResolved(["org.test:foo:1.0", "org.test:bar:1.0"])
123+
124+
when:
125+
resetArguments()
126+
executer.withArgument("-DDEPENDENCY_GRAPH_EXCLUDE_CONFIGURATIONS=test(Compile|Runtime)Classpath")
127+
run()
128+
129+
then:
130+
gitHubManifest().assertResolved(["org.test:foo:1.0", "org.test:bar:1.0"])
131+
}
132+
133+
def "can filter runtime projects to determine scope"() {
134+
given:
135+
settingsFile << "include 'a', 'b'"
136+
137+
buildFile << """
138+
project(':a') {
139+
apply plugin: 'java-library'
140+
dependencies {
141+
api 'org.test:foo:1.0'
142+
}
143+
}
144+
project(':b') {
145+
apply plugin: 'java-library'
146+
dependencies {
147+
implementation 'org.test:bar:1.0'
148+
}
149+
}
150+
"""
151+
152+
when:
153+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_INCLUDE_PROJECTS=:a")
154+
run()
155+
156+
then:
157+
gitHubManifest().assertResolved([
158+
"org.test:foo:1.0": [scope: "runtime"],
159+
"org.test:bar:1.0": [scope: "development"]
160+
])
161+
162+
when:
163+
resetArguments()
164+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_EXCLUDE_PROJECTS=:b")
165+
run()
166+
167+
then:
168+
gitHubManifest().assertResolved([
169+
"org.test:foo:1.0": [scope: "runtime"],
170+
"org.test:bar:1.0": [scope: "development"]
171+
])
172+
173+
when:
174+
resetArguments()
175+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_INCLUDE_PROJECTS=:[ab]")
176+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_EXCLUDE_PROJECTS=:b")
177+
run()
178+
179+
then:
180+
gitHubManifest().assertResolved([
181+
"org.test:foo:1.0": [scope: "runtime"],
182+
"org.test:bar:1.0": [scope: "development"]
183+
])
184+
}
185+
186+
def "can filter runtime configurations to determine scope"() {
187+
given:
188+
settingsFile << "include 'a', 'b'"
189+
190+
buildFile << """
191+
project(':a') {
192+
apply plugin: 'java-library'
193+
dependencies {
194+
api 'org.test:foo:1.0'
195+
testImplementation 'org.test:baz:1.0'
196+
}
197+
}
198+
project(':b') {
199+
apply plugin: 'java-library'
200+
dependencies {
201+
implementation 'org.test:bar:1.0'
202+
testImplementation 'org.test:baz:1.0'
203+
}
204+
}
205+
"""
206+
207+
when:
208+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_INCLUDE_CONFIGURATIONS=compileClasspath")
209+
run()
210+
211+
then:
212+
gitHubManifest().assertResolved([
213+
"org.test:foo:1.0": [scope: "runtime"],
214+
"org.test:bar:1.0": [scope: "runtime"],
215+
"org.test:baz:1.0": [scope: "development", dependencies: ["org.test:bar:1.0"]]
216+
])
217+
218+
when:
219+
resetArguments()
220+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_INCLUDE_CONFIGURATIONS=.*Classpath")
221+
run()
222+
223+
then:
224+
gitHubManifest().assertResolved([
225+
"org.test:foo:1.0": [scope: "runtime"],
226+
"org.test:bar:1.0": [scope: "runtime"],
227+
"org.test:baz:1.0": [scope: "runtime", dependencies: ["org.test:bar:1.0"]]
228+
])
229+
230+
when:
231+
resetArguments()
232+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_INCLUDE_CONFIGURATIONS=.*Classpath")
233+
executer.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_EXCLUDE_CONFIGURATIONS=test(Compile|Runtime)Classpath")
234+
run()
235+
236+
then:
237+
gitHubManifest().assertResolved([
238+
"org.test:foo:1.0": [scope: "runtime"],
239+
"org.test:bar:1.0": [scope: "runtime"],
240+
"org.test:baz:1.0": [scope: "development", dependencies: ["org.test:bar:1.0"]]
241+
])
242+
}
243+
244+
def "can filter runtime projects and configurations to determine scope"() {
245+
given:
246+
settingsFile << "include 'a', 'b', 'c'"
247+
248+
buildFile << """
249+
project(':a') {
250+
apply plugin: 'java-library'
251+
dependencies {
252+
api 'org.test:foo:1.0'
253+
testImplementation 'org.test:baz:1.0'
254+
}
255+
}
256+
project(':b') {
257+
apply plugin: 'java-library'
258+
dependencies {
259+
api 'org.test:bar:1.0'
260+
testImplementation 'org.test:baz:1.0'
261+
}
262+
}
263+
project(':b') {
264+
apply plugin: 'java-library'
265+
dependencies {
266+
api 'org.test:baz:1.0'
267+
}
268+
}
269+
"""
270+
271+
when:
272+
executer
273+
.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_INCLUDE_PROJECTS=:[ab]")
274+
.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_INCLUDE_CONFIGURATIONS=.*Classpath")
275+
.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_EXCLUDE_PROJECTS=:b")
276+
.withArgument("-DDEPENDENCY_GRAPH_RUNTIME_EXCLUDE_CONFIGURATIONS=test(Compile|Runtime)Classpath")
277+
run()
278+
279+
then:
280+
gitHubManifest().assertResolved([
281+
"org.test:foo:1.0": [scope: "runtime"],
282+
"org.test:bar:1.0": [scope: "development"],
283+
"org.test:baz:1.0": [scope: "development", dependencies: ["org.test:bar:1.0"]]
284+
])
285+
}
286+
287+
}

0 commit comments

Comments
 (0)