Browse Source

Move publishing configuration to a separate plugin (#56727)

This is another part of the breakup of the massive BuildPlugin. This PR
moves the code for configuring publications to a separate plugin. Most
of the time these publications are jar files, but this also supports the
zip publication we have for integ tests.
Ryan Ernst 5 years ago
parent
commit
c0ee68b0a0

+ 1 - 1
buildSrc/build.gradle

@@ -159,7 +159,7 @@ if (project == rootProject) {
 // to enforce precommit checks like forbidden apis, as well as setup publishing
 if (project != rootProject) {
   apply plugin: 'elasticsearch.build'
-  apply plugin: 'nebula.maven-base-publish'
+  apply plugin: 'elasticsearch.publish'
 
   // groovydoc succeeds, but has some weird internal exception...
   groovydoc.enabled = false

+ 1 - 205
buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

@@ -110,8 +110,7 @@ class BuildPlugin implements Plugin<Project> {
             )
         }
         project.pluginManager.apply('elasticsearch.java')
-        configureJars(project)
-        configureJarManifest(project)
+        project.pluginManager.apply('elasticsearch.publish')
 
         // apply global test task failure listener
         project.rootProject.pluginManager.apply(TestFailureReportingPlugin)
@@ -120,9 +119,6 @@ class BuildPlugin implements Plugin<Project> {
 
         configureRepositories(project)
         project.extensions.getByType(ExtraPropertiesExtension).set('versions', VersionProperties.versions)
-        configureJavadoc(project)
-        configureSourcesJar(project)
-        configurePomGeneration(project)
         configurePrecommit(project)
         configureDependenciesInfo(project)
         configureFips140(project)
@@ -288,206 +284,6 @@ class BuildPlugin implements Plugin<Project> {
         }
     }
 
-    /**Configuration generation of maven poms. */
-    static void configurePomGeneration(Project project) {
-        project.plugins.withType(MavenPublishPlugin).whenPluginAdded {
-            TaskProvider generatePomTask = project.tasks.register("generatePom") { Task task ->
-                task.dependsOn 'generatePomFileForNebulaPublication'
-            }
-
-            maybeConfigure(project.tasks, LifecycleBasePlugin.ASSEMBLE_TASK_NAME) { assemble ->
-                assemble.dependsOn(generatePomTask)
-            }
-
-            project.tasks.withType(GenerateMavenPom).configureEach({ GenerateMavenPom pomTask ->
-                pomTask.destination = { "${project.buildDir}/distributions/${project.convention.getPlugin(BasePluginConvention).archivesBaseName}-${project.version}.pom" }
-            } as Action<GenerateMavenPom>)
-
-            PublishingExtension publishing = project.extensions.getByType(PublishingExtension)
-
-            project.pluginManager.withPlugin('com.github.johnrengelman.shadow') {
-                MavenPublication publication = publishing.publications.maybeCreate('shadow', MavenPublication)
-                ShadowExtension shadow = project.extensions.getByType(ShadowExtension)
-                shadow.component(publication)
-                // Workaround for https://github.com/johnrengelman/shadow/issues/334
-                // Here we manually add any project dependencies in the "shadow" configuration to our generated POM
-                publication.pom.withXml(this.&addScmInfo)
-                publication.pom.withXml { xml ->
-                    Node root = xml.asNode()
-                    root.appendNode('name', project.name)
-                    root.appendNode('description', project.description)
-                    Node dependenciesNode = (root.get('dependencies') as NodeList).get(0) as Node
-                    project.configurations.getByName(ShadowBasePlugin.CONFIGURATION_NAME).allDependencies.each { dependency ->
-                        if (dependency instanceof ProjectDependency) {
-                            def dependencyNode = dependenciesNode.appendNode('dependency')
-                            dependencyNode.appendNode('groupId', dependency.group)
-                            dependencyNode.appendNode('artifactId', dependency.getDependencyProject().convention.getPlugin(BasePluginConvention).archivesBaseName)
-                            dependencyNode.appendNode('version', dependency.version)
-                            dependencyNode.appendNode('scope', 'compile')
-                        }
-                    }
-                }
-                generatePomTask.configure({ Task t -> t.dependsOn = ['generatePomFileForShadowPublication'] } as Action<Task>)
-
-                // have to defer this until archivesBaseName is set
-                project.afterEvaluate {
-                    publication.artifactId = project.convention.getPlugin(BasePluginConvention).archivesBaseName
-                }
-            }
-        }
-
-        // Add git origin info to generated POM files
-        project.pluginManager.withPlugin('nebula.maven-base-publish') {
-            PublishingExtension publishing = project.extensions.getByType(PublishingExtension)
-            MavenPublication nebulaPublication = (MavenPublication) publishing.publications.getByName('nebula')
-            nebulaPublication.pom.withXml(this.&addScmInfo)
-
-            // have to defer this until archivesBaseName is set
-            project.afterEvaluate {
-                nebulaPublication.artifactId = project.convention.getPlugin(BasePluginConvention).archivesBaseName
-            }
-        }
-    }
-
-    private static void addScmInfo(XmlProvider xml) {
-        Node root = xml.asNode()
-        root.appendNode('url', PluginBuildPlugin.urlFromOrigin(BuildParams.gitOrigin))
-        Node scmNode = root.appendNode('scm')
-        scmNode.appendNode('url', BuildParams.gitOrigin)
-    }
-
-    static void configureJavadoc(Project project) {
-        // remove compiled classes from the Javadoc classpath: http://mail.openjdk.java.net/pipermail/javadoc-dev/2018-January/000400.html
-        final List<File> classes = new ArrayList<>()
-        project.tasks.withType(JavaCompile).configureEach { JavaCompile javaCompile ->
-            classes.add(javaCompile.destinationDir)
-        }
-        project.tasks.withType(Javadoc).configureEach { Javadoc javadoc ->
-            // only explicitly set javadoc executable if compiler JDK is different from Gradle
-            // this ensures better cacheability as setting ths input to an absolute path breaks portability
-            if (Files.isSameFile(BuildParams.compilerJavaHome.toPath(), Jvm.current().getJavaHome().toPath()) == false) {
-                javadoc.executable = new File(BuildParams.compilerJavaHome, 'bin/javadoc')
-            }
-            javadoc.classpath = javadoc.getClasspath().filter { f ->
-                return classes.contains(f) == false
-            }
-            /*
-             * Generate docs using html5 to suppress a warning from `javadoc`
-             * that the default will change to html5 in the future.
-             */
-            (javadoc.options as CoreJavadocOptions).addBooleanOption('html5', true)
-        }
-        // ensure javadoc task is run with 'check'
-        project.pluginManager.withPlugin('lifecycle-base') {
-            project.tasks.named(LifecycleBasePlugin.CHECK_TASK_NAME).configure { it.dependsOn(project.tasks.withType(Javadoc)) }
-        }
-        configureJavadocJar(project)
-    }
-
-    /** Adds a javadocJar task to generate a jar containing javadocs. */
-    static void configureJavadocJar(Project project) {
-        TaskProvider<Jar> javadocJarTask = project.tasks.register('javadocJar', Jar, { Jar jar ->
-            jar.archiveClassifier.set('javadoc')
-            jar.group = 'build'
-            jar.description = 'Assembles a jar containing javadocs.'
-            jar.from(project.tasks.named(JavaPlugin.JAVADOC_TASK_NAME))
-        } as Action<Jar>)
-        maybeConfigure(project.tasks, BasePlugin.ASSEMBLE_TASK_NAME) { Task t ->
-            t.dependsOn(javadocJarTask)
-        }
-    }
-
-    static void configureSourcesJar(Project project) {
-        TaskProvider<Jar> sourcesJarTask = project.tasks.register('sourcesJar', Jar, { Jar jar ->
-            jar.archiveClassifier.set('sources')
-            jar.group = 'build'
-            jar.description = 'Assembles a jar containing source files.'
-            jar.from(project.extensions.getByType(SourceSetContainer).getByName(SourceSet.MAIN_SOURCE_SET_NAME).allSource)
-        } as Action<Jar>)
-        maybeConfigure(project.tasks, BasePlugin.ASSEMBLE_TASK_NAME) { Task t ->
-            t.dependsOn(sourcesJarTask)
-        }
-    }
-
-    /** Adds additional manifest info to jars */
-    static void configureJars(Project project) {
-        ExtraPropertiesExtension ext = project.extensions.getByType(ExtraPropertiesExtension)
-        ext.set('licenseFile',  null)
-        ext.set('noticeFile', null)
-        project.tasks.withType(Jar).configureEach { Jar jarTask ->
-            // we put all our distributable files under distributions
-            jarTask.destinationDirectory.set(new File(project.buildDir, 'distributions'))
-            // fixup the jar manifest
-            jarTask.doFirst {
-                // this doFirst is added before the info plugin, therefore it will run
-                // after the doFirst added by the info plugin, and we can override attributes
-                JavaVersion compilerJavaVersion = BuildParams.compilerJavaVersion
-                jarTask.manifest.attributes(
-                        'Build-Date': BuildParams.buildDate,
-                        'Build-Java-Version': BuildParams.compilerJavaVersion)
-            }
-        }
-        // add license/notice files
-        project.afterEvaluate {
-            project.tasks.withType(Jar).configureEach { Jar jarTask ->
-                if (ext.has('licenseFile') == false || ext.get('licenseFile') == null || ext.has('noticeFile') == false || ext.get('noticeFile') == null) {
-                    throw new GradleException("Must specify license and notice file for project ${project.path}")
-                }
-
-                File licenseFile = ext.get('licenseFile') as File
-                File noticeFile = ext.get('noticeFile') as File
-
-                jarTask.metaInf { CopySpec spec ->
-                    spec.from(licenseFile.parent) { CopySpec from ->
-                        from.include licenseFile.name
-                        from.rename { 'LICENSE.txt' }
-                    }
-                    spec.from(noticeFile.parent) { CopySpec from ->
-                        from.include noticeFile.name
-                        from.rename { 'NOTICE.txt' }
-                    }
-                }
-            }
-        }
-        project.pluginManager.withPlugin('com.github.johnrengelman.shadow') {
-            project.tasks.getByName(ShadowJavaPlugin.SHADOW_JAR_TASK_NAME).configure { ShadowJar shadowJar ->
-                /*
-                 * Replace the default "-all" classifier with null
-                 * which will leave the classifier off of the file name.
-                 */
-                shadowJar.archiveClassifier.set((String) null)
-                /*
-                 * Not all cases need service files merged but it is
-                 * better to be safe
-                 */
-                shadowJar.mergeServiceFiles()
-            }
-            // Add "original" classifier to the non-shadowed JAR to distinguish it from the shadow JAR
-            project.tasks.getByName(JavaPlugin.JAR_TASK_NAME).configure { Jar jar ->
-                jar.archiveClassifier.set('original')
-            }
-            // Make sure we assemble the shadow jar
-            project.tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure { Task task ->
-               task.dependsOn 'shadowJar'
-            }
-        }
-    }
-
-    static void configureJarManifest(Project project) {
-        project.pluginManager.apply('nebula.info-broker')
-        project.pluginManager.apply('nebula.info-basic')
-        project.pluginManager.apply('nebula.info-java')
-        project.pluginManager.apply('nebula.info-jar')
-
-        project.plugins.withId('nebula.info-broker') { InfoBrokerPlugin manifestPlugin ->
-            manifestPlugin.add('Module-Origin') { BuildParams.gitOrigin }
-            manifestPlugin.add('Change') { BuildParams.gitRevision }
-            manifestPlugin.add('X-Compile-Elasticsearch-Version') { VersionProperties.elasticsearch }
-            manifestPlugin.add('X-Compile-Lucene-Version') { VersionProperties.lucene }
-            manifestPlugin.add('X-Compile-Elasticsearch-Snapshot') { VersionProperties.isElasticsearchSnapshot() }
-        }
-    }
-
     private static configurePrecommit(Project project) {
         TaskProvider precommit = PrecommitTasks.create(project, true)
         project.tasks.named(LifecycleBasePlugin.CHECK_TASK_NAME).configure { it.dependsOn(precommit) }

+ 0 - 18
buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy

@@ -226,24 +226,6 @@ class PluginBuildPlugin implements Plugin<Project> {
         project.artifacts.add('zip', bundle)
     }
 
-    static final Pattern GIT_PATTERN = Pattern.compile(/git@([^:]+):([^\.]+)\.git/)
-
-    /** Find the reponame. */
-    static String urlFromOrigin(String origin) {
-        if (origin == null) {
-            return null // best effort, the url doesnt really matter, it is just required by maven central
-        }
-        if (origin.startsWith('https')) {
-            return origin
-        }
-        Matcher matcher = GIT_PATTERN.matcher(origin)
-        if (matcher.matches()) {
-            return "https://${matcher.group(1)}/${matcher.group(2)}"
-        } else {
-            return origin // best effort, the url doesnt really matter, it is just required by maven central
-        }
-    }
-
     /** Configure the pom for the main jar of this plugin */
 
     protected static void addNoticeGeneration(Project project, PluginPropertiesExtension extension) {

+ 135 - 0
buildSrc/src/main/java/org/elasticsearch/gradle/ElasticsearchJavaPlugin.java

@@ -20,6 +20,8 @@
 package org.elasticsearch.gradle;
 
 import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin;
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar;
+import nebula.plugin.info.InfoBrokerPlugin;
 import org.elasticsearch.gradle.info.BuildParams;
 import org.elasticsearch.gradle.info.GlobalBuildInfoPlugin;
 import org.elasticsearch.gradle.test.ErrorReportingTestListener;
@@ -35,24 +37,34 @@ import org.gradle.api.artifacts.ModuleDependency;
 import org.gradle.api.artifacts.ProjectDependency;
 import org.gradle.api.artifacts.ResolutionStrategy;
 import org.gradle.api.file.FileCollection;
+import org.gradle.api.plugins.BasePlugin;
+import org.gradle.api.plugins.ExtraPropertiesExtension;
 import org.gradle.api.plugins.JavaPlugin;
 import org.gradle.api.plugins.JavaPluginExtension;
 import org.gradle.api.tasks.SourceSet;
 import org.gradle.api.tasks.SourceSetContainer;
+import org.gradle.api.tasks.bundling.Jar;
 import org.gradle.api.tasks.compile.CompileOptions;
 import org.gradle.api.tasks.compile.GroovyCompile;
 import org.gradle.api.tasks.compile.JavaCompile;
+import org.gradle.api.tasks.javadoc.Javadoc;
 import org.gradle.api.tasks.testing.Test;
+import org.gradle.external.javadoc.CoreJavadocOptions;
 import org.gradle.internal.jvm.Jvm;
+import org.gradle.language.base.plugins.LifecycleBasePlugin;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
 import static org.elasticsearch.gradle.util.GradleUtils.maybeConfigure;
+import static org.elasticsearch.gradle.util.Util.toStringable;
 
 /**
  * A wrapper around Gradle's Java plugin that applies our common configuration.
@@ -68,6 +80,9 @@ public class ElasticsearchJavaPlugin implements Plugin<Project> {
         configureCompile(project);
         configureInputNormalization(project);
         configureTestTasks(project);
+        configureJars(project);
+        configureJarManifest(project);
+        configureJavadoc(project);
     }
 
     /**
@@ -377,4 +392,124 @@ public class ElasticsearchJavaPlugin implements Plugin<Project> {
             });
         });
     }
+
+    /** Adds additional manifest info to jars */
+    static void configureJars(Project project) {
+        ExtraPropertiesExtension ext = project.getExtensions().getExtraProperties();
+        ext.set("licenseFile", null);
+        ext.set("noticeFile", null);
+        project.getTasks()
+            .withType(Jar.class)
+            .configureEach(
+                jarTask -> {
+                    // we put all our distributable files under distributions
+                    jarTask.getDestinationDirectory().set(new File(project.getBuildDir(), "distributions"));
+                    // fixup the jar manifest
+                    jarTask.doFirst(
+                        t -> {
+                            // this doFirst is added before the info plugin, therefore it will run
+                            // after the doFirst added by the info plugin, and we can override attributes
+                            jarTask.getManifest()
+                                .attributes(
+                                    Map.of(
+                                        "Build-Date",
+                                        BuildParams.getBuildDate(),
+                                        "Build-Java-Version",
+                                        BuildParams.getCompilerJavaVersion()
+                                    )
+                                );
+                        }
+                    );
+                }
+            );
+        // add license/notice files
+        project.afterEvaluate(p -> project.getTasks().withType(Jar.class).configureEach(jarTask -> {
+            File licenseFile = (File) ext.get("licenseFile");
+            File noticeFile = (File) ext.get("noticeFile");
+            if (licenseFile == null || noticeFile == null) {
+                throw new GradleException("Must specify license and notice file for project");
+            }
+
+            jarTask.metaInf(spec -> {
+                spec.from(licenseFile.getParent(), from -> {
+                    from.include(licenseFile.getName());
+                    from.rename(s -> "LICENSE.txt");
+                });
+                spec.from(noticeFile.getParent(), from -> {
+                    from.include(noticeFile.getName());
+                    from.rename(s -> "NOTICE.txt");
+                });
+            });
+        }));
+        project.getPluginManager().withPlugin("com.github.johnrengelman.shadow", p -> {
+            project.getTasks()
+                .withType(ShadowJar.class)
+                .configureEach(
+                    shadowJar -> {
+                        /*
+                         * Replace the default "-all" classifier with null
+                         * which will leave the classifier off of the file name.
+                         */
+                        shadowJar.getArchiveClassifier().set((String) null);
+                        /*
+                         * Not all cases need service files merged but it is
+                         * better to be safe
+                         */
+                        shadowJar.mergeServiceFiles();
+                    }
+                );
+            // Add "original" classifier to the non-shadowed JAR to distinguish it from the shadow JAR
+            project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class).configure(jar -> jar.getArchiveClassifier().set("original"));
+            // Make sure we assemble the shadow jar
+            project.getTasks().named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn("shadowJar"));
+        });
+    }
+
+    private static void configureJarManifest(Project project) {
+        project.getPlugins().withType(InfoBrokerPlugin.class).whenPluginAdded(manifestPlugin -> {
+            manifestPlugin.add("Module-Origin", toStringable(BuildParams::getGitOrigin));
+            manifestPlugin.add("Change", toStringable(BuildParams::getGitRevision));
+            manifestPlugin.add("X-Compile-Elasticsearch-Version", toStringable(VersionProperties::getElasticsearch));
+            manifestPlugin.add("X-Compile-Lucene-Version", toStringable(VersionProperties::getLucene));
+            manifestPlugin.add(
+                "X-Compile-Elasticsearch-Snapshot",
+                toStringable(() -> Boolean.toString(VersionProperties.isElasticsearchSnapshot()))
+            );
+        });
+
+        project.getPluginManager().apply("nebula.info-broker");
+        project.getPluginManager().apply("nebula.info-basic");
+        project.getPluginManager().apply("nebula.info-java");
+        project.getPluginManager().apply("nebula.info-jar");
+    }
+
+    private static void configureJavadoc(Project project) {
+        project.getTasks().withType(Javadoc.class).configureEach(javadoc -> {
+            // only explicitly set javadoc executable if compiler JDK is different from Gradle
+            // this ensures better cacheability as setting ths input to an absolute path breaks portability
+            Path compilerJvm = BuildParams.getCompilerJavaHome().toPath();
+            Path gradleJvm = Jvm.current().getJavaHome().toPath();
+            try {
+                if (Files.isSameFile(compilerJvm, gradleJvm) == false) {
+                    javadoc.setExecutable(compilerJvm.resolve("bin/javadoc").toString());
+                }
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+
+            // remove compiled classes from the Javadoc classpath:
+            // http://mail.openjdk.java.net/pipermail/javadoc-dev/2018-January/000400.html
+            javadoc.setClasspath(Util.getJavaMainSourceSet(project).get().getCompileClasspath());
+            /*
+             * Generate docs using html5 to suppress a warning from `javadoc`
+             * that the default will change to html5 in the future.
+             */
+            CoreJavadocOptions javadocOptions = (CoreJavadocOptions) javadoc.getOptions();
+            javadocOptions.addBooleanOption("html5", true);
+        });
+        // ensure javadoc task is run with 'check'
+        project.getTasks()
+            .named(LifecycleBasePlugin.CHECK_TASK_NAME)
+            .configure(t -> t.dependsOn(project.getTasks().withType(Javadoc.class)));
+    }
 }

+ 157 - 0
buildSrc/src/main/java/org/elasticsearch/gradle/PublishPlugin.java

@@ -0,0 +1,157 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.gradle;
+
+import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin;
+import com.github.jengelman.gradle.plugins.shadow.ShadowExtension;
+import groovy.util.Node;
+import groovy.util.NodeList;
+import org.elasticsearch.gradle.info.BuildParams;
+import org.elasticsearch.gradle.util.Util;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.XmlProvider;
+import org.gradle.api.artifacts.ProjectDependency;
+import org.gradle.api.plugins.BasePlugin;
+import org.gradle.api.plugins.BasePluginConvention;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.publish.PublishingExtension;
+import org.gradle.api.publish.maven.MavenPublication;
+import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
+import org.gradle.api.tasks.SourceSet;
+import org.gradle.api.tasks.TaskProvider;
+import org.gradle.api.tasks.bundling.Jar;
+import org.gradle.language.base.plugins.LifecycleBasePlugin;
+
+import java.util.concurrent.Callable;
+
+import static org.elasticsearch.gradle.util.GradleUtils.maybeConfigure;
+
+public class PublishPlugin implements Plugin<Project> {
+
+    @Override
+    public void apply(Project project) {
+        project.getPluginManager().apply("nebula.maven-base-publish");
+
+        configureJavadocJar(project);
+        configureSourcesJar(project);
+        configurePomGeneration(project);
+    }
+
+    private static String getArchivesBaseName(Project project) {
+        return project.getConvention().getPlugin(BasePluginConvention.class).getArchivesBaseName();
+    }
+
+    /**Configuration generation of maven poms. */
+    private static void configurePomGeneration(Project project) {
+
+        TaskProvider<Task> generatePomTask = project.getTasks().register("generatePom");
+
+        maybeConfigure(project.getTasks(), LifecycleBasePlugin.ASSEMBLE_TASK_NAME, assemble -> assemble.dependsOn(generatePomTask));
+
+        project.getTasks().withType(GenerateMavenPom.class).configureEach(pomTask -> pomTask.setDestination(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                return String.format(
+                    "%s/distributions/%s-%s.pom",
+                    project.getBuildDir(),
+                    getArchivesBaseName(project),
+                    project.getVersion()
+                );
+            }
+        }));
+
+        PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
+
+        project.getPluginManager().withPlugin("com.github.johnrengelman.shadow", plugin -> {
+            MavenPublication publication = publishing.getPublications().maybeCreate("shadow", MavenPublication.class);
+            ShadowExtension shadow = project.getExtensions().getByType(ShadowExtension.class);
+            shadow.component(publication);
+            // Workaround for https://github.com/johnrengelman/shadow/issues/334
+            // Here we manually add any project dependencies in the "shadow" configuration to our generated POM
+            publication.getPom().withXml(xml -> {
+                Node root = xml.asNode();
+                root.appendNode("name", project.getName());
+                root.appendNode("description", project.getDescription());
+                Node dependenciesNode = (Node) ((NodeList) root.get("dependencies")).get(0);
+                project.getConfigurations().getByName(ShadowBasePlugin.getCONFIGURATION_NAME()).getAllDependencies().all(dependency -> {
+                    if (dependency instanceof ProjectDependency) {
+                        Node dependencyNode = dependenciesNode.appendNode("dependency");
+                        dependencyNode.appendNode("groupId", dependency.getGroup());
+                        ProjectDependency projectDependency = (ProjectDependency) dependency;
+                        String artifactId = getArchivesBaseName(projectDependency.getDependencyProject());
+                        dependencyNode.appendNode("artifactId", artifactId);
+                        dependencyNode.appendNode("version", dependency.getVersion());
+                        dependencyNode.appendNode("scope", "compile");
+                    }
+                });
+            });
+        });
+
+        // Add git origin info to generated POM files
+        publishing.getPublications().withType(MavenPublication.class, publication -> {
+            publication.getPom().withXml(PublishPlugin::addScmInfo);
+
+            // have to defer this until archivesBaseName is set
+            project.afterEvaluate(p -> publication.setArtifactId(getArchivesBaseName(project)));
+
+            generatePomTask.configure(
+                t -> t.dependsOn(String.format("generatePomFileFor%sPublication", Util.capitalize(publication.getName())))
+            );
+        });
+
+    }
+
+    private static void addScmInfo(XmlProvider xml) {
+        Node root = xml.asNode();
+        root.appendNode("url", Util.urlFromOrigin(BuildParams.getGitOrigin()));
+        Node scmNode = root.appendNode("scm");
+        scmNode.appendNode("url", BuildParams.getGitOrigin());
+    }
+
+    /** Adds a javadocJar task to generate a jar containing javadocs. */
+    private static void configureJavadocJar(Project project) {
+        project.getPlugins().withId("elasticsearch.java", p -> {
+            TaskProvider<Jar> javadocJarTask = project.getTasks().register("javadocJar", Jar.class);
+            javadocJarTask.configure(jar -> {
+                jar.getArchiveClassifier().set("javadoc");
+                jar.setGroup("build");
+                jar.setDescription("Assembles a jar containing javadocs.");
+                jar.from(project.getTasks().named(JavaPlugin.JAVADOC_TASK_NAME));
+            });
+            maybeConfigure(project.getTasks(), BasePlugin.ASSEMBLE_TASK_NAME, t -> t.dependsOn(javadocJarTask));
+        });
+    }
+
+    static void configureSourcesJar(Project project) {
+        project.getPlugins().withId("elasticsearch.java", p -> {
+            TaskProvider<Jar> sourcesJarTask = project.getTasks().register("sourcesJar", Jar.class);
+            sourcesJarTask.configure(jar -> {
+                jar.getArchiveClassifier().set("sources");
+                jar.setGroup("build");
+                jar.setDescription("Assembles a jar containing source files.");
+                SourceSet mainSourceSet = Util.getJavaMainSourceSet(project).get();
+                jar.from(mainSourceSet.getAllSource());
+            });
+            maybeConfigure(project.getTasks(), BasePlugin.ASSEMBLE_TASK_NAME, t -> t.dependsOn(sourcesJarTask));
+        });
+    }
+}

