Add individual precommit task plugins (#56926) (#57015)

Each precommit task is currently registered inside the shared
PrecommitTasks class. Having a single class with all precommit tasks
makes individualizing which precommit tasks are needed based on type of
project difficult, where we often just disable somet tasks eg for all qa
projects. This commit creates plugins for each precommit task, and moves
the configuration of the task into each plugin. PrecommitTasks remains
for now, and just delegates to each plugin, but will be removed in a
future change.
This commit is contained in:
Ryan Ernst 2020-05-20 14:12:36 -07:00 committed by GitHub
parent 37e2bb7057
commit 33ca5ba44b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 696 additions and 305 deletions

View File

@ -23,7 +23,6 @@ import groovy.transform.CompileStatic
import org.apache.commons.io.IOUtils
import org.elasticsearch.gradle.info.BuildParams
import org.elasticsearch.gradle.info.GlobalBuildInfoPlugin
import org.elasticsearch.gradle.precommit.DependencyLicensesTask
import org.elasticsearch.gradle.precommit.PrecommitTasks
import org.elasticsearch.gradle.test.ErrorReportingTestListener
import org.elasticsearch.gradle.testclusters.ElasticsearchCluster
@ -51,10 +50,8 @@ import org.gradle.api.credentials.HttpHeaderCredentials
import org.gradle.api.execution.TaskActionListener
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.testing.Test
import org.gradle.authentication.http.HttpHeaderAuthentication
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.gradle.util.GradleVersion
import java.nio.charset.StandardCharsets
@ -98,7 +95,7 @@ class BuildPlugin implements Plugin<Project> {
configureRepositories(project)
project.extensions.getByType(ExtraPropertiesExtension).set('versions', VersionProperties.versions)
configurePrecommit(project)
PrecommitTasks.create(project, true)
configureFips140(project)
}
@ -276,18 +273,6 @@ class BuildPlugin implements Plugin<Project> {
}
}
private static configurePrecommit(Project project) {
TaskProvider precommit = PrecommitTasks.create(project, true)
project.tasks.named(LifecycleBasePlugin.CHECK_TASK_NAME).configure { it.dependsOn(precommit) }
project.tasks.named(JavaPlugin.TEST_TASK_NAME).configure { it.mustRunAfter(precommit) }
// only require dependency licenses for non-elasticsearch deps
project.tasks.withType(DependencyLicensesTask).named('dependencyLicenses').configure {
it.dependencies = project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).fileCollection { Dependency dependency ->
dependency.group.startsWith('org.elasticsearch') == false
} - project.configurations.getByName(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME)
}
}
private static class TestFailureReportingPlugin implements Plugin<Project> {
@Override
void apply(Project project) {

View File

@ -0,0 +1,31 @@
/*
* 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.precommit
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.TaskProvider
class LicenseHeadersPrecommitPlugin extends PrecommitPlugin {
@Override
TaskProvider<? extends Task> createTask(Project project) {
return project.getTasks().register("licenseHeaders", LicenseHeadersTask.class);
}
}

View File

@ -18,20 +18,8 @@
*/
package org.elasticsearch.gradle.precommit
import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis
import de.thetaphi.forbiddenapis.gradle.ForbiddenApisPlugin
import org.elasticsearch.gradle.ExportElasticsearchBuildResourcesTask
import org.elasticsearch.gradle.VersionProperties
import org.elasticsearch.gradle.info.BuildParams
import org.elasticsearch.gradle.util.Util
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.quality.Checkstyle
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
/**
* Validation tasks which should be run before committing. These run before tests.
@ -40,42 +28,21 @@ class PrecommitTasks {
/** Adds a precommit task, which depends on non-test verification tasks. */
public static TaskProvider create(Project project, boolean includeDependencyLicenses) {
project.configurations.create("forbiddenApisCliJar")
project.dependencies {
forbiddenApisCliJar('de.thetaphi:forbiddenapis:2.7')
}
public static void create(Project project, boolean includeDependencyLicenses) {
Configuration jarHellConfig = project.configurations.create("jarHell")
if (BuildParams.internal && project.path.equals(":libs:elasticsearch-core") == false) {
// External plugins will depend on this already via transitive dependencies.
// Internal projects are not all plugins, so make sure the check is available
// we are not doing this for this project itself to avoid jar hell with itself
project.dependencies {
jarHell project.project(":libs:elasticsearch-core")
}
}
List<TaskProvider> precommitTasks = [
configureCheckstyle(project),
configureForbiddenApisCli(project),
project.tasks.register('forbiddenPatterns', ForbiddenPatternsTask),
project.tasks.register('licenseHeaders', LicenseHeadersTask),
project.tasks.register('filepermissions', FilePermissionsTask),
configureJarHell(project, jarHellConfig),
configureThirdPartyAudit(project),
configureTestingConventions(project)
]
project.pluginManager.apply(CheckstylePrecommitPlugin)
project.pluginManager.apply(ForbiddenApisPrecommitPlugin)
project.pluginManager.apply(JarHellPrecommitPlugin)
project.pluginManager.apply(ForbiddenPatternsPrecommitPlugin)
project.pluginManager.apply(LicenseHeadersPrecommitPlugin)
project.pluginManager.apply(FilePermissionsPrecommitPlugin)
project.pluginManager.apply(ThirdPartyAuditPrecommitPlugin)
project.pluginManager.apply(TestingConventionsPrecommitPlugin)
// tasks with just tests don't need dependency licenses, so this flag makes adding
// the task optional
if (includeDependencyLicenses) {
TaskProvider<DependencyLicensesTask> dependencyLicenses = project.tasks.register('dependencyLicenses', DependencyLicensesTask)
precommitTasks.add(dependencyLicenses)
// we also create the updateShas helper task that is associated with dependencyLicenses
project.tasks.register('updateShas', UpdateShasTask) {
it.parentTask = dependencyLicenses
}
project.pluginManager.apply(DependencyLicensesPrecommitPlugin)
}
if (project.path != ':build-tools') {
/*
@ -88,195 +55,7 @@ class PrecommitTasks {
* use the NamingConventionsCheck we break the circular dependency
* here.
*/
precommitTasks.add(configureLoggerUsage(project))
}
// We want to get any compilation error before running the pre-commit checks.
project.sourceSets.all { sourceSet ->
precommitTasks.each { provider ->
provider.configure {
shouldRunAfter(sourceSet.getClassesTaskName())
}
}
}
TaskProvider precommit = project.tasks.register('precommit') {
group = JavaBasePlugin.VERIFICATION_GROUP
description = 'Runs all non-test checks.'
dependsOn = precommitTasks
}
// not all jar projects produce a pom (we don't ship all jars), so a pom validation
// task is only added on some projects, and thus we can't always have a task
// here to add to precommit tasks explicitly. Instead, we apply our internal
// pom validation plugin after the precommit task is created and let the
// plugin add the task if necessary
project.plugins.apply(PomValidationPlugin)
return precommit
}
static TaskProvider configureTestingConventions(Project project) {
return project.getTasks().register("testingConventions", TestingConventionsTasks) {
naming {
Tests {
baseClass "org.apache.lucene.util.LuceneTestCase"
}
IT {
baseClass "org.elasticsearch.test.ESIntegTestCase"
baseClass 'org.elasticsearch.test.rest.ESRestTestCase'
}
}
}
}
private static TaskProvider configureJarHell(Project project, Configuration jarHellConfig) {
return project.tasks.register('jarHell', JarHellTask) { task ->
task.classpath = project.sourceSets.test.runtimeClasspath + jarHellConfig
task.dependsOn(jarHellConfig)
}
}
private static TaskProvider configureThirdPartyAudit(Project project) {
ExportElasticsearchBuildResourcesTask buildResources = project.tasks.getByName('buildResources')
return project.tasks.register('thirdPartyAudit', ThirdPartyAuditTask) { task ->
task.dependsOn(buildResources)
task.signatureFile = buildResources.copy("forbidden/third-party-audit.txt")
task.javaHome = BuildParams.runtimeJavaHome
task.targetCompatibility.set(project.provider({ BuildParams.runtimeJavaVersion }))
}
}
private static TaskProvider configureForbiddenApisCli(Project project) {
project.pluginManager.apply(ForbiddenApisPlugin)
ExportElasticsearchBuildResourcesTask buildResources = project.tasks.getByName('buildResources')
project.tasks.withType(CheckForbiddenApis).configureEach {
dependsOn(buildResources)
assert name.startsWith(ForbiddenApisPlugin.FORBIDDEN_APIS_TASK_NAME)
String sourceSetName
if (ForbiddenApisPlugin.FORBIDDEN_APIS_TASK_NAME.equals(name)) {
sourceSetName = "main"
} else {
//parse out the sourceSetName
char[] chars = name.substring(ForbiddenApisPlugin.FORBIDDEN_APIS_TASK_NAME.length()).toCharArray()
chars[0] = Character.toLowerCase(chars[0])
sourceSetName = new String(chars)
}
SourceSet sourceSet = project.sourceSets.getByName(sourceSetName)
classpath = project.files { sourceSet.runtimeClasspath.plus(sourceSet.compileClasspath) }
targetCompatibility = BuildParams.runtimeJavaVersion.majorVersion
if (BuildParams.runtimeJavaVersion > JavaVersion.VERSION_14) {
// TODO: forbidden apis does not yet support java 15, rethink using runtime version
targetCompatibility = JavaVersion.VERSION_14.majorVersion
}
bundledSignatures = [
"jdk-unsafe", "jdk-deprecated", "jdk-non-portable", "jdk-system-out"
]
signaturesFiles = project.files(
buildResources.copy("forbidden/jdk-signatures.txt"),
buildResources.copy("forbidden/es-all-signatures.txt")
)
suppressAnnotations = ['**.SuppressForbidden']
if (name.endsWith('Test')) {
signaturesFiles += project.files(
buildResources.copy("forbidden/es-test-signatures.txt"),
buildResources.copy("forbidden/http-signatures.txt")
)
} else {
signaturesFiles += project.files(buildResources.copy("forbidden/es-server-signatures.txt"))
}
ext.replaceSignatureFiles = { String... names ->
signaturesFiles = project.files(
names.collect { buildResources.copy("forbidden/${it}.txt") }
)
}
ext.addSignatureFiles = { String... names ->
signaturesFiles += project.files(
names.collect { buildResources.copy("forbidden/${it}.txt") }
)
}
}
TaskProvider forbiddenApis = project.tasks.named("forbiddenApis")
forbiddenApis.configure {
group = ""
}
return forbiddenApis
}
private static TaskProvider configureCheckstyle(Project project) {
// Always copy the checkstyle configuration files to 'buildDir/checkstyle' since the resources could be located in a jar
// file. If the resources are located in a jar, Gradle will fail when it tries to turn the URL into a file
URL checkstyleConfUrl = PrecommitTasks.getResource("/checkstyle.xml")
URL checkstyleSuppressionsUrl = PrecommitTasks.getResource("/checkstyle_suppressions.xml")
File checkstyleDir = new File(project.buildDir, "checkstyle")
File checkstyleSuppressions = new File(checkstyleDir, "checkstyle_suppressions.xml")
File checkstyleConf = new File(checkstyleDir, "checkstyle.xml");
TaskProvider copyCheckstyleConf = project.tasks.register("copyCheckstyleConf")
// configure inputs and outputs so up to date works properly
copyCheckstyleConf.configure {
outputs.files(checkstyleSuppressions, checkstyleConf)
}
if ("jar".equals(checkstyleConfUrl.getProtocol())) {
JarURLConnection jarURLConnection = (JarURLConnection) checkstyleConfUrl.openConnection()
copyCheckstyleConf.configure {
inputs.file(jarURLConnection.getJarFileURL())
}
} else if ("file".equals(checkstyleConfUrl.getProtocol())) {
copyCheckstyleConf.configure {
inputs.files(checkstyleConfUrl.getFile(), checkstyleSuppressionsUrl.getFile())
}
}
copyCheckstyleConf.configure {
doLast {
checkstyleDir.mkdirs()
// withStream will close the output stream and IOGroovyMethods#getBytes reads the InputStream fully and closes it
new FileOutputStream(checkstyleConf).withStream {
it.write(checkstyleConfUrl.openStream().getBytes())
}
new FileOutputStream(checkstyleSuppressions).withStream {
it.write(checkstyleSuppressionsUrl.openStream().getBytes())
}
}
}
TaskProvider checkstyleTask = project.tasks.register('checkstyle') {
dependsOn project.tasks.withType(Checkstyle)
}
// Apply the checkstyle plugin to create `checkstyleMain` and `checkstyleTest`. It only
// creates them if there is main or test code to check and it makes `check` depend
// on them. We also want `precommit` to depend on `checkstyle`.
project.pluginManager.apply('checkstyle')
project.checkstyle {
configDir = checkstyleDir
}
project.dependencies {
checkstyle "com.puppycrawl.tools:checkstyle:${VersionProperties.versions.checkstyle}"
checkstyle project.files(Util.buildSrcCodeSource)
}
project.tasks.withType(Checkstyle).configureEach { task ->
task.dependsOn(copyCheckstyleConf)
task.reports {
html.enabled false
}
}
return checkstyleTask
}
private static TaskProvider configureLoggerUsage(Project project) {
Object dependency = BuildParams.internal ? project.project(':test:logger-usage') :
"org.elasticsearch.test:logger-usage:${VersionProperties.elasticsearch}"
project.configurations.create('loggerUsagePlugin')
project.dependencies.add('loggerUsagePlugin', dependency)
return project.tasks.register('loggerUsageCheck', LoggerUsageTask) {
classpath = project.configurations.loggerUsagePlugin
project.pluginManager.apply(LoggerUsagePrecommitPlugin)
}
}
}

View File

@ -95,6 +95,5 @@ class StandaloneRestTestPlugin implements Plugin<Project> {
idea.module.scopes.put('TEST', [plus: [project.configurations.getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME)]] as Map<String, Collection<Configuration>>)
PrecommitTasks.create(project, false)
project.tasks.named('check').configure { it.dependsOn(project.tasks.named('precommit')) }
}
}

