Skip to content

Commit ea7dc0e

Browse files
committed
fix: filter out configs without deps
Before using a configuration, check that it has resolvable dependencies. Each configuraiton must have at least one firstLevelModuleDependencies that comes from a resolvable configuration. This filters out deprecated configurations, like compile and runtime. By allowing these configurations to be proccesed we incorrectly resolve dependencies for them.
1 parent 557de77 commit ea7dc0e

File tree

7 files changed

+95
-15
lines changed

7 files changed

+95
-15
lines changed

lib/init.gradle

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -272,20 +272,46 @@ def findProjectConfigs(proj, confNameFilter, confAttrSpec) {
272272
debugLog("resolvableConfigs=$resolvable")
273273
return resolvable
274274
}
275+
276+
// Only include configurations that actually have dependencies
277+
def hasResolvableDependencies(config, resolvableConfigs) {
278+
def resolvableDependencies = []
279+
// Does this dependency come from a resolvable configuration?
280+
config.firstLevelModuleDependencies.each { dep ->
281+
def isResolvableDependency = resolvableConfigs.any { conf -> conf.name == dep.configuration }
282+
if (isResolvableDependency) {
283+
resolvableDependencies.add(dep)
284+
}
285+
}
286+
287+
if (resolvableDependencies.isEmpty()) {
288+
return false
289+
}
290+
return true
291+
}
292+
275293
List getResolvedConfigs(resolvableConfigs){
276294
List resolvedConfigs = []
277295
resolvableConfigs.each({ config ->
278296
ResolvedConfiguration resConf = config.getResolvedConfiguration()
279297
debugLog("config `$config.name' resolution has errors: ${resConf.hasError()}")
280298
if (!resConf.hasError()) {
281-
resolvedConfigs.add(resConf)
282-
debugLog("Fully resolved config `$config.name' with deps: $resConf.firstLevelModuleDependencies")
299+
if (hasResolvableDependencies(resConf, resolvableConfigs)) {
300+
resolvedConfigs.add(resConf)
301+
debugLog("Fully resolved config `$config.name' with deps: $resConf.firstLevelModuleDependencies")
302+
} else {
303+
debugLog("Skipping resolved config `$config.name' no resolvable dependencies found")
304+
}
283305
} else {
284306
// even if some dependencies fail to resolve, we prefer a partial result to none
285307
LenientConfiguration lenientConf = resConf.getLenientConfiguration()
286-
debugLog("Partially resolved config `$config.name' with: $lenientConf.firstLevelModuleDependencies")
287-
debugLog("Couldn't resolve: ${lenientConf.getUnresolvedModuleDependencies()}")
288-
resolvedConfigs.add(lenientConf)
308+
if (hasResolvableDependencies(lenientConf, resolvableConfigs)) {
309+
resolvedConfigs.add(lenientConf)
310+
debugLog("Partially resolved config `$config.name' with: $lenientConf.firstLevelModuleDependencies")
311+
debugLog("Couldn't resolve: ${lenientConf.getUnresolvedModuleDependencies()}")
312+
} else {
313+
debugLog("Skipping lenient config `$config.name' no resolvable dependencies found")
314+
}
289315
}
290316
})
291317
return resolvedConfigs
@@ -379,11 +405,6 @@ allprojects { Project currProj ->
379405

380406
def resolvableConfigs = findProjectConfigs(proj, confNameFilter, confAttrSpec)
381407
List resolvedConfigs = getResolvedConfigs(resolvableConfigs)
382-
383-
if (resolvedConfigs.isEmpty() && !resolvableConfigs.isEmpty()) {
384-
throw new RuntimeException('Configurations: ' + resolvableConfigs.collect { it.name } +
385-
' for project ' + proj + ' could not be resolved.')
386-
}
387408
List nonemptyFirstLevelDeps = []
388409
resolvedConfigs.each { nonemptyFirstLevelDeps.addAll(it.getFirstLevelModuleDependencies()) }
389410

@@ -481,11 +502,6 @@ allprojects { Project currProj ->
481502

482503
def resolvableConfigs = findProjectConfigs(proj, confNameFilter, confAttrSpec)
483504
List resolvedConfigs = getResolvedConfigs(resolvableConfigs)
484-
if (!resolvableConfigs.isEmpty() && resolvedConfigs.isEmpty()) {
485-
throw new RuntimeException('Configurations: ' + resolvableConfigs.collect { it.name } +
486-
' for project ' + proj + ' could not be resolved.')
487-
}
488-
489505
List nonemptyFirstLevelDeps = []
490506
resolvedConfigs.each { nonemptyFirstLevelDeps.addAll(it.getFirstLevelModuleDependencies()) }
491507

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# multi-project-compile
2+
3+
This test fixture ensures we only resolve a single version of 'tomcat-embed-core' when one subproject depends on another using the 'compile' configuration.
4+
5+
Changes made to the init.gradle now ensure empty configurations and dependencies that come from non-resolvable configurations are ignored.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
allprojects {
2+
repositories {
3+
mavenCentral()
4+
}
5+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
rootProject.name = 'root-proj'
2+
include 'subproj-a', 'subproj-b'
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
plugins {
2+
id 'java-library'
3+
id 'org.springframework.boot' version '2.7.18'
4+
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
5+
}
6+
7+
bootJar {
8+
enabled = false
9+
}
10+
11+
dependencies {
12+
compile project(':subproj-b')
13+
implementation 'org.apache.tomcat.embed:tomcat-embed-core:9.0.99'
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
plugins {
2+
id 'java-library'
3+
id 'org.springframework.boot' version '2.7.18'
4+
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
5+
}
6+
7+
bootJar {
8+
enabled = false
9+
}
10+
11+
dependencies {
12+
implementation 'org.apache.tomcat.embed:tomcat-embed-core:9.0.99'
13+
}

test/system/multi-module.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,4 +649,29 @@ describe('multi-project', () => {
649649
'module/tools',
650650
]);
651651
});
652+
653+
test('multi-project-compile: ignores empty configurations and dependencies that are not resolvable', async () => {
654+
const result = await inspect(
655+
'.',
656+
path.join(fixtureDir('multi-project-compile'), 'build.gradle'),
657+
{ allSubProjects: true },
658+
);
659+
660+
expect(result.scannedProjects.length).toBe(3);
661+
662+
const allDependencies = new Set<string>();
663+
for (const project of result.scannedProjects) {
664+
const pkgs = project.depGraph.getDepPkgs();
665+
Object.keys(pkgs).forEach((id) => {
666+
allDependencies.add(`${pkgs[id].name}@${pkgs[id].version}`);
667+
});
668+
}
669+
670+
// Check that we only have one version of tomcat-embed-core
671+
const tomcatVersions = Array.from(allDependencies).filter(dep =>
672+
dep.startsWith('org.apache.tomcat.embed:tomcat-embed-core@')
673+
);
674+
675+
expect(tomcatVersions).toEqual(['org.apache.tomcat.embed:tomcat-embed-core@9.0.99']);
676+
});
652677
});

0 commit comments

Comments
 (0)