Skip to content

Commit 1d193cf

Browse files
committed
Build: Rework shadow plugin configuration (elastic#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 7b9785e commit 1d193cf

File tree

57 files changed

+156
-165
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

+156
-165
lines changed

CONTRIBUTING.md

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

292292
<dl>
293293
<dt>`compile`</dt><dd>Code that is on the classpath at both compile and
294-
runtime. If the [`shadow`][shadow-plugin] plugin is applied to the project then
295-
this code is bundled into the jar produced by the project.</dd>
294+
runtime.</dd>
296295
<dt>`runtime`</dt><dd>Code that is not on the classpath at compile time but is
297296
on the classpath at runtime. We mostly use this configuration to make sure that
298297
we do not accidentally compile against dependencies of our dependencies also
299298
known as "transitive" dependencies".</dd>
300-
<dt>`compileOnly`</dt><dd>Code that is on the classpath at comile time but that
299+
<dt>`compileOnly`</dt><dd>Code that is on the classpath at compile time but that
301300
should not be shipped with the project because it is "provided" by the runtime
302301
somehow. Elasticsearch plugins use this configuration to include dependencies
303302
that are bundled with Elasticsearch's server.</dd>
304-
<dt>`shadow`</dt><dd>Only available in projects with the shadow plugin. Code
305-
that is on the classpath at both compile and runtime but it *not* bundled into
306-
the jar produced by the project. If you depend on a project with the `shadow`
307-
plugin then you need to depend on this configuration because it will bring
308-
along all of the dependencies you need at runtime.</dd>
303+
<dt>`bundle`</dt><dd>Only available in projects with the shadow plugin,
304+
dependencies with this configuration are bundled into the jar produced by the
305+
build. Since IDEs do not understand this configuration we rig them to treat
306+
dependencies in this configuration as `compile` dependencies.</dd>
309307
<dt>`testCompile`</dt><dd>Code that is on the classpath for compiling tests
310308
that are part of this project but not production code. The canonical example
311309
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
@@ -298,7 +299,7 @@ subprojects {
298299
// org.elasticsearch:elasticsearch must be the last one or all the links for the
299300
// other packages (e.g org.elasticsearch.client) will point to server rather than
300301
// their own artifacts.
301-
if (project.plugins.hasPlugin(BuildPlugin)) {
302+
if (project.plugins.hasPlugin(BuildPlugin) || project.plugins.hasPlugin(PluginBuildPlugin)) {
302303
String artifactsHost = VersionProperties.elasticsearch.isSnapshot() ? "https://snapshots.elastic.co" : "https://artifacts.elastic.co"
303304
Closure sortClosure = { a, b -> b.group <=> a.group }
304305
Closure depJavadocClosure = { shadowed, dep ->
@@ -316,13 +317,6 @@ subprojects {
316317
*/
317318
project.evaluationDependsOn(upstreamProject.path)
318319
project.javadoc.source += upstreamProject.javadoc.source
319-
/*
320-
* Do not add those projects to the javadoc classpath because
321-
* we are going to resolve them with their source instead.
322-
*/
323-
project.javadoc.classpath = project.javadoc.classpath.filter { f ->
324-
false == upstreamProject.configurations.archives.artifacts.files.files.contains(f)
325-
}
326320
/*
327321
* Instead we need the upstream project's javadoc classpath so
328322
* we don't barf on the classes that it references.
@@ -339,16 +333,16 @@ subprojects {
339333
project.configurations.compile.dependencies
340334
.findAll()
341335
.toSorted(sortClosure)
342-
.each({ c -> depJavadocClosure(hasShadow, c) })
336+
.each({ c -> depJavadocClosure(false, c) })
343337
project.configurations.compileOnly.dependencies
344338
.findAll()
345339
.toSorted(sortClosure)
346-
.each({ c -> depJavadocClosure(hasShadow, c) })
340+
.each({ c -> depJavadocClosure(false, c) })
347341
if (hasShadow) {
348-
project.configurations.shadow.dependencies
342+
project.configurations.bundle.dependencies
349343
.findAll()
350344
.toSorted(sortClosure)
351-
.each({ c -> depJavadocClosure(false, c) })
345+
.each({ c -> depJavadocClosure(true, c) })
352346
}
353347
}
354348
}
@@ -517,25 +511,18 @@ allprojects {
517511
allprojects {
518512
/*
519513
* IntelliJ and Eclipse don't know about the shadow plugin so when we're
520-
* in "IntelliJ mode" or "Eclipse mode" add "runtime" dependencies
521-
* eveywhere where we see a "shadow" dependency which will cause them to
522-
* reference shadowed projects directly rather than rely on the shadowing
523-
* to include them. This is the correct thing for it to do because it
524-
* doesn't run the jar shadowing at all. This isn't needed for the project
514+
* in "IntelliJ mode" or "Eclipse mode" switch "bundle" dependencies into
515+
* regular "compile" dependencies. This isn't needed for the project
525516
* itself because the IDE configuration is done by SourceSets but it is
526517
* *is* needed for projects that depends on the project doing the shadowing.
527518
* Without this they won't properly depend on the shadowed project.
528519
*/
529520
if (isEclipse || isIdea) {
530-
configurations.all { Configuration configuration ->
531-
dependencies.all { Dependency dep ->
532-
if (dep instanceof ProjectDependency) {
533-
if (dep.getTargetConfiguration() == 'shadow') {
534-
configuration.dependencies.add(project.dependencies.project(path: dep.dependencyProject.path, configuration: 'runtime'))
535-
}
536-
}
537-
}
538-
}
521+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
522+
project.afterEvaluate {
523+
project.configurations.compile.extendsFrom project.configurations.bundle
524+
}
525+
}
539526
}
540527
}
541528

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

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

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

931906
private static configurePrecommit(Project project) {
@@ -937,7 +912,7 @@ class BuildPlugin implements Plugin<Project> {
937912
it.group.startsWith('org.elasticsearch') == false
938913
} - project.configurations.compileOnly
939914
project.plugins.withType(ShadowPlugin).whenPluginAdded {
940-
project.dependencyLicenses.dependencies += project.configurations.shadow.fileCollection {
915+
project.dependencyLicenses.dependencies += project.configurations.bundle.fileCollection {
941916
it.group.startsWith('org.elasticsearch') == false
942917
}
943918
}
@@ -948,7 +923,7 @@ class BuildPlugin implements Plugin<Project> {
948923
deps.runtimeConfiguration = project.configurations.runtime
949924
project.plugins.withType(ShadowPlugin).whenPluginAdded {
950925
deps.runtimeConfiguration = project.configurations.create('infoDeps')
951-
deps.runtimeConfiguration.extendsFrom(project.configurations.runtime, project.configurations.shadow)
926+
deps.runtimeConfiguration.extendsFrom(project.configurations.runtime, project.configurations.bundle)
952927
}
953928
deps.compileOnlyConfiguration = project.configurations.compileOnly
954929
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
@@ -155,11 +155,10 @@ public class PluginBuildPlugin extends BuildPlugin {
155155
from pluginMetadata // metadata (eg custom security policy)
156156
/*
157157
* If the plugin is using the shadow plugin then we need to bundle
158-
* "shadow" things rather than the default jar and dependencies so
159-
* we don't hit jar hell.
158+
* that shadow jar.
160159
*/
161160
from { project.plugins.hasPlugin(ShadowPlugin) ? project.shadowJar : project.jar }
162-
from { project.plugins.hasPlugin(ShadowPlugin) ? project.configurations.shadow : project.configurations.runtime - project.configurations.compileOnly }
161+
from project.configurations.runtime - project.configurations.compileOnly
163162
// extra files for the plugin to go into the zip
164163
from('src/main/packaging') // TODO: move all config/bin/_size/etc into packaging
165164
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
}
@@ -310,7 +311,7 @@ setups['farequote_datafeed'] = setups['farequote_job'] + '''
310311
"job_id":"farequote",
311312
"indexes":"farequote"
312313
}
313-
'''
314+
'''
314315
setups['ml_filter_safe_domains'] = '''
315316
- do:
316317
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)