View File

@ -24,6 +24,7 @@ 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.precommit.PomValidationPrecommitPlugin;
import org.elasticsearch.gradle.util.Util;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
@ -50,6 +51,7 @@ public class PublishPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPluginManager().apply("nebula.maven-base-publish");
project.getPluginManager().apply(PomValidationPrecommitPlugin.class);
configureJavadocJar(project);
configureSourcesJar(project);

View File

@ -0,0 +1,101 @@
/*
* 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.precommit;
import org.elasticsearch.gradle.VersionProperties;
import org.elasticsearch.gradle.util.Util;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.plugins.quality.Checkstyle;
import org.gradle.api.plugins.quality.CheckstyleExtension;
import org.gradle.api.tasks.TaskProvider;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
public class CheckstylePrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
// Always copy the checkstyle configuration files to 'buildDir/checkstyle' since the resources could be located in a jar
// file. If the resources are located in a jar, Gradle will fail when it tries to turn the URL into a file
URL checkstyleConfUrl = CheckstylePrecommitPlugin.class.getResource("/checkstyle.xml");
URL checkstyleSuppressionsUrl = CheckstylePrecommitPlugin.class.getResource("/checkstyle_suppressions.xml");
File checkstyleDir = new File(project.getBuildDir(), "checkstyle");
File checkstyleSuppressions = new File(checkstyleDir, "checkstyle_suppressions.xml");
File checkstyleConf = new File(checkstyleDir, "checkstyle.xml");
TaskProvider<Task> copyCheckstyleConf = project.getTasks().register("copyCheckstyleConf");
// configure inputs and outputs so up to date works properly
copyCheckstyleConf.configure(t -> t.getOutputs().files(checkstyleSuppressions, checkstyleConf));
if ("jar".equals(checkstyleConfUrl.getProtocol())) {
try {
JarURLConnection jarURLConnection = (JarURLConnection) checkstyleConfUrl.openConnection();
copyCheckstyleConf.configure(t -> t.getInputs().file(jarURLConnection.getJarFileURL()));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
} else if ("file".equals(checkstyleConfUrl.getProtocol())) {
copyCheckstyleConf.configure(t -> t.getInputs().files(checkstyleConfUrl.getFile(), checkstyleSuppressionsUrl.getFile()));
}
copyCheckstyleConf.configure(t -> t.doLast(task -> {
checkstyleDir.mkdirs();
try (InputStream stream = checkstyleConfUrl.openStream()) {
Files.copy(stream, checkstyleConf.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
try (InputStream stream = checkstyleSuppressionsUrl.openStream()) {
Files.copy(stream, checkstyleSuppressions.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}));
TaskProvider<Task> checkstyleTask = project.getTasks().register("checkstyle");
checkstyleTask.configure(t -> t.dependsOn(project.getTasks().withType(Checkstyle.class)));
// Apply the checkstyle plugin to create `checkstyleMain` and `checkstyleTest`. It only
// creates them if there is main or test code to check and it makes `check` depend
// on them. We also want `precommit` to depend on `checkstyle`.
project.getPluginManager().apply("checkstyle");
CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
checkstyle.getConfigDirectory().set(checkstyleDir);
DependencyHandler dependencies = project.getDependencies();
String checkstyleVersion = VersionProperties.getVersions().get("checkstyle");
dependencies.add("checkstyle", "com.puppycrawl.tools:checkstyle:" + checkstyleVersion);
dependencies.add("checkstyle", project.files(Util.getBuildSrcCodeSource()));
project.getTasks().withType(Checkstyle.class).configureEach(t -> {
t.dependsOn(copyCheckstyleConf);
t.reports(r -> r.getHtml().setEnabled(false));
});
return checkstyleTask;
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.precommit;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.TaskProvider;
public class DependencyLicensesPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
TaskProvider<DependencyLicensesTask> dependencyLicenses = project.getTasks()
.register("dependencyLicenses", DependencyLicensesTask.class);
// only require dependency licenses for non-elasticsearch deps
dependencyLicenses.configure(t -> {
Configuration runtimeClasspath = project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);
Configuration compileOnly = project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME);
t.setDependencies(
runtimeClasspath.fileCollection(dependency -> dependency.getGroup().startsWith("org.elasticsearch") == false)
.minus(compileOnly)
);
});
// we also create the updateShas helper task that is associated with dependencyLicenses
project.getTasks().register("updateShas", UpdateShasTask.class, t -> t.setParentTask(dependencyLicenses));
return dependencyLicenses;
}
}

View File

@ -186,7 +186,11 @@ public class DependencyLicensesTask extends DefaultTask {
}
return; // no dependencies to check
} else if (licensesDir.exists() == false) {
throw new GradleException("Licences dir " + licensesDir + " does not exist, but there are dependencies");
String deps = "";
for (File file : dependencies) {
deps += file.getName() + "\n";
}
throw new GradleException("Licences dir " + licensesDir + " does not exist, but there are dependencies: " + deps);
}
Map<String, Boolean> licenses = new HashMap<>();

View File

@ -0,0 +1,31 @@
/*
* 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.precommit;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskProvider;
public class FilePermissionsPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
return project.getTasks().register("filepermissions", FilePermissionsTask.class);
}
}

View File

@ -0,0 +1,124 @@
/*
* 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.precommit;
import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis;
import de.thetaphi.forbiddenapis.gradle.ForbiddenApisPlugin;
import groovy.lang.Closure;
import org.elasticsearch.gradle.ExportElasticsearchBuildResourcesTask;
import org.elasticsearch.gradle.info.BuildParams;
import org.elasticsearch.gradle.util.GradleUtils;
import org.gradle.api.JavaVersion;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.ExtraPropertiesExtension;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskProvider;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class ForbiddenApisPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
project.getPluginManager().apply(ForbiddenApisPlugin.class);
TaskProvider<ExportElasticsearchBuildResourcesTask> buildResources = project.getTasks()
.named("buildResources", ExportElasticsearchBuildResourcesTask.class);
project.getTasks().withType(CheckForbiddenApis.class).configureEach(t -> {
ExportElasticsearchBuildResourcesTask buildResourcesTask = buildResources.get();
t.dependsOn(buildResources);
assert t.getName().startsWith(ForbiddenApisPlugin.FORBIDDEN_APIS_TASK_NAME);
String sourceSetName;
if (ForbiddenApisPlugin.FORBIDDEN_APIS_TASK_NAME.equals(t.getName())) {
sourceSetName = "main";
} else {
// parse out the sourceSetName
char[] chars = t.getName().substring(ForbiddenApisPlugin.FORBIDDEN_APIS_TASK_NAME.length()).toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
sourceSetName = new String(chars);
}
SourceSetContainer sourceSets = GradleUtils.getJavaSourceSets(project);
SourceSet sourceSet = sourceSets.getByName(sourceSetName);
t.setClasspath(project.files(sourceSet.getRuntimeClasspath()).plus(sourceSet.getCompileClasspath()));
t.setTargetCompatibility(BuildParams.getRuntimeJavaVersion().getMajorVersion());
if (BuildParams.getRuntimeJavaVersion().compareTo(JavaVersion.VERSION_14) > 0) {
// TODO: forbidden apis does not yet support java 15, rethink using runtime version
t.setTargetCompatibility(JavaVersion.VERSION_14.getMajorVersion());
}
t.setBundledSignatures(Set.of("jdk-unsafe", "jdk-deprecated", "jdk-non-portable", "jdk-system-out"));
t.setSignaturesFiles(
project.files(
buildResourcesTask.copy("forbidden/jdk-signatures.txt"),
buildResourcesTask.copy("forbidden/es-all-signatures.txt")
)
);
t.setSuppressAnnotations(Set.of("**.SuppressForbidden"));
if (t.getName().endsWith("Test")) {
t.setSignaturesFiles(
t.getSignaturesFiles()
.plus(
project.files(
buildResourcesTask.copy("forbidden/es-test-signatures.txt"),
buildResourcesTask.copy("forbidden/http-signatures.txt")
)
)
);
} else {
t.setSignaturesFiles(
t.getSignaturesFiles().plus(project.files(buildResourcesTask.copy("forbidden/es-server-signatures.txt")))
);
}
ExtraPropertiesExtension ext = t.getExtensions().getExtraProperties();
ext.set("replaceSignatureFiles", new Closure<Void>(t) {
@Override
public Void call(Object... names) {
List<File> resources = new ArrayList<>(names.length);
for (Object name : names) {
resources.add(buildResourcesTask.copy("forbidden/" + name + ".txt"));
}
t.setSignaturesFiles(project.files(resources));
return null;
}
});
ext.set("addSignatureFiles", new Closure<Void>(t) {
@Override
public Void call(Object... names) {
List<File> resources = new ArrayList<>(names.length);
for (Object name : names) {
resources.add(buildResourcesTask.copy("forbidden/" + name + ".txt"));
}
t.setSignaturesFiles(t.getSignaturesFiles().plus(project.files(resources)));
return null;
}
});
});
TaskProvider<Task> forbiddenApis = project.getTasks().named("forbiddenApis");
forbiddenApis.configure(t -> t.setGroup(""));
return forbiddenApis;
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.precommit;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskProvider;
public class ForbiddenPatternsPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
return project.getTasks().register("forbiddenPatterns", ForbiddenPatternsTask.class);
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.precommit;
import org.elasticsearch.gradle.info.BuildParams;
import org.elasticsearch.gradle.util.Util;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
public class JarHellPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
Configuration jarHellConfig = project.getConfigurations().create("jarHell");
if (BuildParams.isInternal() && project.getPath().equals(":libs:elasticsearch-core") == false) {
// External plugins will depend on this already via transitive dependencies.
// Internal projects are not all plugins, so make sure the check is available
// we are not doing this for this project itself to avoid jar hell with itself
project.getDependencies().add("jarHell", project.project(":libs:elasticsearch-core"));
}
TaskProvider<JarHellTask> jarHell = project.getTasks().register("jarHell", JarHellTask.class);
jarHell.configure(t -> {
SourceSet testSourceSet = Util.getJavaTestSourceSet(project).get();
t.setClasspath(testSourceSet.getRuntimeClasspath().plus(jarHellConfig));
t.dependsOn(jarHellConfig);
});
return jarHell;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.precommit;
import org.elasticsearch.gradle.VersionProperties;
import org.elasticsearch.gradle.info.BuildParams;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.tasks.TaskProvider;
public class LoggerUsagePrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
Object dependency = BuildParams.isInternal()
? project.project(":test:logger-usage")
: ("org.elasticsearch.test:logger-usage:" + VersionProperties.getElasticsearch());
Configuration loggerUsageConfig = project.getConfigurations().create("loggerUsagePlugin");
project.getDependencies().add("loggerUsagePlugin", dependency);
TaskProvider<LoggerUsageTask> loggerUsage = project.getTasks().register("loggerUsageCheck", LoggerUsageTask.class);
loggerUsage.configure(t -> t.setClasspath(loggerUsageConfig));
return loggerUsage;
}
}

View File

@ -1,53 +0,0 @@
/*
* 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.precommit;
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.tasks.GenerateMavenPom;
import org.gradle.api.tasks.TaskProvider;
/**
* Adds pom validation to every pom generation task.
*/
public class PomValidationPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPluginManager().withPlugin("maven-publish", p -> {
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
publishing.getPublications().all(publication -> {
String publicationName = Util.capitalize(publication.getName());
TaskProvider<PomValidationTask> validateTask = project.getTasks()
.register("validate" + publicationName + "Pom", PomValidationTask.class);
validateTask.configure(task -> {
GenerateMavenPom generateMavenPom = project.getTasks()
.withType(GenerateMavenPom.class)
.getByName("generatePomFileFor" + publicationName + "Publication");
task.dependsOn(generateMavenPom);
task.getPomFile().fileValue(generateMavenPom.getDestination());
});
project.getTasks().named("precommit").configure(precommit -> { precommit.dependsOn(validateTask); });
});
});
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.precommit;
import org.elasticsearch.gradle.util.Util;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
import org.gradle.api.tasks.TaskProvider;
/**
* Adds pom validation to every pom generation task.
*/
public class PomValidationPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
TaskProvider<Task> validatePom = project.getTasks().register("validatePom");
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
publishing.getPublications().all(publication -> {
String publicationName = Util.capitalize(publication.getName());
TaskProvider<PomValidationTask> validateTask = project.getTasks()
.register("validate" + publicationName + "Pom", PomValidationTask.class);
validatePom.configure(t -> t.dependsOn(validateTask));
validateTask.configure(task -> {
GenerateMavenPom generateMavenPom = project.getTasks()
.withType(GenerateMavenPom.class)
.getByName("generatePomFileFor" + publicationName + "Publication");
task.dependsOn(generateMavenPom);
task.getPomFile().fileValue(generateMavenPom.getDestination());
});
});
return validatePom;
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.precommit;
import org.elasticsearch.gradle.util.GradleUtils;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.testing.Test;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
/**
* Base plugin for adding a precommit task.
*/
public abstract class PrecommitPlugin implements Plugin<Project> {
public static final String PRECOMMIT_TASK_NAME = "precommit";
@Override
public final void apply(Project project) {
project.getPluginManager().apply(PrecommitTaskPlugin.class);
TaskProvider<? extends Task> task = createTask(project);
TaskProvider<Task> precommit = project.getTasks().named(PRECOMMIT_TASK_NAME);
precommit.configure(t -> t.dependsOn(task));
project.getPluginManager()
.withPlugin(
"java",
p -> {
// We want to get any compilation error before running the pre-commit checks.
for (SourceSet sourceSet : GradleUtils.getJavaSourceSets(project)) {
task.configure(t -> t.shouldRunAfter(sourceSet.getClassesTaskName()));
}
}
);
}
public abstract TaskProvider<? extends Task> createTask(Project project);
static class PrecommitTaskPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
TaskProvider<Task> precommit = project.getTasks().register(PRECOMMIT_TASK_NAME, t -> {
t.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
t.setDescription("Runs all non-test checks");
});
project.getPluginManager().withPlugin("java", p -> {
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME).configure(t -> t.dependsOn(precommit));
project.getTasks().withType(Test.class).configureEach(t -> t.mustRunAfter(precommit));
});
}
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.precommit;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskProvider;
public class TestingConventionsPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
TaskProvider<TestingConventionsTasks> testingConventions = project.getTasks()
.register("testingConventions", TestingConventionsTasks.class);
testingConventions.configure(t -> {
TestingConventionRule testsRule = t.getNaming().maybeCreate("Tests");
testsRule.baseClass("org.apache.lucene.util.LuceneTestCase");
TestingConventionRule itRule = t.getNaming().maybeCreate("IT");
itRule.baseClass("org.elasticsearch.test.ESIntegTestCase");
itRule.baseClass("org.elasticsearch.test.rest.ESRestTestCase");
});
return testingConventions;
}
}

View File

@ -106,7 +106,7 @@ public class TestingConventionsTasks extends DefaultTask {
return new File(getProject().getBuildDir(), "markers/" + getName());
}
public void naming(Closure<TestingConventionRule> action) {
public void naming(Closure<?> action) {
naming.configure(action);
}

View File

@ -0,0 +1,46 @@
/*
* 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.precommit;
import org.elasticsearch.gradle.ExportElasticsearchBuildResourcesTask;
import org.elasticsearch.gradle.info.BuildParams;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskProvider;
public class ThirdPartyAuditPrecommitPlugin extends PrecommitPlugin {
@Override
public TaskProvider<? extends Task> createTask(Project project) {
project.getConfigurations().create("forbiddenApisCliJar");
project.getDependencies().add("forbiddenApisCliJar", "de.thetaphi:forbiddenapis:2.7");
TaskProvider<ExportElasticsearchBuildResourcesTask> buildResources = project.getTasks()
.named("buildResources", ExportElasticsearchBuildResourcesTask.class);
TaskProvider<ThirdPartyAuditTask> audit = project.getTasks().register("thirdPartyAudit", ThirdPartyAuditTask.class);
audit.configure(t -> {
t.dependsOn(buildResources);
t.setSignatureFile(buildResources.get().copy("forbidden/third-party-audit.txt"));
t.setJavaHome(BuildParams.getRuntimeJavaHome().toString());
t.getTargetCompatibility().set(project.provider(BuildParams::getRuntimeJavaVersion));
});
return audit;
}
}