Build: Move shadow customizations into common code (#32014)
Moves the customizations to the build to produce nice shadow jars and javadocs into common build code, mostly BuildPlugin with a little into the root build.gradle file. This means that any project that applies the shadow plugin will automatically be set up just like the high level rest client: * The non-shadow jar will not be built * The shadow jar will not have a "classifier" * Tests will run against the shadow jar * Javadoc will include all of the shadowed classes * Service files in `META-INF/services` will be merged
This commit is contained in:
parent
1c63eb1081
commit
1b97652a4c
|
@ -17,17 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://plugins.gradle.org/m2/'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'elasticsearch.build'
|
||||
|
||||
// order of this section matters, see: https://github.com/johnrengelman/shadow/issues/336
|
||||
|
@ -81,10 +70,6 @@ thirdPartyAudit.excludes = [
|
|||
'org.openjdk.jmh.util.Utils'
|
||||
]
|
||||
|
||||
shadowJar {
|
||||
classifier = 'benchmarks'
|
||||
}
|
||||
|
||||
runShadow {
|
||||
executable = new File(project.runtimeJavaHome, 'bin/java')
|
||||
}
|
||||
|
|
57
build.gradle
57
build.gradle
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
import org.elasticsearch.gradle.BuildPlugin
|
||||
|
@ -303,18 +303,55 @@ subprojects {
|
|||
if (project.plugins.hasPlugin(BuildPlugin)) {
|
||||
String artifactsHost = VersionProperties.elasticsearch.isSnapshot() ? "https://snapshots.elastic.co" : "https://artifacts.elastic.co"
|
||||
Closure sortClosure = { a, b -> b.group <=> a.group }
|
||||
Closure depJavadocClosure = { dep ->
|
||||
if (dep.group != null && dep.group.startsWith('org.elasticsearch')) {
|
||||
Project upstreamProject = dependencyToProject(dep)
|
||||
if (upstreamProject != null) {
|
||||
project.javadoc.dependsOn "${upstreamProject.path}:javadoc"
|
||||
String artifactPath = dep.group.replaceAll('\\.', '/') + '/' + dep.name.replaceAll('\\.', '/') + '/' + dep.version
|
||||
project.javadoc.options.linksOffline artifactsHost + "/javadoc/" + artifactPath, "${upstreamProject.buildDir}/docs/javadoc/"
|
||||
Closure depJavadocClosure = { shadowed, dep ->
|
||||
if (dep.group == null || false == dep.group.startsWith('org.elasticsearch')) {
|
||||
return
|
||||
}
|
||||
Project upstreamProject = dependencyToProject(dep)
|
||||
if (upstreamProject == null) {
|
||||
return
|
||||
}
|
||||
if (shadowed) {
|
||||
/*
|
||||
* Include the source of shadowed upstream projects so we don't
|
||||
* have to publish their javadoc.
|
||||
*/
|
||||
project.evaluationDependsOn(upstreamProject.path)
|
||||
project.javadoc.source += upstreamProject.javadoc.source
|
||||
/*
|
||||
* Do not add those projects to the javadoc classpath because
|
||||
* we are going to resolve them with their source instead.
|
||||
*/
|
||||
project.javadoc.classpath = project.javadoc.classpath.filter { f ->
|
||||
false == upstreamProject.configurations.archives.artifacts.files.files.contains(f)
|
||||
}
|
||||
/*
|
||||
* Instead we need the upstream project's javadoc classpath so
|
||||
* we don't barf on the classes that it references.
|
||||
*/
|
||||
project.javadoc.classpath += upstreamProject.javadoc.classpath
|
||||
} else {
|
||||
// Link to non-shadowed dependant projects
|
||||
project.javadoc.dependsOn "${upstreamProject.path}:javadoc"
|
||||
String artifactPath = dep.group.replaceAll('\\.', '/') + '/' + dep.name.replaceAll('\\.', '/') + '/' + dep.version
|
||||
project.javadoc.options.linksOffline artifactsHost + "/javadoc/" + artifactPath, "${upstreamProject.buildDir}/docs/javadoc/"
|
||||
}
|
||||
}
|
||||
project.configurations.compile.dependencies.findAll().toSorted(sortClosure).each(depJavadocClosure)
|
||||
project.configurations.compileOnly.dependencies.findAll().toSorted(sortClosure).each(depJavadocClosure)
|
||||
boolean hasShadow = project.plugins.hasPlugin(ShadowPlugin)
|
||||
project.configurations.compile.dependencies
|
||||
.findAll()
|
||||
.toSorted(sortClosure)
|
||||
.each({ c -> depJavadocClosure(hasShadow, c) })
|
||||
project.configurations.compileOnly.dependencies
|
||||
.findAll()
|
||||
.toSorted(sortClosure)
|
||||
.each({ c -> depJavadocClosure(hasShadow, c) })
|
||||
if (hasShadow) {
|
||||
project.configurations.shadow.dependencies
|
||||
.findAll()
|
||||
.toSorted(sortClosure)
|
||||
.each({ c -> depJavadocClosure(false, c) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ dependencies {
|
|||
compile 'de.thetaphi:forbiddenapis:2.5'
|
||||
compile 'org.apache.rat:apache-rat:0.11'
|
||||
compile "org.elasticsearch:jna:4.5.1"
|
||||
compile 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
testCompile "junit:junit:${props.getProperty('junit')}"
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.elasticsearch.gradle
|
||||
|
||||
import com.carrotsearch.gradle.junit4.RandomizedTestingTask
|
||||
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import org.eclipse.jgit.lib.Constants
|
||||
import org.eclipse.jgit.lib.RepositoryBuilder
|
||||
|
@ -36,12 +37,14 @@ import org.gradle.api.artifacts.ModuleDependency
|
|||
import org.gradle.api.artifacts.ModuleVersionIdentifier
|
||||
import org.gradle.api.artifacts.ProjectDependency
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.artifacts.SelfResolvingDependency
|
||||
import org.gradle.api.artifacts.dsl.RepositoryHandler
|
||||
import org.gradle.api.execution.TaskExecutionGraph
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
|
||||
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.compile.GroovyCompile
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
|
@ -498,7 +501,41 @@ class BuildPlugin implements Plugin<Project> {
|
|||
}
|
||||
}
|
||||
}
|
||||
project.plugins.withType(ShadowPlugin).whenPluginAdded {
|
||||
project.publishing {
|
||||
publications {
|
||||
nebula(MavenPublication) {
|
||||
artifact project.tasks.shadowJar
|
||||
artifactId = project.archivesBaseName
|
||||
/*
|
||||
* Configure the pom to include the "shadow" as compile dependencies
|
||||
* because that is how we're using them but remove all other dependencies
|
||||
* because they've been shaded into the jar.
|
||||
*/
|
||||
pom.withXml { XmlProvider xml ->
|
||||
Node root = xml.asNode()
|
||||
root.remove(root.dependencies)
|
||||
Node dependenciesNode = root.appendNode('dependencies')
|
||||
project.configurations.shadow.allDependencies.each {
|
||||
if (false == it instanceof SelfResolvingDependency) {
|
||||
Node dependencyNode = dependenciesNode.appendNode('dependency')
|
||||
dependencyNode.appendNode('groupId', it.group)
|
||||
dependencyNode.appendNode('artifactId', it.name)
|
||||
dependencyNode.appendNode('version', it.version)
|
||||
dependencyNode.appendNode('scope', 'compile')
|
||||
}
|
||||
}
|
||||
// Be tidy and remove the element if it is empty
|
||||
if (dependenciesNode.children.empty) {
|
||||
root.remove(dependenciesNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Adds compiler settings to the project */
|
||||
|
@ -660,6 +697,28 @@ class BuildPlugin implements Plugin<Project> {
|
|||
}
|
||||
}
|
||||
}
|
||||
project.plugins.withType(ShadowPlugin).whenPluginAdded {
|
||||
/*
|
||||
* When we use the shadow plugin we entirely replace the
|
||||
* normal jar with the shadow jar so we no longer want to run
|
||||
* the jar task.
|
||||
*/
|
||||
project.tasks.jar.enabled = false
|
||||
project.tasks.shadowJar {
|
||||
/*
|
||||
* Replace the default "shadow" classifier with null
|
||||
* which will leave the classifier off of the file name.
|
||||
*/
|
||||
classifier = null
|
||||
/*
|
||||
* Not all cases need service files merged but it is
|
||||
* better to be safe
|
||||
*/
|
||||
mergeServiceFiles()
|
||||
}
|
||||
// Make sure we assemble the shadow jar
|
||||
project.tasks.assemble.dependsOn project.tasks.shadowJar
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a closure of common configuration shared by unit and integration tests. */
|
||||
|
@ -744,6 +803,18 @@ class BuildPlugin implements Plugin<Project> {
|
|||
}
|
||||
|
||||
exclude '**/*$*.class'
|
||||
|
||||
project.plugins.withType(ShadowPlugin).whenPluginAdded {
|
||||
/*
|
||||
* If we make a shaded jar we test against it.
|
||||
*/
|
||||
classpath -= project.tasks.compileJava.outputs.files
|
||||
classpath -= project.configurations.compile
|
||||
classpath -= project.configurations.runtime
|
||||
classpath += project.configurations.shadow
|
||||
classpath += project.tasks.shadowJar.outputs.files
|
||||
dependsOn project.tasks.shadowJar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -766,7 +837,26 @@ class BuildPlugin implements Plugin<Project> {
|
|||
additionalTest.dependsOn(project.tasks.testClasses)
|
||||
test.dependsOn(additionalTest)
|
||||
});
|
||||
return test
|
||||
|
||||
project.plugins.withType(ShadowPlugin).whenPluginAdded {
|
||||
/*
|
||||
* We need somewhere to configure dependencies that we don't wish
|
||||
* to shade into the jar. The shadow plugin creates a "shadow"
|
||||
* configuration which is *almost* exactly that. It is never
|
||||
* bundled into the shaded jar but is used for main source
|
||||
* compilation. Unfortunately, by default it is not used for
|
||||
* *test* source compilation and isn't used in tests at all. This
|
||||
* change makes it available for test compilation.
|
||||
*
|
||||
* Note that this isn't going to work properly with qa projects
|
||||
* but they have no business applying the shadow plugin in the
|
||||
* firstplace.
|
||||
*/
|
||||
SourceSet testSourceSet = project.sourceSets.findByName('test')
|
||||
if (testSourceSet != null) {
|
||||
testSourceSet.compileClasspath += project.configurations.shadow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static configurePrecommit(Project project) {
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
*/
|
||||
package org.elasticsearch.gradle.plugin
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
|
||||
import nebula.plugin.info.scm.ScmInfoPlugin
|
||||
import org.elasticsearch.gradle.BuildPlugin
|
||||
import org.elasticsearch.gradle.NoticeTask
|
||||
import org.elasticsearch.gradle.test.RestIntegTestTask
|
||||
import org.elasticsearch.gradle.test.RunTask
|
||||
import org.gradle.api.InvalidUserDataException
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
|
@ -46,6 +48,18 @@ public class PluginBuildPlugin extends BuildPlugin {
|
|||
@Override
|
||||
public void apply(Project project) {
|
||||
super.apply(project)
|
||||
project.plugins.withType(ShadowPlugin).whenPluginAdded {
|
||||
/*
|
||||
* We've not tested these plugins together and we're fairly sure
|
||||
* they aren't going to work properly as is *and* we're not really
|
||||
* sure *why* you'd want to shade stuff in plugins. So we throw an
|
||||
* exception here to make you come and read this comment. If you
|
||||
* have a need for shadow while building plugins then know that you
|
||||
* are probably going to have to fight with gradle for a while....
|
||||
*/
|
||||
throw new InvalidUserDataException('elasticsearch.esplugin is not '
|
||||
+ 'compatible with com.github.johnrengelman.shadow');
|
||||
}
|
||||
configureDependencies(project)
|
||||
// this afterEvaluate must happen before the afterEvaluate added by integTest creation,
|
||||
// so that the file name resolution for installing the plugin will be setup
|
||||
|
|
|
@ -17,18 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://plugins.gradle.org/m2/'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
apply plugin: 'elasticsearch.build'
|
||||
// build an uberjar with all benchmarks
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
|
|
@ -21,17 +21,6 @@ import org.elasticsearch.gradle.precommit.PrecommitTasks
|
|||
import org.elasticsearch.gradle.test.RestIntegTestTask
|
||||
import org.gradle.api.internal.provider.Providers
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://plugins.gradle.org/m2/'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'elasticsearch.build'
|
||||
apply plugin: 'elasticsearch.rest-test'
|
||||
apply plugin: 'nebula.maven-base-publish'
|
||||
|
@ -45,49 +34,6 @@ archivesBaseName = 'elasticsearch-rest-high-level-client'
|
|||
Task copyRestSpec = RestIntegTestTask.createCopyRestSpecTask(project, Providers.FALSE)
|
||||
test.dependsOn(copyRestSpec)
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
nebula(MavenPublication) {
|
||||
artifact shadowJar
|
||||
artifactId = archivesBaseName
|
||||
/*
|
||||
* Configure the pom to include the "shadow" as compile dependencies
|
||||
* because that is how we're using them but remove all other dependencies
|
||||
* because they've been shaded into the jar.
|
||||
*/
|
||||
pom.withXml { XmlProvider xml ->
|
||||
Node root = xml.asNode()
|
||||
root.remove(root.dependencies)
|
||||
Node dependenciesNode = root.appendNode('dependencies')
|
||||
project.configurations.shadow.allDependencies.each {
|
||||
if (false == it instanceof SelfResolvingDependency) {
|
||||
Node dependencyNode = dependenciesNode.appendNode('dependency')
|
||||
dependencyNode.appendNode('groupId', it.group)
|
||||
dependencyNode.appendNode('artifactId', it.name)
|
||||
dependencyNode.appendNode('version', it.version)
|
||||
dependencyNode.appendNode('scope', 'compile')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We need somewhere to configure dependencies that we don't wish to shade
|
||||
* into the high level REST client. The shadow plugin creates a "shadow"
|
||||
* configuration which is *almost* exactly that. It is never bundled into
|
||||
* the shaded jar but is used for main source compilation. Unfortunately,
|
||||
* by default it is not used for *test* source compilation and isn't used
|
||||
* in tests at all. This change makes it available for test compilation.
|
||||
* A change below makes it available for testing.
|
||||
*/
|
||||
sourceSets {
|
||||
test {
|
||||
compileClasspath += configurations.shadow
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/*
|
||||
* Everything in the "shadow" configuration is *not* copied into the
|
||||
|
@ -124,48 +70,3 @@ forbiddenApisMain {
|
|||
signaturesURLs += [PrecommitTasks.getResource('/forbidden/http-signatures.txt')]
|
||||
signaturesURLs += [file('src/main/resources/forbidden/rest-high-level-signatures.txt').toURI().toURL()]
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
classifier = null
|
||||
mergeServiceFiles()
|
||||
}
|
||||
|
||||
// We don't need normal jar, we use shadow jar instead
|
||||
jar.enabled = false
|
||||
assemble.dependsOn shadowJar
|
||||
|
||||
javadoc {
|
||||
/*
|
||||
* Bundle all of the javadoc from all of the shaded projects into this one
|
||||
* so we don't *have* to publish javadoc for all of the "client" jars.
|
||||
*/
|
||||
configurations.compile.dependencies.all { Dependency dep ->
|
||||
Project p = dependencyToProject(dep)
|
||||
if (p != null) {
|
||||
evaluationDependsOn(p.path)
|
||||
source += p.sourceSets.main.allJava
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the jar for testing so we have tests of the bundled jar.
|
||||
* Use the "shadow" configuration for testing because we need things
|
||||
* in it.
|
||||
*/
|
||||
test {
|
||||
classpath -= compileJava.outputs.files
|
||||
classpath -= configurations.compile
|
||||
classpath -= configurations.runtime
|
||||
classpath += configurations.shadow
|
||||
classpath += shadowJar.outputs.files
|
||||
dependsOn shadowJar
|
||||
}
|
||||
integTestRunner {
|
||||
classpath -= compileJava.outputs.files
|
||||
classpath -= configurations.compile
|
||||
classpath -= configurations.runtime
|
||||
classpath += configurations.shadow
|
||||
classpath += shadowJar.outputs.files
|
||||
dependsOn shadowJar
|
||||
}
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://plugins.gradle.org/m2/'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'elasticsearch.build'
|
||||
apply plugin: 'nebula.maven-base-publish'
|
||||
apply plugin: 'nebula.maven-scm'
|
||||
|
@ -49,7 +37,6 @@ dependencyLicenses {
|
|||
}
|
||||
|
||||
shadowJar {
|
||||
classifier = null
|
||||
relocate 'com.fasterxml', 'org.elasticsearch.fasterxml'
|
||||
}
|
||||
|
||||
|
@ -70,26 +57,3 @@ artifacts {
|
|||
nodeps nodepsJar
|
||||
archives shadowJar
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
nebula(MavenPublication) {
|
||||
artifact shadowJar
|
||||
pom.withXml {
|
||||
// Nebula is mistakenly including all dependencies that are already shadowed into the shadow jar
|
||||
asNode().remove(asNode().dependencies)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assemble.dependsOn shadowJar
|
||||
|
||||
// Use the jar for testing so the tests are more "real"
|
||||
test {
|
||||
classpath -= compileJava.outputs.files
|
||||
classpath -= configurations.compile
|
||||
classpath -= configurations.runtime
|
||||
classpath += shadowJar.outputs.files
|
||||
dependsOn shadowJar
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue