Skip to content

Commit 2c81d7f

Browse files
authored
Build: Rework shadow plugin configuration (#32409)
This reworks how we configure the `shadow` plugin in the build. The major change is that we no longer bundle dependencies in the `compile` configuration, instead we bundle dependencies in the new `bundle` configuration. This feels more right because it is a little more "opt in" rather than "opt out" and the name of the `bundle` configuration is a little more obvious. As an neat side effect of this, the `runtimeElements` configuration used when one project depends on another now contains exactly the dependencies needed to run the project so you no longer need to reference projects that use the shadow plugin like this: ``` testCompile project(path: ':client:rest-high-level', configuration: 'shadow') ``` You can instead use the much more normal: ``` testCompile "org.elasticsearch.client:elasticsearch-rest-high-level-client:${version}" ```
1 parent 67b5a83 commit 2c81d7f

File tree

57 files changed

+158
-166
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+158
-166
lines changed

CONTRIBUTING.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -325,21 +325,19 @@ common configurations in our build and how we use them:
325325

326326
<dl>
327327
<dt>`compile`</dt><dd>Code that is on the classpath at both compile and
328-
runtime. If the [`shadow`][shadow-plugin] plugin is applied to the project then
329-
this code is bundled into the jar produced by the project.</dd>
328+
runtime.</dd>
330329
<dt>`runtime`</dt><dd>Code that is not on the classpath at compile time but is
331330
on the classpath at runtime. We mostly use this configuration to make sure that
332331
we do not accidentally compile against dependencies of our dependencies also
333332
known as "transitive" dependencies".</dd>
334-
<dt>`compileOnly`</dt><dd>Code that is on the classpath at comile time but that
333+
<dt>`compileOnly`</dt><dd>Code that is on the classpath at compile time but that
335334
should not be shipped with the project because it is "provided" by the runtime
336335
somehow. Elasticsearch plugins use this configuration to include dependencies
337336
that are bundled with Elasticsearch's server.</dd>
338-
<dt>`shadow`</dt><dd>Only available in projects with the shadow plugin. Code
339-
that is on the classpath at both compile and runtime but it *not* bundled into
340-
the jar produced by the project. If you depend on a project with the `shadow`
341-
plugin then you need to depend on this configuration because it will bring
342-
along all of the dependencies you need at runtime.</dd>
337+
<dt>`bundle`</dt><dd>Only available in projects with the shadow plugin,
338+
dependencies with this configuration are bundled into the jar produced by the
339+
build. Since IDEs do not understand this configuration we rig them to treat
340+
dependencies in this configuration as `compile` dependencies.</dd>
343341
<dt>`testCompile`</dt><dd>Code that is on the classpath for compiling tests
344342
that are part of this project but not production code. The canonical example
345343
of this is `junit`.</dd>

build.gradle

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import org.elasticsearch.gradle.LoggedExec
2222
import org.elasticsearch.gradle.Version
2323
import org.elasticsearch.gradle.VersionCollection
2424
import org.elasticsearch.gradle.VersionProperties
25+
import org.elasticsearch.gradle.plugin.PluginBuildPlugin
2526
import org.gradle.plugins.ide.eclipse.model.SourceFolder
2627
import org.gradle.util.GradleVersion
2728
import org.gradle.util.DistributionLocator
@@ -304,7 +305,7 @@ subprojects {
304305
// org.elasticsearch:elasticsearch must be the last one or all the links for the
305306
// other packages (e.g org.elasticsearch.client) will point to server rather than
306307
// their own artifacts.
307-
if (project.plugins.hasPlugin(BuildPlugin)) {
308+
if (project.plugins.hasPlugin(BuildPlugin) || project.plugins.hasPlugin(PluginBuildPlugin)) {
308309
String artifactsHost = VersionProperties.elasticsearch.isSnapshot() ? "https://snapshots.elastic.co" : "https://artifacts.elastic.co"
309310
Closure sortClosure = { a, b -> b.group <=> a.group }
310311
Closure depJavadocClosure = { shadowed, dep ->
@@ -322,13 +323,6 @@ subprojects {
322323
*/
323324
project.evaluationDependsOn(upstreamProject.path)
324325
project.javadoc.source += upstreamProject.javadoc.source
325-
/*
326-
* Do not add those projects to the javadoc classpath because
327-
* we are going to resolve them with their source instead.
328-
*/
329-
project.javadoc.classpath = project.javadoc.classpath.filter { f ->
330-
false == upstreamProject.configurations.archives.artifacts.files.files.contains(f)
331-
}
332326
/*
333327
* Instead we need the upstream project's javadoc classpath so
334328
* we don't barf on the classes that it references.
@@ -345,16 +339,16 @@ subprojects {
345339
project.configurations.compile.dependencies
346340
.findAll()
347341
.toSorted(sortClosure)
348-
.each({ c -> depJavadocClosure(hasShadow, c) })
342+
.each({ c -> depJavadocClosure(false, c) })
349343
project.configurations.compileOnly.dependencies
350344
.findAll()
351345
.toSorted(sortClosure)
352-
.each({ c -> depJavadocClosure(hasShadow, c) })
346+
.each({ c -> depJavadocClosure(false, c) })
353347
if (hasShadow) {
354-
project.configurations.shadow.dependencies
348+
project.configurations.bundle.dependencies
355349
.findAll()
356350
.toSorted(sortClosure)
357-
.each({ c -> depJavadocClosure(false, c) })
351+
.each({ c -> depJavadocClosure(true, c) })
358352
}
359353
}
360354
}
@@ -523,25 +517,18 @@ allprojects {
523517
allprojects {
524518
/*
525519
* IntelliJ and Eclipse don't know about the shadow plugin so when we're
526-
* in "IntelliJ mode" or "Eclipse mode" add "runtime" dependencies
527-
* eveywhere where we see a "shadow" dependency which will cause them to
528-
* reference shadowed projects directly rather than rely on the shadowing
529-
* to include them. This is the correct thing for it to do because it
530-
* doesn't run the jar shadowing at all. This isn't needed for the project
520+
* in "IntelliJ mode" or "Eclipse mode" switch "bundle" dependencies into
521+
* regular "compile" dependencies. This isn't needed for the project
531522
* itself because the IDE configuration is done by SourceSets but it is
532523
* *is* needed for projects that depends on the project doing the shadowing.
533524
* Without this they won't properly depend on the shadowed project.
534525
*/
535526
if (isEclipse || isIdea) {
536-
configurations.all { Configuration configuration ->
537-
dependencies.all { Dependency dep ->
538-
if (dep instanceof ProjectDependency) {
539-
if (dep.getTargetConfiguration() == 'shadow') {
540-
configuration.dependencies.add(project.dependencies.project(path: dep.dependencyProject.path, configuration: 'runtime'))
541-
}
542-
}
543-
}
544-
}
527+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
528+
project.afterEvaluate {
529+
project.configurations.compile.extendsFrom project.configurations.bundle
530+
}
531+
}
545532
}
546533
}
547534

buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

Lines changed: 30 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ class BuildPlugin implements Plugin<Project> {
7979
}
8080
project.pluginManager.apply('java')
8181
project.pluginManager.apply('carrotsearch.randomized-testing')
82-
// these plugins add lots of info to our jars
82+
configureConfigurations(project)
8383
configureJars(project) // jar config must be added before info broker
84+
// these plugins add lots of info to our jars
8485
project.pluginManager.apply('nebula.info-broker')
8586
project.pluginManager.apply('nebula.info-basic')
8687
project.pluginManager.apply('nebula.info-java')
@@ -91,8 +92,8 @@ class BuildPlugin implements Plugin<Project> {
9192

9293
globalBuildInfo(project)
9394
configureRepositories(project)
94-
configureConfigurations(project)
9595
project.ext.versions = VersionProperties.versions
96+
configureSourceSets(project)
9697
configureCompile(project)
9798
configureJavadoc(project)
9899
configureSourcesJar(project)
@@ -421,8 +422,10 @@ class BuildPlugin implements Plugin<Project> {
421422
project.configurations.compile.dependencies.all(disableTransitiveDeps)
422423
project.configurations.testCompile.dependencies.all(disableTransitiveDeps)
423424
project.configurations.compileOnly.dependencies.all(disableTransitiveDeps)
425+
424426
project.plugins.withType(ShadowPlugin).whenPluginAdded {
425-
project.configurations.shadow.dependencies.all(disableTransitiveDeps)
427+
Configuration bundle = project.configurations.create('bundle')
428+
bundle.dependencies.all(disableTransitiveDeps)
426429
}
427430
}
428431

@@ -556,37 +559,27 @@ class BuildPlugin implements Plugin<Project> {
556559
publications {
557560
nebula(MavenPublication) {
558561
artifacts = [ project.tasks.shadowJar ]
559-
artifactId = project.archivesBaseName
560-
/*
561-
* Configure the pom to include the "shadow" as compile dependencies
562-
* because that is how we're using them but remove all other dependencies
563-
* because they've been shaded into the jar.
564-
*/
565-
pom.withXml { XmlProvider xml ->
566-
Node root = xml.asNode()
567-
root.remove(root.dependencies)
568-
Node dependenciesNode = root.appendNode('dependencies')
569-
project.configurations.shadow.allDependencies.each {
570-
if (false == it instanceof SelfResolvingDependency) {
571-
Node dependencyNode = dependenciesNode.appendNode('dependency')
572-
dependencyNode.appendNode('groupId', it.group)
573-
dependencyNode.appendNode('artifactId', it.name)
574-
dependencyNode.appendNode('version', it.version)
575-
dependencyNode.appendNode('scope', 'compile')
576-
}
577-
}
578-
// Be tidy and remove the element if it is empty
579-
if (dependenciesNode.children.empty) {
580-
root.remove(dependenciesNode)
581-
}
582-
}
583562
}
584563
}
585564
}
586565
}
587566
}
588567
}
589568

569+
/**
570+
* Add dependencies that we are going to bundle to the compile classpath.
571+
*/
572+
static void configureSourceSets(Project project) {
573+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
574+
['main', 'test'].each {name ->
575+
SourceSet sourceSet = project.sourceSets.findByName(name)
576+
if (sourceSet != null) {
577+
sourceSet.compileClasspath += project.configurations.bundle
578+
}
579+
}
580+
}
581+
}
582+
590583
/** Adds compiler settings to the project */
591584
static void configureCompile(Project project) {
592585
if (project.compilerJavaVersion < JavaVersion.VERSION_1_10) {
@@ -764,9 +757,16 @@ class BuildPlugin implements Plugin<Project> {
764757
* better to be safe
765758
*/
766759
mergeServiceFiles()
760+
/*
761+
* Bundle dependencies of the "bundled" configuration.
762+
*/
763+
configurations = [project.configurations.bundle]
767764
}
768765
// Make sure we assemble the shadow jar
769766
project.tasks.assemble.dependsOn project.tasks.shadowJar
767+
project.artifacts {
768+
apiElements project.tasks.shadowJar
769+
}
770770
}
771771
}
772772

@@ -873,13 +873,8 @@ class BuildPlugin implements Plugin<Project> {
873873
exclude '**/*$*.class'
874874

875875
project.plugins.withType(ShadowPlugin).whenPluginAdded {
876-
/*
877-
* If we make a shaded jar we test against it.
878-
*/
876+
// Test against a shadow jar if we made one
879877
classpath -= project.tasks.compileJava.outputs.files
880-
classpath -= project.configurations.compile
881-
classpath -= project.configurations.runtime
882-
classpath += project.configurations.shadow
883878
classpath += project.tasks.shadowJar.outputs.files
884879
dependsOn project.tasks.shadowJar
885880
}
@@ -905,26 +900,6 @@ class BuildPlugin implements Plugin<Project> {
905900
additionalTest.dependsOn(project.tasks.testClasses)
906901
project.check.dependsOn(additionalTest)
907902
});
908-
909-
project.plugins.withType(ShadowPlugin).whenPluginAdded {
910-
/*
911-
* We need somewhere to configure dependencies that we don't wish
912-
* to shade into the jar. The shadow plugin creates a "shadow"
913-
* configuration which is *almost* exactly that. It is never
914-
* bundled into the shaded jar but is used for main source
915-
* compilation. Unfortunately, by default it is not used for
916-
* *test* source compilation and isn't used in tests at all. This
917-
* change makes it available for test compilation.
918-
*
919-
* Note that this isn't going to work properly with qa projects
920-
* but they have no business applying the shadow plugin in the
921-
* firstplace.
922-
*/
923-
SourceSet testSourceSet = project.sourceSets.findByName('test')
924-
if (testSourceSet != null) {
925-
testSourceSet.compileClasspath += project.configurations.shadow
926-
}
927-
}
928903
}
929904