+ 1 - 2
buildSrc/src/main/java/org/elasticsearch/gradle/precommit/PomValidationPlugin.java

@@ -23,7 +23,6 @@ import org.elasticsearch.gradle.util.Util;
 import org.gradle.api.Plugin;
 import org.gradle.api.Project;
 import org.gradle.api.publish.PublishingExtension;
-import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
 import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
 import org.gradle.api.tasks.TaskProvider;
 
@@ -34,7 +33,7 @@ public class PomValidationPlugin implements Plugin<Project> {
 
     @Override
     public void apply(Project project) {
-        project.getPlugins().withType(MavenPublishPlugin.class).whenPluginAdded(p -> {
+        project.getPluginManager().withPlugin("maven-publish", p -> {
             PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
             publishing.getPublications().all(publication -> {
                 String publicationName = Util.capitalize(publication.getName());

+ 30 - 0
buildSrc/src/main/java/org/elasticsearch/gradle/util/Util.java

@@ -37,6 +37,9 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Locale;
 import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class Util {
 
@@ -144,4 +147,31 @@ public class Util {
             ? Optional.empty()
             : Optional.ofNullable(GradleUtils.getJavaSourceSets(project).findByName(SourceSet.MAIN_SOURCE_SET_NAME));
     }
+
+    static final Pattern GIT_PATTERN = Pattern.compile("git@([^:]+):([^\\.]+)\\.git");
+
+    /** Find the reponame. */
+    public static String urlFromOrigin(String origin) {
+        if (origin == null) {
+            return null; // best effort, the url doesnt really matter, it is just required by maven central
+        }
+        if (origin.startsWith("https")) {
+            return origin;
+        }
+        Matcher matcher = GIT_PATTERN.matcher(origin);
+        if (matcher.matches()) {
+            return String.format("https://%s/%s", matcher.group(1), matcher.group(2));
+        } else {
+            return origin; // best effort, the url doesnt really matter, it is just required by maven central
+        }
+    }
+
+    public static Object toStringable(Supplier<String> getter) {
+        return new Object() {
+            @Override
+            public String toString() {
+                return getter.get();
+            }
+        };
+    }
 }

+ 1 - 0
buildSrc/src/main/resources/META-INF/gradle-plugins/elasticsearch.publish.properties

@@ -0,0 +1 @@
+implementation-class=org.elasticsearch.gradle.PublishPlugin

+ 3 - 0
buildSrc/src/testKit/elasticsearch.build/build.gradle

@@ -26,6 +26,9 @@ test.enabled = false
 // This requires an additional Jar not part of build-tools
 loggerUsageCheck.enabled = false
 
+// TODO: shouldn't be part of BuildPlugin, should be tested separately
+validateNebulaPom.enabled = false
+
 task hello {
   doFirst {
     println "build plugin can be applied"

+ 1 - 1
client/rest-high-level/build.gradle

@@ -22,7 +22,7 @@ import org.elasticsearch.gradle.info.BuildParams
 apply plugin: 'elasticsearch.testclusters'
 apply plugin: 'elasticsearch.build'
 apply plugin: 'elasticsearch.rest-test'
-apply plugin: 'maven-publish'
+apply plugin: 'elasticsearch.publish'
 apply plugin: 'com.github.johnrengelman.shadow'
 apply plugin: 'elasticsearch.rest-resources'
 

+ 1 - 1
client/rest/build.gradle

@@ -19,7 +19,7 @@ import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis
  * under the License.
  */
 apply plugin: 'elasticsearch.build'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 targetCompatibility = JavaVersion.VERSION_1_8
 sourceCompatibility = JavaVersion.VERSION_1_8

+ 1 - 1
client/sniffer/build.gradle

@@ -17,7 +17,7 @@
  * under the License.
  */
 apply plugin: 'elasticsearch.build'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 targetCompatibility = JavaVersion.VERSION_1_8
 sourceCompatibility = JavaVersion.VERSION_1_8

+ 2 - 32
distribution/archives/build.gradle

@@ -345,10 +345,8 @@ configure(subprojects.findAll { it.name == 'integ-test-zip' }) {
     MavenFilteringHack.filter(it, project(':distribution').restTestExpansions)
   }
 
-
   // The integ-test-distribution is published to maven
-  BuildPlugin.configurePomGeneration(project)
-  apply plugin: 'nebula.maven-base-publish'
+  apply plugin: 'elasticsearch.publish'
 
   // make the pom file name use elasticsearch instead of the project name
   archivesBaseName = "elasticsearch${it.name.contains('oss') ? '-oss' : ''}"
@@ -356,37 +354,9 @@ configure(subprojects.findAll { it.name == 'integ-test-zip' }) {
   publishing {
     publications {
       nebula {
-        artifactId archivesBaseName
+        pom.packaging = 'zip'
         artifact(buildDist.flatMap { it.archiveFile })
       }
-      /*
-       * HUGE HACK: the underlying maven publication library refuses to
-       * deploy any attached artifacts when the packaging type is set to
-       * 'pom'. But Sonatype's OSS repositories require source files for
-       * artifacts that are of type 'zip'. We already publish the source
-       * and javadoc for Elasticsearch under the various other subprojects.
-       * So here we create another publication using the same name that
-       * has the "real" pom, and rely on the fact that gradle will execute
-       * the publish tasks in alphabetical order. This lets us publish the
-       * zip file and even though the pom says the type is 'pom' instead of
-       * 'zip'. We cannot setup a dependency between the tasks because the
-       * publishing tasks are created *extremely* late in the configuration
-       * phase, so that we cannot get ahold of the actual task. Furthermore,
-       * this entire hack only exists so we can make publishing to maven
-       * local work, since we publish to maven central externally.
-       */
-      nebulaRealPom(MavenPublication) {
-        artifactId archivesBaseName
-        pom.packaging = 'pom'
-        pom.withXml { XmlProvider xml ->
-          Node root = xml.asNode()
-          root.appendNode('name', 'Elasticsearch')
-          root.appendNode('description', 'A Distributed RESTful Search Engine')
-          root.appendNode('url', PluginBuildPlugin.urlFromOrigin(BuildParams.gitOrigin))
-          Node scmNode = root.appendNode('scm')
-          scmNode.appendNode('url', BuildParams.gitOrigin)
-        }
-      }
     }
   }
 }

+ 1 - 1
libs/cli/build.gradle

@@ -18,7 +18,7 @@
  */
 apply plugin: 'elasticsearch.build'
 apply plugin: 'nebula.optional-base'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 dependencies {
   compile 'net.sf.jopt-simple:jopt-simple:5.0.2'

+ 1 - 1
libs/core/build.gradle

@@ -18,7 +18,7 @@
  */
 
 apply plugin: 'nebula.optional-base'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 dependencies {
   // This dependency is used only by :libs:core for null-checking interop with other tools

+ 1 - 1
libs/geo/build.gradle

@@ -18,7 +18,7 @@
  */
 
 apply plugin: 'elasticsearch.build'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 dependencies {
   testCompile(project(":test:framework")) {

+ 1 - 1
libs/nio/build.gradle

@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 dependencies {
   compile project(':libs:elasticsearch-core')

+ 1 - 1
libs/secure-sm/build.gradle

@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 dependencies {
   // do not add non-test compile dependencies to secure-sm without a good reason to do so

+ 1 - 1
libs/ssl-config/build.gradle

@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-apply plugin: "nebula.maven-base-publish"
+apply plugin: "elasticsearch.publish"
 
 dependencies {
   compile project(':libs:elasticsearch-core')

+ 1 - 1
libs/x-content/build.gradle

@@ -18,7 +18,7 @@
  */
 
 apply plugin: 'elasticsearch.build'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 dependencies {
   compile project(':libs:elasticsearch-core')

+ 1 - 1
modules/lang-painless/spi/build.gradle

@@ -18,7 +18,7 @@
  */
 
 apply plugin: 'elasticsearch.build'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 
 group = 'org.elasticsearch.plugin'
 archivesBaseName = 'elasticsearch-scripting-painless-spi'

+ 1 - 1
plugins/transport-nio/build.gradle

@@ -18,7 +18,7 @@ import org.elasticsearch.gradle.info.BuildParams
  * specific language governing permissions and limitations
  * under the License.
  */
-apply plugin: "nebula.maven-base-publish"
+apply plugin: "elasticsearch.publish"
 
 esplugin {
   description 'The nio transport.'

+ 1 - 1
rest-api-spec/build.gradle

@@ -1,5 +1,5 @@
 apply plugin: 'elasticsearch.build'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 apply plugin: 'elasticsearch.rest-resources'
 apply plugin: 'elasticsearch.validate-rest-spec'
 

+ 1 - 1
server/build.gradle

@@ -21,7 +21,7 @@ import org.elasticsearch.gradle.info.BuildParams
 
 apply plugin: 'elasticsearch.build'
 apply plugin: 'nebula.optional-base'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 apply plugin: 'elasticsearch.internal-cluster-test'
 
 publishing {

+ 1 - 1
test/build.gradle

@@ -23,7 +23,7 @@ subprojects {
 
   group = 'org.elasticsearch.test'
   apply plugin: 'elasticsearch.build'
-  apply plugin: 'nebula.maven-base-publish'
+  apply plugin: 'elasticsearch.publish'
 
   // TODO: should we have licenses for our test deps?
   dependencyLicenses.enabled = false

+ 1 - 1
x-pack/plugin/core/build.gradle

@@ -5,7 +5,7 @@ import java.nio.file.Files
 import java.nio.file.Paths
 
 apply plugin: 'elasticsearch.esplugin'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 apply plugin: 'elasticsearch.internal-cluster-test'
 
 archivesBaseName = 'x-pack-core'

+ 1 - 1
x-pack/plugin/identity-provider/build.gradle

@@ -1,7 +1,7 @@
 evaluationDependsOn(xpackModule('core'))
 
 apply plugin: 'elasticsearch.esplugin'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 esplugin {
   name 'x-pack-identity-provider'
   description 'Elasticsearch Expanded Pack Plugin - Identity Provider'

+ 1 - 1
x-pack/plugin/security/build.gradle

@@ -1,7 +1,7 @@
 evaluationDependsOn(xpackModule('core'))
 
 apply plugin: 'elasticsearch.esplugin'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 esplugin {
   name 'x-pack-security'
   description 'Elasticsearch Expanded Pack Plugin - Security'

+ 1 - 1
x-pack/plugin/sql/jdbc/build.gradle

@@ -1,5 +1,5 @@
 apply plugin: 'elasticsearch.build'
-apply plugin: 'nebula.maven-base-publish'
+apply plugin: 'elasticsearch.publish'
 apply plugin: 'com.github.johnrengelman.shadow'
 
 description = 'JDBC driver for Elasticsearch'