930905
private static configurePrecommit(Project project) {
@@ -936,7 +911,7 @@ class BuildPlugin implements Plugin<Project> {
936911
it.group.startsWith('org.elasticsearch') == false
937912
} - project.configurations.compileOnly
938913
project.plugins.withType(ShadowPlugin).whenPluginAdded {
939-
project.dependencyLicenses.dependencies += project.configurations.shadow.fileCollection {
914+
project.dependencyLicenses.dependencies += project.configurations.bundle.fileCollection {
940915
it.group.startsWith('org.elasticsearch') == false
941916
}
942917
}
@@ -947,7 +922,7 @@ class BuildPlugin implements Plugin<Project> {
947922
deps.runtimeConfiguration = project.configurations.runtime
948923
project.plugins.withType(ShadowPlugin).whenPluginAdded {
949924
deps.runtimeConfiguration = project.configurations.create('infoDeps')
950-
deps.runtimeConfiguration.extendsFrom(project.configurations.runtime, project.configurations.shadow)
925+
deps.runtimeConfiguration.extendsFrom(project.configurations.runtime, project.configurations.bundle)
951926
}
952927
deps.compileOnlyConfiguration = project.configurations.compileOnly
953928
project.afterEvaluate {

buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,10 @@ public class PluginBuildPlugin extends BuildPlugin {
157157
from pluginMetadata // metadata (eg custom security policy)
158158
/*
159159
* If the plugin is using the shadow plugin then we need to bundle
160-
* "shadow" things rather than the default jar and dependencies so
161-
* we don't hit jar hell.
160+
* that shadow jar.
162161
*/
163162
from { project.plugins.hasPlugin(ShadowPlugin) ? project.shadowJar : project.jar }
164-
from { project.plugins.hasPlugin(ShadowPlugin) ? project.configurations.shadow : project.configurations.runtime - project.configurations.compileOnly }
163+
from project.configurations.runtime - project.configurations.compileOnly
165164
// extra files for the plugin to go into the zip
166165
from('src/main/packaging') // TODO: move all config/bin/_size/etc into packaging
167166
from('src/main') {

buildSrc/src/main/groovy/org/elasticsearch/gradle/precommit/JarHellTask.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.gradle.precommit
2121

22+
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
2223
import org.elasticsearch.gradle.LoggedExec
2324
import org.gradle.api.file.FileCollection
2425
import org.gradle.api.tasks.OutputFile
@@ -39,6 +40,9 @@ public class JarHellTask extends LoggedExec {
3940
public JarHellTask() {
4041
project.afterEvaluate {
4142
FileCollection classpath = project.sourceSets.test.runtimeClasspath
43+
if (project.plugins.hasPlugin(ShadowPlugin)) {
44+
classpath += project.configurations.bundle
45+
}
4246
inputs.files(classpath)
4347
dependsOn(classpath)
4448
description = "Runs CheckJarHell on ${classpath}"

buildSrc/src/main/groovy/org/elasticsearch/gradle/precommit/ThirdPartyAuditTask.groovy

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.elasticsearch.gradle.precommit;
2020

21+
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
2122
import org.apache.tools.ant.BuildEvent;
2223
import org.apache.tools.ant.BuildException;
2324
import org.apache.tools.ant.BuildListener;
@@ -82,6 +83,11 @@ public class ThirdPartyAuditTask extends AntTask {
8283
configuration = project.configurations.findByName('testCompile')
8384
}
8485
assert configuration != null
86+
if (project.plugins.hasPlugin(ShadowPlugin)) {
87+
Configuration original = configuration
88+
configuration = project.configurations.create('thirdPartyAudit')
89+
configuration.extendsFrom(original, project.configurations.bundle)
90+
}
8591
if (compileOnly == null) {
8692
classpath = configuration
8793
} else {

client/rest-high-level/build.gradle

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ dependencies {
4747
* Everything in the "shadow" configuration is *not* copied into the
4848
* shadowJar.
4949
*/
50-
shadow "org.elasticsearch:elasticsearch:${version}"
51-
shadow "org.elasticsearch.client:elasticsearch-rest-client:${version}"
52-
shadow "org.elasticsearch.plugin:parent-join-client:${version}"
53-
shadow "org.elasticsearch.plugin:aggs-matrix-stats-client:${version}"
54-
shadow "org.elasticsearch.plugin:rank-eval-client:${version}"
55-
shadow "org.elasticsearch.plugin:lang-mustache-client:${version}"
56-
compile project(':x-pack:protocol')
50+
compile "org.elasticsearch:elasticsearch:${version}"
51+
compile "org.elasticsearch.client:elasticsearch-rest-client:${version}"
52+
compile "org.elasticsearch.plugin:parent-join-client:${version}"
53+
compile "org.elasticsearch.plugin:aggs-matrix-stats-client:${version}"
54+
compile "org.elasticsearch.plugin:rank-eval-client:${version}"
55+
compile "org.elasticsearch.plugin:lang-mustache-client:${version}"
56+
bundle project(':x-pack:protocol')
5757

5858
testCompile "org.elasticsearch.client:test:${version}"
5959
testCompile "org.elasticsearch.test:framework:${version}"

qa/ccs-unavailable-clusters/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ apply plugin: 'elasticsearch.rest-test'
2121
apply plugin: 'elasticsearch.test-with-dependencies'
2222

2323
dependencies {
24-
testCompile project(path: ':client:rest-high-level', configuration: 'shadow')
24+
testCompile "org.elasticsearch.client:elasticsearch-rest-high-level-client:${version}"
2525
}

x-pack/docs/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ buildRestTests.expectedUnconvertedCandidates = [
3030
]
3131

3232
dependencies {
33-
testCompile project(path: xpackModule('core'), configuration: 'shadow')
33+
// "org.elasticsearch.plugin:x-pack-core:${version}" doesn't work with idea because the testArtifacts are also here
34+
testCompile project(path: xpackModule('core'), configuration: 'default')
3435
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
3536
testCompile project(path: xpackProject('plugin').path, configuration: 'testArtifacts')
3637
}
@@ -309,7 +310,7 @@ setups['farequote_datafeed'] = setups['farequote_job'] + '''
309310
"job_id":"farequote",
310311
"indexes":"farequote"
311312
}
312-
'''
313+
'''
313314
setups['ml_filter_safe_domains'] = '''
314315
- do:
315316
xpack.ml.put_filter:

x-pack/license-tools/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apply plugin: 'elasticsearch.build'
22

33
dependencies {
4-
compile project(path: xpackModule('core'), configuration: 'shadow')
4+
compile "org.elasticsearch.plugin:x-pack-core:${version}"
55
compile "org.elasticsearch:elasticsearch:${version}"
66
testCompile "org.elasticsearch.test:framework:${version}"
77
}

0 commit comments

Comments
 (0)