Move public build api into included build #72861 (7.x backport) (#73715)

backport of #72861 to 7.x branch

This moves the public build api and plugins into a separete included build called 'build-tools' and we remove the duplication of included buildSrc twice (as build-tools).

The elasticsearch internal build logic is kept in build-tools-internal as included build which allows us better handling of this project that its just being an buildSrc project (e.g. we can reference tasks directly from the root build etc.)

Convention logic applied to both projects will live in a new build-conventions project.
This commit is contained in:
Rene Groeschke 2021-06-07 15:56:21 +02:00 committed by GitHub
parent 367c9d0a80
commit ea641cd359
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
436 changed files with 2798 additions and 901 deletions

View file

@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
plugins {
id 'java-gradle-plugin'
id 'java-test-fixtures'
}
group = "org.elasticsearch"
targetCompatibility = 11
sourceCompatibility = 11
gradlePlugin {
// We already configure publication and we don't need or want the one that comes
// with the java-gradle-plugin
automatedPublishing = false
plugins {
internalLicenseheaders {
id = 'elasticsearch.internal-licenseheaders'
implementationClass = 'org.elasticsearch.gradle.internal.conventions.precommit.LicenseHeadersPrecommitPlugin'
}
publish {
id = 'elasticsearch.publish'
implementationClass = 'org.elasticsearch.gradle.internal.conventions.PublishPlugin'
}
licensing {
id = 'elasticsearch.licensing'
implementationClass = 'org.elasticsearch.gradle.internal.conventions.LicensingPlugin'
}
basics {
id = 'elasticsearch.basic-build-tool-conventions'
implementationClass = 'org.elasticsearch.gradle.internal.conventions.BasicBuildToolConventionsPlugin'
}
}
}
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
api 'org.apache.maven:maven-model:3.6.2'
api 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0'
api 'org.apache.rat:apache-rat:0.11'
}

View file

@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
rootProject.name = 'build-conventions'

View file

@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.conventions;
import org.elasticsearch.gradle.internal.conventions.info.ParallelDetector;
import org.elasticsearch.gradle.internal.conventions.util.Util;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.testing.Test;
import java.io.File;
public class BasicBuildToolConventionsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
int defaultParallel = ParallelDetector.findDefaultParallel(project);
project.getTasks().withType(Test.class).configureEach(test -> {
test.onlyIf((t) -> Util.getBooleanProperty("tests.fips.enabled", false) == false);
test.setMaxParallelForks(defaultParallel);
});
// we put all our distributable files under distributions
project.getTasks().withType(Jar.class).configureEach(j ->
j.getDestinationDirectory().set(new File(project.getBuildDir(), "distributions"))
);
}
}

View file

@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.conventions;
import java.util.Locale;
public abstract class GUtils {
public static String capitalize(String s) {
return s.substring(0, 1).toUpperCase(Locale.ROOT) + s.substring(1);
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.conventions;
import org.elasticsearch.gradle.internal.conventions.info.GitInfo;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.initialization.layout.BuildLayout;
import javax.inject.Inject;
import java.io.File;
class GitInfoPlugin implements Plugin<Project> {
private ProviderFactory factory;
private ObjectFactory objectFactory;
private Provider<String> revision;
private Property<GitInfo> gitInfo;
@Inject
public GitInfoPlugin(ProviderFactory factory, ObjectFactory objectFactory) {
this.factory = factory;
this.objectFactory = objectFactory;
}
@Override
public void apply(Project project) {
File rootDir = (project.getGradle().getParent() == null) ?
project.getRootDir() :
project.getGradle().getParent().getRootProject().getRootDir();
gitInfo = objectFactory.property(GitInfo.class).value(factory.provider(() ->
GitInfo.gitInfo(rootDir)
));
gitInfo.disallowChanges();
gitInfo.finalizeValueOnRead();
revision = gitInfo.map(info -> info.getRevision() == null ? info.getRevision() : "master");
}
public Property<GitInfo> getGitInfo() {
return gitInfo;
}
public Provider<String> getRevision() {
return revision;
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.conventions;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import javax.inject.Inject;
import java.util.Map;
import java.util.concurrent.Callable;
public class LicensingPlugin implements Plugin<Project> {
final static String ELASTIC_LICENSE_URL_PREFIX = "https://raw.githubusercontent.com/elastic/elasticsearch/";
final static String ELASTIC_LICENSE_URL_POSTFIX = "/licenses/ELASTIC-LICENSE-2.0.txt";
private ProviderFactory providerFactory;
@Inject
public LicensingPlugin(ProviderFactory providerFactory) {
this.providerFactory = providerFactory;
}
@Override
public void apply(Project project) {
Provider<String> revision = project.getRootProject().getPlugins().apply(GitInfoPlugin.class).getRevision();
Provider<String> licenseCommitProvider = providerFactory.provider(() ->
isSnapshotVersion(project) ? revision.get() : "v" + project.getVersion().toString()
);
MapProperty<String, String> licensesProperty = project.getObjects().mapProperty(String.class, String.class);
Provider<String> projectLicenseURL = licenseCommitProvider.map(licenseCommit -> ELASTIC_LICENSE_URL_PREFIX +
licenseCommit + ELASTIC_LICENSE_URL_POSTFIX);
// But stick the Elastic license url in project.ext so we can get it if we need to switch to it
project.getExtensions().getExtraProperties().set("elasticLicenseUrl", projectLicenseURL);
MapProperty<String, String> convention = licensesProperty.convention(
providerFactory.provider((Callable<Map<? extends String, ? extends String>>) () -> Map.of(
"Server Side Public License, v 1", "https://www.mongodb.com/licensing/server-side-public-license",
"Elastic License 2.0", projectLicenseURL.get())
)
);
// Default to the SSPL+Elastic dual license
project.getExtensions().getExtraProperties().set("licenseCommit", licenseCommitProvider);
project.getExtensions().getExtraProperties().set("projectLicenses", convention);
}
private boolean isSnapshotVersion(Project project) {
return project.getVersion().toString().endsWith("-SNAPSHOT");
}
}

View file

@ -6,22 +6,26 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal;
package org.elasticsearch.gradle.internal.conventions;
import org.elasticsearch.gradle.internal.conventions.precommit.PomValidationPrecommitPlugin;
import com.github.jengelman.gradle.plugins.shadow.ShadowExtension;
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin;
import groovy.util.Node;
import org.elasticsearch.gradle.internal.info.BuildParams;
import org.elasticsearch.gradle.internal.precommit.PomValidationPrecommitPlugin;
import org.elasticsearch.gradle.internal.util.Util;
import org.elasticsearch.gradle.internal.conventions.util.Util;
import org.elasticsearch.gradle.internal.conventions.info.GitInfo;
import org.gradle.api.NamedDomainObjectSet;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.Project;
import org.gradle.api.XmlProvider;
import org.gradle.api.plugins.BasePlugin;
import org.gradle.api.plugins.BasePluginConvention;
import org.gradle.api.plugins.JavaLibraryPlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
@ -30,9 +34,10 @@ 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;
import java.io.File;
import java.util.Map;
import java.util.concurrent.Callable;
public class PublishPlugin implements Plugin<Project> {
@ -41,15 +46,18 @@ public class PublishPlugin implements Plugin<Project> {
project.getPluginManager().apply(BasePlugin.class);
project.getPluginManager().apply(MavenPublishPlugin.class);
project.getPluginManager().apply(PomValidationPrecommitPlugin.class);
configurePublications(project);
project.getPluginManager().apply(LicensingPlugin.class);
configureJavadocJar(project);
configureSourcesJar(project);
configurePomGeneration(project);
configurePublications(project);
}
private void configurePublications(Project project) {
PublishingExtension publishingExtension = project.getExtensions().getByType(PublishingExtension.class);
MavenPublication publication = publishingExtension.getPublications().create("elastic", MavenPublication.class);
project.afterEvaluate(project1 -> {
if (project1.getPlugins().hasPlugin(ShadowPlugin.class)) {
configureWithShadowPlugin(project1, publication);
@ -57,6 +65,25 @@ public class PublishPlugin implements Plugin<Project> {
publication.from(project.getComponents().getByName("java"));
}
});
publication.getPom().withXml(xml -> {
Node node = xml.asNode();
node.appendNode("inceptionYear", "2009");
Node licensesNode = node.appendNode("licenses");
MapProperty<String, String> projectLicenses = (MapProperty<String, String>) project.getExtensions().getExtraProperties().get("projectLicenses");
projectLicenses.get().entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
Node license = licensesNode.appendNode("license");
license.appendNode("name", entry.getKey());
license.appendNode("url", entry.getValue());
license.appendNode("distribution", "repo");
});
Node developer = node.appendNode("developers").appendNode("developer");
developer.appendNode("name", "Elastic");
developer.appendNode("url", "https://www.elastic.co");
});
publishingExtension.getRepositories().maven(mavenArtifactRepository -> {
mavenArtifactRepository.setName("test");
mavenArtifactRepository.setUrl(new File(project.getRootProject().getBuildDir(), "local-test-repo"));
});
}
private static String getArchivesBaseName(Project project) {
@ -67,6 +94,8 @@ public class PublishPlugin implements Plugin<Project> {
* Configuration generation of maven poms.
*/
private static void configurePomGeneration(Project project) {
Property<GitInfo> gitInfo = project.getRootProject().getPlugins().apply(GitInfoPlugin.class).getGitInfo();
TaskProvider<Task> generatePomTask = project.getTasks().register("generatePom");
project.getTasks().named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).configure(assemble -> assemble.dependsOn(generatePomTask));
project.getTasks()
@ -82,12 +111,12 @@ public class PublishPlugin implements Plugin<Project> {
)
);
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
final var mavenPublications = publishing.getPublications().withType(MavenPublication.class);
final NamedDomainObjectSet<MavenPublication> mavenPublications = publishing.getPublications().withType(MavenPublication.class);
addNameAndDescriptiontoPom(project, mavenPublications);
mavenPublications.all(publication -> {
// Add git origin info to generated POM files for internal builds
BuildParams.withInternalBuild(() -> publication.getPom().withXml(PublishPlugin::addScmInfo));
publication.getPom().withXml((xmlProvider) -> addScmInfo(xmlProvider, gitInfo.get()));
// have to defer this until archivesBaseName is set
project.afterEvaluate(p -> publication.setArtifactId(getArchivesBaseName(project)));
generatePomTask.configure(t -> t.dependsOn(project.getTasks().withType(GenerateMavenPom.class)));
@ -99,7 +128,7 @@ public class PublishPlugin implements Plugin<Project> {
Node root = xml.asNode();
root.appendNode("name", project.getName());
String description = project.getDescription() != null ? project.getDescription() : "";
root.appendNode("description", project.getDescription());
root.appendNode("description", description);
}));
}
@ -108,18 +137,18 @@ public class PublishPlugin implements Plugin<Project> {
shadow.component(publication);
}
private static void addScmInfo(XmlProvider xml) {
private static void addScmInfo(XmlProvider xml, GitInfo gitInfo) {
Node root = xml.asNode();
root.appendNode("url", Util.urlFromOrigin(BuildParams.getGitOrigin()));
root.appendNode("url", gitInfo.urlFromOrigin());
Node scmNode = root.appendNode("scm");
scmNode.appendNode("url", BuildParams.getGitOrigin());
scmNode.appendNode("url", gitInfo.getOrigin());
}
/**
* Adds a javadocJar task to generate a jar containing javadocs.
*/
private static void configureJavadocJar(Project project) {
project.getPlugins().withId("elasticsearch.java", p -> {
project.getPlugins().withType(JavaLibraryPlugin.class, p -> {
TaskProvider<Jar> javadocJarTask = project.getTasks().register("javadocJar", Jar.class);
javadocJarTask.configure(jar -> {
jar.getArchiveClassifier().set("javadoc");
@ -127,12 +156,12 @@ public class PublishPlugin implements Plugin<Project> {
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));
project.getTasks().named(BasePlugin.ASSEMBLE_TASK_NAME).configure(t -> t.dependsOn(javadocJarTask));
});
}
static void configureSourcesJar(Project project) {
project.getPlugins().withId("elasticsearch.java", p -> {
project.getPlugins().withType(JavaLibraryPlugin.class, p -> {
TaskProvider<Jar> sourcesJarTask = project.getTasks().register("sourcesJar", Jar.class);
sourcesJarTask.configure(jar -> {
jar.getArchiveClassifier().set("sources");
@ -141,7 +170,7 @@ public class PublishPlugin implements Plugin<Project> {
SourceSet mainSourceSet = Util.getJavaMainSourceSet(project).get();
jar.from(mainSourceSet.getAllSource());
});
maybeConfigure(project.getTasks(), BasePlugin.ASSEMBLE_TASK_NAME, t -> t.dependsOn(sourcesJarTask));
project.getTasks().named(BasePlugin.ASSEMBLE_TASK_NAME).configure(t -> t.dependsOn(sourcesJarTask));
});
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.conventions;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
// Define this here because we need it early.
public class VersionPropertiesLoader {
static Properties loadBuildSrcVersion(File input) throws IOException {
Properties props = new Properties();
InputStream is = new FileInputStream(input);
try {
props.load(is);
} finally {
is.close();
}
loadBuildSrcVersion(props, System.getProperties());
return props;
}
protected static void loadBuildSrcVersion(Properties loadedProps, Properties systemProperties) {
String elasticsearch = loadedProps.getProperty("elasticsearch");
if (elasticsearch == null) {
throw new IllegalStateException("Elasticsearch version is missing from properties.");
}
if (elasticsearch.matches("[0-9]+\\.[0-9]+\\.[0-9]+") == false) {
throw new IllegalStateException(
"Expected elasticsearch version to be numbers only of the form X.Y.Z but it was: " +
elasticsearch
);
}
String qualifier = systemProperties.getProperty("build.version_qualifier", "");
if (qualifier.isEmpty() == false) {
if (qualifier.matches("(alpha|beta|rc)\\d+") == false) {
throw new IllegalStateException("Invalid qualifier: " + qualifier);
}
elasticsearch += "-" + qualifier;
}
final String buildSnapshotSystemProperty = systemProperties.getProperty("build.snapshot", "true");
switch (buildSnapshotSystemProperty) {
case "true":
elasticsearch += "-SNAPSHOT";
break;
case "false":
// do nothing
break;
default:
throw new IllegalArgumentException(
"build.snapshot was set to [" + buildSnapshotSystemProperty + "] but can only be unset or [true|false]");
}
loadedProps.put("elasticsearch", elasticsearch);
}
}

View file

@ -0,0 +1,186 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.conventions.info;
import org.gradle.api.GradleException;
import org.gradle.api.logging.Logging;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class GitInfo {
private static final Pattern GIT_PATTERN = Pattern.compile("git@([^:]+):([^\\.]+)\\.git");
private final String revision;
private final String origin;
private GitInfo(String revision, String origin) {
this.revision = revision;
this.origin = origin;
}
public String getRevision() {
return revision;
}
public String getOrigin() {
return origin;
}
public static GitInfo gitInfo(File rootDir) {
try {
/*
* We want to avoid forking another process to run git rev-parse HEAD. Instead, we will read the refs manually. The
* documentation for this follows from https://git-scm.com/docs/gitrepository-layout and https://git-scm.com/docs/git-worktree.
*
* There are two cases to consider:
* - a plain repository with .git directory at the root of the working tree
* - a worktree with a plain text .git file at the root of the working tree
*
* In each case, our goal is to parse the HEAD file to get either a ref or a bare revision (in the case of being in detached
* HEAD state).
*
* In the case of a plain repository, we can read the HEAD file directly, resolved directly from the .git directory.
*
* In the case of a worktree, we read the gitdir from the plain text .git file. This resolves to a directory from which we read
* the HEAD file and resolve commondir to the plain git repository.
*/
final Path dotGit = rootDir.toPath().resolve(".git");
final String revision;
if (Files.exists(dotGit) == false) {
return new GitInfo("unknown", "unknown");
}
final Path head;
final Path gitDir;
if (Files.isDirectory(dotGit)) {
// this is a git repository, we can read HEAD directly
head = dotGit.resolve("HEAD");
gitDir = dotGit;
} else {
// this is a git worktree, follow the pointer to the repository
final Path workTree = Paths.get(readFirstLine(dotGit).substring("gitdir:".length()).trim());
if (Files.exists(workTree) == false) {
return new GitInfo("unknown", "unknown");
}
head = workTree.resolve("HEAD");
final Path commonDir = Paths.get(readFirstLine(workTree.resolve("commondir")));
if (commonDir.isAbsolute()) {
gitDir = commonDir;
} else {
// this is the common case
gitDir = workTree.resolve(commonDir);
}
}
final String ref = readFirstLine(head);
if (ref.startsWith("ref:")) {
String refName = ref.substring("ref:".length()).trim();
Path refFile = gitDir.resolve(refName);
if (Files.exists(refFile)) {
revision = readFirstLine(refFile);
} else if (Files.exists(gitDir.resolve("packed-refs"))) {
// Check packed references for commit ID
Pattern p = Pattern.compile("^([a-f0-9]{40}) " + refName + "$");
try (Stream<String> lines = Files.lines(gitDir.resolve("packed-refs"))) {
revision = lines.map(p::matcher)
.filter(Matcher::matches)
.map(m -> m.group(1))
.findFirst()
.orElseThrow(() -> new IOException("Packed reference not found for refName " + refName));
}
} else {
File refsDir = gitDir.resolve("refs").toFile();
if (refsDir.exists()) {
String foundRefs = Arrays.stream(refsDir.listFiles()).map(f -> f.getName()).collect(Collectors.joining("\n"));
Logging.getLogger(GitInfo.class).error("Found git refs\n" + foundRefs);
} else {
Logging.getLogger(GitInfo.class).error("No git refs dir found");
}
throw new GradleException("Can't find revision for refName " + refName);
}
} else {
// we are in detached HEAD state
revision = ref;
}
return new GitInfo(revision, findOriginUrl(gitDir.resolve("config")));
} catch (final IOException e) {
// for now, do not be lenient until we have better understanding of real-world scenarios where this happens
throw new GradleException("unable to read the git revision", e);
}
}
private static String findOriginUrl(final Path configFile) throws IOException {
Map<String, String> props = new HashMap<>();
try (Stream<String> stream = Files.lines(configFile, StandardCharsets.UTF_8)) {
Iterator<String> lines = stream.iterator();
boolean foundOrigin = false;
while (lines.hasNext()) {
String line = lines.next().trim();
if (line.startsWith(";") || line.startsWith("#")) {
// ignore comments
continue;
}
if (foundOrigin) {
if (line.startsWith("[")) {
// we're on to the next config item so stop looking
break;
}
String[] pair = line.trim().split("=", 2);
props.put(pair[0].trim(), pair[1].trim());
} else {
if (line.equals("[remote \"origin\"]")) {
foundOrigin = true;
}
}
}
}
String originUrl = props.get("url");
return originUrl == null ? "unknown" : originUrl;
}
private static String readFirstLine(final Path path) throws IOException {
String firstLine;
try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
firstLine = lines.findFirst().orElseThrow(() -> new IOException("file [" + path + "] is empty"));
}
return firstLine;
}
/** Find the reponame. */
public String urlFromOrigin() {
String oritin = getOrigin();
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
}
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.conventions.info;
import org.gradle.api.Project;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ParallelDetector {
private static Integer _defaultParallel = null;
public static int findDefaultParallel(Project project) {
// Since it costs IO to compute this, and is done at configuration time we want to cache this if possible
// It's safe to store this in a static variable since it's just a primitive so leaking memory isn't an issue
if (_defaultParallel == null) {
File cpuInfoFile = new File("/proc/cpuinfo");
if (cpuInfoFile.exists()) {
// Count physical cores on any Linux distro ( don't count hyper-threading )
Map<String, Integer> socketToCore = new HashMap<>();
String currentID = "";
try (BufferedReader reader = new BufferedReader(new FileReader(cpuInfoFile))) {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
if (line.contains(":")) {
List<String> parts = Arrays.stream(line.split(":", 2)).map(String::trim).collect(Collectors.toList());
String name = parts.get(0);
String value = parts.get(1);
// the ID of the CPU socket
if (name.equals("physical id")) {
currentID = value;
}
// Number of cores not including hyper-threading
if (name.equals("cpu cores")) {
assert currentID.isEmpty() == false;
socketToCore.put("currentID", Integer.valueOf(value));
currentID = "";
}
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
_defaultParallel = socketToCore.values().stream().mapToInt(i -> i).sum();
} else if (isMac()) {
// Ask macOS to count physical CPUs for us
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
project.exec(spec -> {
spec.setExecutable("sysctl");
spec.args("-n", "hw.physicalcpu");
spec.setStandardOutput(stdout);
});
_defaultParallel = Integer.parseInt(stdout.toString().trim());
}
_defaultParallel = Runtime.getRuntime().availableProcessors() / 2;
}
return _defaultParallel;
}
private static boolean isMac() {
return System.getProperty("os.name", "").startsWith("Mac");
}
}

View file

@ -6,14 +6,12 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.precommit;
package org.elasticsearch.gradle.internal.conventions.precommit;
import org.elasticsearch.gradle.internal.InternalPlugin;
import org.elasticsearch.gradle.precommit.PrecommitPlugin;
import org.elasticsearch.gradle.util.GradleUtils;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskProvider;
@ -21,7 +19,7 @@ import org.gradle.api.tasks.TaskProvider;
import javax.inject.Inject;
import java.util.stream.Collectors;
public class LicenseHeadersPrecommitPlugin extends PrecommitPlugin implements InternalPlugin {
public class LicenseHeadersPrecommitPlugin extends PrecommitPlugin {
@Inject
public LicenseHeadersPrecommitPlugin(ProviderFactory providerFactory) {
this.providerFactory = providerFactory;
@ -31,7 +29,7 @@ public class LicenseHeadersPrecommitPlugin extends PrecommitPlugin implements In
public TaskProvider<? extends Task> createTask(Project project) {
return project.getTasks().register("licenseHeaders", LicenseHeadersTask.class, licenseHeadersTask -> {
project.getPlugins().withType(JavaBasePlugin.class, javaBasePlugin -> {
final SourceSetContainer sourceSets = GradleUtils.getJavaSourceSets(project);
final SourceSetContainer sourceSets = project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets();
licenseHeadersTask.getSourceFolders()
.addAll(providerFactory.provider(() -> sourceSets.stream().map(s -> s.getAllJava()).collect(Collectors.toList())));
});

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.precommit;
package org.elasticsearch.gradle.internal.conventions.precommit;
import org.apache.rat.Defaults;
import org.apache.rat.ReportConfiguration;

View file

@ -6,10 +6,9 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.precommit;
package org.elasticsearch.gradle.internal.conventions.precommit;
import org.elasticsearch.gradle.precommit.PrecommitPlugin;
import org.elasticsearch.gradle.internal.util.Util;
import org.elasticsearch.gradle.internal.conventions.GUtils;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.publish.PublishingExtension;
@ -26,7 +25,7 @@ public class PomValidationPrecommitPlugin extends PrecommitPlugin {
TaskProvider<Task> validatePom = project.getTasks().register("validatePom");
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
publishing.getPublications().all(publication -> {
String publicationName = Util.capitalize(publication.getName());
String publicationName = GUtils.capitalize(publication.getName());
TaskProvider<PomValidationTask> validateTask = project.getTasks()
.register("validate" + publicationName + "Pom", PomValidationTask.class);
validatePom.configure(t -> t.dependsOn(validateTask));

View file

@ -6,11 +6,11 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.precommit;
package org.elasticsearch.gradle.internal.conventions.precommit;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.elasticsearch.gradle.precommit.PrecommitTask;
import org.elasticsearch.gradle.internal.conventions.precommit.PrecommitTask;
import org.gradle.api.GradleException;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFile;

View file

@ -6,12 +6,12 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.precommit;
package org.elasticsearch.gradle.internal.conventions.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.JavaPluginConvention;
import org.gradle.api.tasks.TaskProvider;
/**
@ -27,10 +27,11 @@ public abstract class PrecommitPlugin implements Plugin<Project> {
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.
GradleUtils.getJavaSourceSets(project).all(sourceSet -> task.configure(t -> t.shouldRunAfter(sourceSet.getClassesTaskName())));
project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().all(sourceSet ->
task.configure(t -> t.shouldRunAfter(sourceSet.getClassesTaskName()))
);
});
}

View file

@ -5,7 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.precommit;
package org.elasticsearch.gradle.internal.conventions.precommit;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.ProjectLayout;

View file

@ -6,13 +6,13 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.precommit;
package org.elasticsearch.gradle.internal.conventions.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.plugins.JavaPluginConvention;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.testing.Test;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
@ -33,8 +33,9 @@ public class PrecommitTaskPlugin implements Plugin<Project> {
);
project.getPluginManager().withPlugin("java", p -> {
// run compilation as part of precommit
GradleUtils.getJavaSourceSets(project).all(sourceSet -> precommit.configure(t -> t.dependsOn(sourceSet.getClassesTaskName())));
project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().all(sourceSet ->
precommit.configure(t -> t.shouldRunAfter(sourceSet.getClassesTaskName()))
);
// make sure tests run after all precommit tasks
project.getTasks().withType(Test.class).configureEach(t -> t.mustRunAfter(precommit));
});

View file

@ -6,30 +6,22 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.util;
package org.elasticsearch.gradle.internal.conventions.util;
import org.elasticsearch.gradle.internal.info.GlobalBuildInfoPlugin;
import org.elasticsearch.gradle.util.GradleUtils;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.gradle.api.file.FileTree;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.util.PatternFilterable;
import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
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 {
@ -47,36 +39,6 @@ public class Util {
}
}
public static String getResourceContents(String resourcePath) {
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(GlobalBuildInfoPlugin.class.getResourceAsStream(resourcePath)))
) {
StringBuilder b = new StringBuilder();
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
if (b.length() != 0) {
b.append('\n');
}
b.append(line);
}
return b.toString();
} catch (IOException e) {
throw new UncheckedIOException("Error trying to read classpath resource: " + resourcePath, e);
}
}
public static String capitalize(String s) {
return s.substring(0, 1).toUpperCase(Locale.ROOT) + s.substring(1);
}
public static URI getBuildSrcCodeSource() {
try {
return Util.class.getProtectionDomain().getCodeSource().getLocation().toURI();
} catch (URISyntaxException e) {
throw new GradleException("Error determining build tools JAR location", e);
}
}
/**
* @param project The project to look for resources.
* @param filter Optional filter function to filter the returned resources
@ -125,7 +87,7 @@ public class Util {
public static Optional<SourceSet> getJavaTestSourceSet(Project project) {
return project.getConvention().findPlugin(JavaPluginConvention.class) == null
? Optional.empty()
: Optional.ofNullable(GradleUtils.getJavaSourceSets(project).findByName(SourceSet.TEST_SOURCE_SET_NAME));
: Optional.ofNullable(getJavaSourceSets(project).findByName(SourceSet.TEST_SOURCE_SET_NAME));
}
/**
@ -135,26 +97,9 @@ public class Util {
public static Optional<SourceSet> getJavaMainSourceSet(Project project) {
return project.getConvention().findPlugin(JavaPluginConvention.class) == null
? Optional.empty()
: Optional.ofNullable(GradleUtils.getJavaSourceSets(project).findByName(SourceSet.MAIN_SOURCE_SET_NAME));
: Optional.ofNullable(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() {
@ -164,4 +109,9 @@ public class Util {
}
};
}
public static SourceSetContainer getJavaSourceSets(Project project) {
return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets();
}
}

View file

@ -8,30 +8,18 @@
import org.gradle.internal.jvm.Jvm
import org.gradle.util.GradleVersion
import org.elasticsearch.gradle.internal.conventions.VersionPropertiesLoader
plugins {
id 'java-gradle-plugin'
id 'groovy-gradle-plugin'
id 'groovy'
id 'java-test-fixtures'
id 'elasticsearch.internal-licenseheaders'
id 'elasticsearch.basic-build-tool-conventions'
}
group = 'org.elasticsearch.gradle'
String minimumGradleVersion = file('src/main/resources/minimumGradleVersion').text.trim()
if (GradleVersion.current() < GradleVersion.version(minimumGradleVersion)) {
throw new GradleException("Gradle ${minimumGradleVersion}+ is required to build elasticsearch")
}
if (project == rootProject) {
// change the build dir used during build init, so that doing a clean
// won't wipe out the buildscript jar
buildDir = 'build-bootstrap'
}
/*****************************************************************************
* Propagating version.properties to the rest of the build *
*****************************************************************************/
// we update the version property to reflect if we are building a snapshot or a release build
// we write this back out below to load it in the Build.java which will be shown in rest main action
// to indicate this being a snapshot build or a release build.
@ -47,10 +35,6 @@ gradlePlugin {
id = 'elasticsearch.build'
implementationClass = 'org.elasticsearch.gradle.internal.BuildPlugin'
}
distributionDownload {
id = 'elasticsearch.distribution-download'
implementationClass = 'org.elasticsearch.gradle.DistributionDownloadPlugin'
}
distroTest {
id = 'elasticsearch.distro-test'
implementationClass = 'org.elasticsearch.gradle.internal.test.DistroTestPlugin'
@ -63,10 +47,6 @@ gradlePlugin {
id = 'elasticsearch.docs-test'
implementationClass = 'org.elasticsearch.gradle.internal.doc.DocsTestPlugin'
}
esPlugin {
id = 'elasticsearch.esplugin'
implementationClass = 'org.elasticsearch.gradle.plugin.PluginBuildPlugin'
}
globalBuildInfo {
id = 'elasticsearch.global-build-info'
implementationClass = 'org.elasticsearch.gradle.internal.info.GlobalBuildInfoPlugin'
@ -95,10 +75,6 @@ gradlePlugin {
id = 'elasticsearch.internal-distribution-download'
implementationClass = 'org.elasticsearch.gradle.internal.InternalDistributionDownloadPlugin'
}
internalLicenseheaders {
id = 'elasticsearch.internal-licenseheaders'
implementationClass = 'org.elasticsearch.gradle.internal.precommit.LicenseHeadersPrecommitPlugin'
}
internalPlugin {
id = 'elasticsearch.internal-es-plugin'
implementationClass = 'org.elasticsearch.gradle.internal.InternalPluginBuildPlugin'
@ -127,18 +103,6 @@ gradlePlugin {
id = 'elasticsearch.java-rest-test'
implementationClass = 'org.elasticsearch.gradle.internal.test.rest.JavaRestTestPlugin'
}
jdkDownload {
id = 'elasticsearch.jdk-download'
implementationClass = 'org.elasticsearch.gradle.internal.JdkDownloadPlugin'
}
publish {
id = 'elasticsearch.publish'
implementationClass = 'org.elasticsearch.gradle.internal.PublishPlugin'
}
reaper {
id = 'elasticsearch.reaper'
implementationClass = 'org.elasticsearch.gradle.ReaperPlugin'
}
repositories {
id = 'elasticsearch.repositories'
implementationClass = 'org.elasticsearch.gradle.internal.RepositoriesSetupPlugin'
@ -175,33 +139,16 @@ gradlePlugin {
id = 'elasticsearch.test-with-ssl'
implementationClass = 'org.elasticsearch.gradle.internal.test.TestWithSslPlugin'
}
testclusters {
id = 'elasticsearch.testclusters'
implementationClass = 'org.elasticsearch.gradle.testclusters.TestClustersPlugin'
}
validateRestSpec {
id = 'elasticsearch.validate-rest-spec'
implementationClass = 'org.elasticsearch.gradle.internal.precommit.ValidateRestSpecPlugin'
}
yamlRestCompatTest {
id = 'elasticsearch.yaml-rest-compat-test'
implementationClass = 'org.elasticsearch.gradle.internal.rest.compat.YamlRestCompatTestPlugin'
}
yamlRestTest {
id = 'elasticsearch.yaml-rest-test'
implementationClass = 'org.elasticsearch.gradle.internal.test.rest.YamlRestTestPlugin'
}
}
}
def generateVersionProperties = tasks.register("generateVersionProperties", WriteProperties) {
outputFile = "${buildDir}/version.properties"
comment = 'Generated version properties'
properties(props)
}
tasks.named("processResources").configure {
from(generateVersionProperties)
}
/*****************************************************************************
* Java version *
@ -211,11 +158,8 @@ if (JavaVersion.current() < JavaVersion.VERSION_11) {
throw new GradleException('At least Java 11 is required to build elasticsearch gradle tools')
}
allprojects {
apply plugin: 'java'
targetCompatibility = '11'
sourceCompatibility = '11'
}
targetCompatibility = 11
sourceCompatibility = 11
sourceSets {
integTest {
@ -228,6 +172,10 @@ tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
tasks.named('licenseHeaders').configure {
// ignore gradle generated binary script plugins
excludes << "Elasticsearch*Plugin.java"
}
/*****************************************************************************
* Dependencies used by the entire build *
*****************************************************************************/
@ -244,6 +192,9 @@ dependencies {
api localGroovy()
api "org.elasticsearch:build-conventions:$version"
api "org.elasticsearch:build-tools:$version"
api 'commons-codec:commons-codec:1.12'
api 'org.apache.commons:commons-compress:1.19'
api 'org.apache.ant:ant:1.10.8'
@ -265,22 +216,26 @@ dependencies {
compileOnly "com.puppycrawl.tools:checkstyle:${props.getProperty('checkstyle')}"
testImplementation "com.puppycrawl.tools:checkstyle:${props.getProperty('checkstyle')}"
testFixturesApi "junit:junit:${props.getProperty('junit')}"
testFixturesApi "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${props.getProperty('randomizedrunner')}"
testFixturesApi gradleApi()
testFixturesApi gradleTestKit()
testImplementation "junit:junit:${props.getProperty('junit')}"
// testFixturesApi "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${props.getProperty('randomizedrunner')}"
// testFixturesApi gradleApi()
// testFixturesApi gradleTestKit()
testImplementation 'com.github.tomakehurst:wiremock-jre8-standalone:2.23.2'
testImplementation 'org.mockito:mockito-core:1.9.5'
testImplementation "org.hamcrest:hamcrest:${props.getProperty('hamcrest')}"
testImplementation testFixtures("org.elasticsearch:build-tools:$version")
integTestImplementation(platform("org.junit:junit-bom:${props.getProperty('junit5')}"))
integTestImplementation("org.junit.jupiter:junit-jupiter") {
because 'allows to write and run Jupiter tests'
}
integTestImplementation("net.bytebuddy:byte-buddy:1.11.0") {
because 'Generating dynamic mocks of internal libraries like JdkJarHell'
}
testRuntimeOnly("org.junit.vintage:junit-vintage-engine") {
because 'allows JUnit 3 and JUnit 4 tests to run'
}
integTestRuntimeOnly("org.junit.platform:junit-platform-launcher") {
because 'allows tests to run from IDEs that bundle older version of launcher'
}
@ -298,117 +253,6 @@ dependencies {
integTestImplementation "org.xmlunit:xmlunit-core:2.8.2"
}
/*****************************************************************************
* Bootstrap repositories *
*****************************************************************************/
// this will only happen when buildSrc is built on its own during build init
if (project == rootProject) {
apply plugin: 'groovy-gradle-plugin'
repositories {
if (System.getProperty("repos.mavenLocal") != null) {
mavenLocal()
}
}
dependencies {
// add this so the runtime classpath so Gradle will properly track it as a build runtime classpath input
runtimeOnly project('reaper')
}
// only run tests as build-tools
tasks.named("test").configure {
enabled = false
}
}
/*****************************************************************************
* Normal project checks *
*****************************************************************************/
// this happens when included as a normal project in the build, which we do
// to enforce precommit checks like forbidden apis, as well as setup publishing
if (project != rootProject) {
apply plugin: 'elasticsearch.build'
apply plugin: 'elasticsearch.publish'
// We have to set this again down here since the elasticsearch.java plugin defaults to minimumRuntimeVersion
targetCompatibility = '11'
sourceCompatibility = '11'
// groovydoc succeeds, but has some weird internal exception...
tasks.named("groovydoc").configure {
enabled = false
}
// build-tools is not ready for primetime with these...
tasks.named("dependencyLicenses").configure { enabled = false }
tasks.named("dependenciesInfo").configure {enabled = false }
disableTasks('forbiddenApisMain', 'forbiddenApisTest', 'forbiddenApisIntegTest', 'forbiddenApisTestFixtures')
tasks.named("jarHell").configure {
enabled = false
}
tasks.named("thirdPartyAudit").configure {
enabled = false
}
configurations.register("distribution")
configurations.register("reaper")
dependencies {
reaper project('reaper')
distribution project(':distribution:archives:windows-zip')
distribution project(':distribution:archives:darwin-tar')
distribution project(':distribution:archives:darwin-aarch64-tar')
distribution project(':distribution:archives:linux-aarch64-tar')
distribution project(':distribution:archives:linux-tar')
integTestRuntimeOnly(project(":libs:elasticsearch-core"))
}
// for external projects we want to remove the marker file indicating we are running the Elasticsearch project
tasks.named("processResources").configure {
exclude 'buildSrc.marker'
into('META-INF') {
from configurations.reaper
}
}
tasks.withType(Test).configureEach {
// Track reaper jar as a test input using runtime classpath normalization strategy
inputs.files(configurations.reaper).withNormalizer(ClasspathNormalizer)
useJUnitPlatform()
}
tasks.named("test").configure {
include("**/*TestSpec.class")
}
normalization {
runtimeClasspath {
// We already include the reaper jar as part of our runtime classpath. Ignore the copy in META-INF.
ignore('META-INF/reaper.jar')
}
}
tasks.named("forbiddenPatterns").configure {
exclude '**/*.wav'
exclude '**/*.p12'
exclude '**/*.jks'
exclude '**/*.crt'
// the file that actually defines nocommit
exclude '**/ForbiddenPatternsTask.java'
exclude '**/*.bcfks'
}
tasks.named("testingConventions") {
naming.clear()
naming {
Tests {
baseClass 'org.elasticsearch.gradle.internal.test.GradleUnitTestCase'
}
TestSpec {
baseClass 'spock.lang.Specification'
}
}
}
tasks.register("integTest", Test) {
inputs.dir(file("src/testKit")).withPropertyName("testkit dir").withPathSensitivity(PathSensitivity.RELATIVE)
systemProperty 'test.version_under_test', version
@ -416,65 +260,3 @@ if (project != rootProject) {
classpath = sourceSets.integTest.runtimeClasspath
useJUnitPlatform()
}
tasks.named("check").configure { dependsOn("integTest") }
// for now we hardcode the tests for our build to use the gradle jvm.
tasks.withType(Test).configureEach {
onlyIf { org.elasticsearch.gradle.internal.info.BuildParams.inFipsJvm == false }
it.executable = Jvm.current().getJavaExecutable()
maxParallelForks = providers.systemProperty('tests.jvms').forUseAtConfigurationTime().getOrElse(org.elasticsearch.gradle.internal.info.BuildParams.defaultParallel.toString()) as Integer
}
publishing.publications.named("elastic").configure {
suppressPomMetadataWarningsFor("testFixturesApiElements")
suppressPomMetadataWarningsFor("testFixturesRuntimeElements")
}
}
// Define this here because we need it early.
class VersionPropertiesLoader {
static Properties loadBuildSrcVersion(File input) throws IOException {
Properties props = new Properties();
InputStream is = new FileInputStream(input)
try {
props.load(is)
} finally {
is.close()
}
loadBuildSrcVersion(props, System.getProperties())
return props
}
protected static void loadBuildSrcVersion(Properties loadedProps, Properties systemProperties) {
String elasticsearch = loadedProps.getProperty("elasticsearch")
if (elasticsearch == null) {
throw new IllegalStateException("Elasticsearch version is missing from properties.")
}
if (elasticsearch.matches("[0-9]+\\.[0-9]+\\.[0-9]+") == false) {
throw new IllegalStateException(
"Expected elasticsearch version to be numbers only of the form X.Y.Z but it was: " +
elasticsearch
)
}
String qualifier = systemProperties.getProperty("build.version_qualifier", "")
if (qualifier.isEmpty() == false) {
if (qualifier.matches("(alpha|beta|rc)\\d+") == false) {
throw new IllegalStateException("Invalid qualifier: " + qualifier)
}
elasticsearch += "-" + qualifier
}
final String buildSnapshotSystemProperty = systemProperties.getProperty("build.snapshot", "true");
switch (buildSnapshotSystemProperty) {
case "true":
elasticsearch += "-SNAPSHOT"
break;
case "false":
// do nothing
break;
default:
throw new IllegalArgumentException(
"build.snapshot was set to [" + buildSnapshotSystemProperty + "] but can only be unset or [true|false]");
}
loadedProps.put("elasticsearch", elasticsearch)
}
}

View file

@ -0,0 +1,7 @@
#Eclipse configuration for import order for Elasticsearch
0=
1=com
2=org
3=java
4=javax
5=\#

View file

@ -0,0 +1,2 @@
includeBuild '../build-conventions'
includeBuild '../build-tools'

View file

@ -9,6 +9,7 @@
package org.elasticsearch.gradle.fixtures
import org.apache.commons.io.FileUtils
import org.elasticsearch.gradle.internal.test.InternalAwareGradleRunner
import org.gradle.testkit.runner.GradleRunner
import org.junit.Rule
import org.junit.rules.TemporaryFolder

View file

@ -10,8 +10,10 @@ package org.elasticsearch.gradle.internal
import org.elasticsearch.gradle.fixtures.AbstractGradleFuncTest
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Ignore
import org.xmlunit.builder.DiffBuilder
import org.xmlunit.builder.Input
import spock.lang.IgnoreRest
class PublishPluginFuncTest extends AbstractGradleFuncTest {
@ -38,15 +40,41 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
file("build/distributions/hello-world-1.0-sources.jar").exists()
file("build/distributions/hello-world-1.0.pom").exists()
assertXmlEquals(file("build/distributions/hello-world-1.0.pom").text, """
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>hello-world</artifactId>
<version>1.0</version>
<name>hello-world</name>
<description>custom project description</description>
<url>unknown</url>
<scm>
<url>unknown</url>
</scm>
<inceptionYear>2009</inceptionYear>
<licenses>
<license>
<name>Elastic License 2.0</name>
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/ELASTIC-LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
<license>
<name>Server Side Public License, v 1</name>
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>Elastic</name>
<url>https://www.elastic.co</url>
</developer>
</developers>
</project>"""
)
}
@ -99,6 +127,29 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
<version>1.0</version>
<name>hello-world</name>
<description>some description</description>
<url>unknown</url>
<scm>
<url>unknown</url>
</scm>
<inceptionYear>2009</inceptionYear>
<licenses>
<license>
<name>Elastic License 2.0</name>
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/ELASTIC-LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
<license>
<name>Server Side Public License, v 1</name>
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>Elastic</name>
<url>https://www.elastic.co</url>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
@ -160,6 +211,29 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
<version>1.0</version>
<name>hello-world</name>
<description>some description</description>
<url>unknown</url>
<scm>
<url>unknown</url>
</scm>
<inceptionYear>2009</inceptionYear>
<licenses>
<license>
<name>Elastic License 2.0</name>
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/ELASTIC-LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
<license>
<name>Server Side Public License, v 1</name>
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>Elastic</name>
<url>https://www.elastic.co</url>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.acme</groupId>
@ -216,15 +290,41 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
file("build/distributions/hello-world-plugin-1.0-sources.jar").exists()
file("build/distributions/hello-world-plugin-1.0.pom").exists()
assertXmlEquals(file("build/distributions/hello-world-plugin-1.0.pom").text, """
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>hello-world-plugin</artifactId>
<version>1.0</version>
<name>hello-world</name>
<description>custom project description</description>
<url>unknown</url>
<scm>
<url>unknown</url>
</scm>
<inceptionYear>2009</inceptionYear>
<licenses>
<license>
<name>Elastic License 2.0</name>
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/ELASTIC-LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
<license>
<name>Server Side Public License, v 1</name>
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>Elastic</name>
<url>https://www.elastic.co</url>
</developer>
</developers>
<dependencies/>
</project>"""
)
@ -250,7 +350,7 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
tasks.named('bundlePlugin').configure { enabled = false }
licenseFile = file('license.txt')
noticeFile = file('notice.txt')
version = "1.0"
version = "2.0"
group = 'org.acme'
"""
@ -259,22 +359,48 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
then:
result.task(":generatePom").outcome == TaskOutcome.SUCCESS
file("build/distributions/hello-world-plugin-1.0.pom").exists()
assertXmlEquals(file("build/distributions/hello-world-plugin-1.0.pom").text, """
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
file("build/distributions/hello-world-plugin-2.0.pom").exists()
assertXmlEquals(file("build/distributions/hello-world-plugin-2.0.pom").text, """
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>hello-world-plugin</artifactId>
<version>1.0</version>
<version>2.0</version>
<name>hello-world</name>
<description>custom project description</description>
<url>unknown</url>
<scm>
<url>unknown</url>
</scm>
<inceptionYear>2009</inceptionYear>
<licenses>
<license>
<name>Elastic License 2.0</name>
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v2.0/licenses/ELASTIC-LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
<license>
<name>Server Side Public License, v 1</name>
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>Elastic</name>
<url>https://www.elastic.co</url>
</developer>
</developers>
</project>"""
)
}
def "generated pom can be tweaked and validated"() {
def "generated pom can be validated"() {
given:
// scm info only added for internal builds
internalBuild()
@ -288,58 +414,37 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
group = 'org.acme'
description = "just a test project"
// this is currently required to have validation passed
// In our elasticsearch build this is currently setup in the
// root build.gradle file.
plugins.withType(MavenPublishPlugin) {
publishing {
publications {
// add license information to generated poms
all {
pom.withXml { XmlProvider xml ->
Node node = xml.asNode()
node.appendNode('inceptionYear', '2009')
Node license = node.appendNode('licenses').appendNode('license')
license.appendNode('name', "The Apache Software License, Version 2.0")
license.appendNode('url', "http://www.apache.org/licenses/LICENSE-2.0.txt")
license.appendNode('distribution', 'repo')
Node developer = node.appendNode('developers').appendNode('developer')
developer.appendNode('name', 'Elastic')
developer.appendNode('url', 'https://www.elastic.co')
}
}
}
}
}
ext.projectLicenses.set(['The Apache Software License, Version 2.0': 'http://www.apache.org/licenses/LICENSE-2.0'])
"""
when:
def result = gradleRunner('generatePom', 'validatElasticPom').build()
def result = gradleRunner('generatePom', 'validateElasticPom').build()
then:
result.task(":generatePom").outcome == TaskOutcome.SUCCESS
file("build/distributions/hello-world-1.0.pom").exists()
assertXmlEquals(file("build/distributions/hello-world-1.0.pom").text, """
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>hello-world</artifactId>
<version>1.0</version>
<name>hello-world</name>
<description>just a test project</description>
<url>https://some-repo.com/repo.git</url>
<url>unknown</url>
<scm>
<url>https://some-repo.com/repo.git</url>
<url>unknown</url>
</scm>
<inceptionYear>2009</inceptionYear>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>

View file

@ -0,0 +1,368 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.test.rest
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SequenceWriter
import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import org.elasticsearch.gradle.Version
import org.elasticsearch.gradle.fixtures.AbstractRestResourcesFuncTest
import org.elasticsearch.gradle.VersionProperties
import org.gradle.testkit.runner.TaskOutcome
class YamlRestCompatTestPluginFuncTest extends AbstractRestResourcesFuncTest {
def compatibleVersion = Version.fromString(VersionProperties.getVersions().get("elasticsearch")).getMajor() - 1
def specIntermediateDir = "restResources/v${compatibleVersion}/yamlSpecs"
def testIntermediateDir = "restResources/v${compatibleVersion}/yamlTests"
def transformTask = ":transformV${compatibleVersion}RestTests"
def YAML_FACTORY = new YAMLFactory()
def MAPPER = new ObjectMapper(YAML_FACTORY)
def READER = MAPPER.readerFor(ObjectNode.class)
def WRITER = MAPPER.writerFor(ObjectNode.class)
def "yamlRestCompatTest does nothing when there are no tests"() {
given:
addSubProject(":distribution:bwc:minor") << """
configurations { checkout }
artifacts {
checkout(new File(projectDir, "checkoutDir"))
}
"""
buildFile << """
plugins {
id 'elasticsearch.yaml-rest-compat-test'
}
"""
when:
def result = gradleRunner("yamlRestCompatTest").build()
then:
result.task(':yamlRestCompatTest').outcome == TaskOutcome.NO_SOURCE
result.task(':copyRestCompatApiTask').outcome == TaskOutcome.NO_SOURCE
result.task(':copyRestCompatTestTask').outcome == TaskOutcome.NO_SOURCE
result.task(transformTask).outcome == TaskOutcome.NO_SOURCE
}
def "yamlRestCompatTest executes and copies api and transforms tests from :bwc:minor"() {
given:
internalBuild()
addSubProject(":distribution:bwc:minor") << """
configurations { checkout }
artifacts {
checkout(new File(projectDir, "checkoutDir"))
}
"""
buildFile << """
apply plugin: 'elasticsearch.yaml-rest-compat-test'
// avoids a dependency problem in this test, the distribution in use here is inconsequential to the test
import org.elasticsearch.gradle.testclusters.TestDistribution;
dependencies {
yamlRestTestImplementation "junit:junit:4.12"
}
// can't actually spin up test cluster from this test
tasks.withType(Test).configureEach{ enabled = false }
"""
String wrongApi = "wrong_version.json"
String wrongTest = "wrong_version.yml"
String additionalTest = "additional_test.yml"
setupRestResources([wrongApi], [wrongTest]) //setups up resources for current version, which should not be used for this test
addRestTestsToProject([additionalTest], "yamlRestCompatTest")
//intentionally adding to yamlRestTest source set since the .classes are copied from there
file("src/yamlRestTest/java/MockIT.java") << "import org.junit.Test;class MockIT { @Test public void doNothing() { }}"
String api = "foo.json"
String test = "10_basic.yml"
//add the compatible test and api files, these are the prior version's normal yaml rest tests
file("distribution/bwc/minor/checkoutDir/rest-api-spec/src/main/resources/rest-api-spec/api/" + api) << ""
file("distribution/bwc/minor/checkoutDir/src/yamlRestTest/resources/rest-api-spec/test/" + test) << ""
when:
def result = gradleRunner("yamlRestCompatTest").build()
then:
result.task(':yamlRestCompatTest').outcome == TaskOutcome.SKIPPED
result.task(':copyRestCompatApiTask').outcome == TaskOutcome.SUCCESS
result.task(':copyRestCompatTestTask').outcome == TaskOutcome.SUCCESS
result.task(transformTask).outcome == TaskOutcome.SUCCESS
file("/build/${specIntermediateDir}/rest-api-spec/api/" + api).exists()
file("/build/${testIntermediateDir}/original/rest-api-spec/test/" + test).exists()
file("/build/${testIntermediateDir}/transformed/rest-api-spec/test/" + test).exists()
file("/build/${testIntermediateDir}/original/rest-api-spec/test/" + test).exists()
file("/build/${testIntermediateDir}/transformed/rest-api-spec/test/" + test).exists()
file("/build/${testIntermediateDir}/transformed/rest-api-spec/test/" + test).text.contains("headers") //transformation adds this
file("/build/resources/yamlRestCompatTest/rest-api-spec/test/" + additionalTest).exists()
//additionalTest is not copied from the prior version, and thus not in the intermediate directory, nor transformed
file("/build/resources/yamlRestCompatTest/" + testIntermediateDir + "/rest-api-spec/test/" + additionalTest).exists() == false
file("/build/resources/yamlRestCompatTest/rest-api-spec/test/" + additionalTest).text.contains("headers") == false
file("/build/classes/java/yamlRestTest/MockIT.class").exists() //The "standard" runner is used to execute the compat test
file("/build/resources/yamlRestCompatTest/rest-api-spec/api/" + wrongApi).exists() == false
file("/build/resources/yamlRestCompatTest/" + testIntermediateDir + "/rest-api-spec/test/" + wrongTest).exists() == false
file("/build/resources/yamlRestCompatTest/rest-api-spec/test/" + wrongTest).exists() == false
result.task(':copyRestApiSpecsTask').outcome == TaskOutcome.NO_SOURCE
result.task(':copyYamlTestsTask').outcome == TaskOutcome.NO_SOURCE
when:
result = gradleRunner("yamlRestCompatTest").build()
then:
result.task(':yamlRestCompatTest').outcome == TaskOutcome.SKIPPED
result.task(':copyRestCompatApiTask').outcome == TaskOutcome.UP_TO_DATE
result.task(':copyRestCompatTestTask').outcome == TaskOutcome.UP_TO_DATE
result.task(transformTask).outcome == TaskOutcome.UP_TO_DATE
}
def "yamlRestCompatTest is wired into check and checkRestCompat"() {
given:
addSubProject(":distribution:bwc:minor") << """
configurations { checkout }
artifacts {
checkout(new File(projectDir, "checkoutDir"))
}
"""
buildFile << """
plugins {
id 'elasticsearch.yaml-rest-compat-test'
}
"""
when:
def result = gradleRunner("check").build()
then:
result.task(':check').outcome == TaskOutcome.UP_TO_DATE
result.task(':checkRestCompat').outcome == TaskOutcome.UP_TO_DATE
result.task(':yamlRestCompatTest').outcome == TaskOutcome.NO_SOURCE
result.task(':copyRestCompatApiTask').outcome == TaskOutcome.NO_SOURCE
result.task(':copyRestCompatTestTask').outcome == TaskOutcome.NO_SOURCE
result.task(transformTask).outcome == TaskOutcome.NO_SOURCE
when:
buildFile << """
ext.bwc_tests_enabled = false
"""
result = gradleRunner("check").build()
then:
result.task(':check').outcome == TaskOutcome.UP_TO_DATE
result.task(':checkRestCompat').outcome == TaskOutcome.UP_TO_DATE
result.task(':yamlRestCompatTest').outcome == TaskOutcome.SKIPPED
result.task(':copyRestCompatApiTask').outcome == TaskOutcome.SKIPPED
result.task(':copyRestCompatTestTask').outcome == TaskOutcome.SKIPPED
result.task(transformTask).outcome == TaskOutcome.SKIPPED
}
def "transform task executes and works as configured"() {
given:
internalBuild()
addSubProject(":distribution:bwc:minor") << """
configurations { checkout }
artifacts {
checkout(new File(projectDir, "checkoutDir"))
}
"""
buildFile << """
apply plugin: 'elasticsearch.yaml-rest-compat-test'
// avoids a dependency problem in this test, the distribution in use here is inconsequential to the test
import org.elasticsearch.gradle.testclusters.TestDistribution;
dependencies {
yamlRestTestImplementation "junit:junit:4.12"
}
tasks.named("transformV7RestTests").configure({ task ->
task.replaceValueInMatch("_type", "_doc")
task.replaceValueInMatch("_source.values", ["z", "x", "y"], "one")
task.removeMatch("_source.blah")
task.removeMatch("_source.junk", "two")
task.addMatch("_source.added", [name: 'jake', likes: 'cheese'], "one")
task.addWarning("one", "warning1", "warning2")
task.addWarningRegex("two", "regex warning here .* [a-z]")
task.addAllowedWarning("added allowed warning")
task.addAllowedWarningRegex("added allowed warning regex .* [0-9]")
task.removeWarning("one", "warning to remove")
task.replaceIsTrue("value_to_replace", "replaced_value")
task.replaceIsFalse("value_to_replace", "replaced_value")
task.replaceKeyInDo("do_.some.key_to_replace", "do_.some.key_that_was_replaced")
task.replaceKeyInMatch("match_.some.key_to_replace", "match_.some.key_that_was_replaced")
task.replaceKeyInLength("key.in_length_to_replace", "key.in_length_that_was_replaced")
})
// can't actually spin up test cluster from this test
tasks.withType(Test).configureEach{ enabled = false }
"""
setupRestResources([], [])
file("distribution/bwc/minor/checkoutDir/src/yamlRestTest/resources/rest-api-spec/test/test.yml" ) << """
"one":
- do:
do_.some.key_to_replace:
index: test
id: 1
warnings:
- "warning to remove"
- match: { _source.values: ["foo"] }
- match: { _type: "_foo" }
- match: { _source.blah: 1234 }
- match: { _source.junk: true }
- match: { match_.some.key_to_replace: true }
- is_true: "value_to_replace"
- is_false: "value_to_replace"
- is_true: "value_not_to_replace"
- is_false: "value_not_to_replace"
- length: { key.in_length_to_replace: 1 }
---
"two":
- do:
get:
index: test
id: 1
- match: { _source.values: ["foo"] }
- match: { _type: "_foo" }
- match: { _source.blah: 1234 }
- match: { _source.junk: true }
- is_true: "value_to_replace"
- is_false: "value_to_replace"
- is_true: "value_not_to_replace"
- is_false: "value_not_to_replace"
""".stripIndent()
when:
def result = gradleRunner("yamlRestCompatTest").build()
then:
result.task(transformTask).outcome == TaskOutcome.SUCCESS
file("/build/${testIntermediateDir}/transformed/rest-api-spec/test/test.yml" ).exists()
List<ObjectNode> actual = READER.readValues(file("/build/${testIntermediateDir}/transformed/rest-api-spec/test/test.yml")).readAll()
List<ObjectNode> expectedAll = READER.readValues(
"""
---
setup:
- skip:
features:
- "headers"
- "warnings"
- "warnings_regex"
- "allowed_warnings"
- "allowed_warnings_regex"
---
one:
- do:
do_.some.key_that_was_replaced:
index: "test"
id: 1
warnings:
- "warning1"
- "warning2"
headers:
Content-Type: "application/vnd.elasticsearch+json;compatible-with=7"
Accept: "application/vnd.elasticsearch+json;compatible-with=7"
allowed_warnings:
- "added allowed warning"
allowed_warnings_regex:
- "added allowed warning regex .* [0-9]"
- match:
_source.values:
- "z"
- "x"
- "y"
- match:
_type: "_doc"
- match: {}
- match:
_source.junk: true
- match:
match_.some.key_that_was_replaced: true
- is_true: "replaced_value"
- is_false: "replaced_value"
- is_true: "value_not_to_replace"
- is_false: "value_not_to_replace"
- length: { key.in_length_that_was_replaced: 1 }
- match:
_source.added:
name: "jake"
likes: "cheese"
---
two:
- do:
get:
index: "test"
id: 1
headers:
Content-Type: "application/vnd.elasticsearch+json;compatible-with=7"
Accept: "application/vnd.elasticsearch+json;compatible-with=7"
warnings_regex:
- "regex warning here .* [a-z]"
allowed_warnings:
- "added allowed warning"
allowed_warnings_regex:
- "added allowed warning regex .* [0-9]"
- match:
_source.values:
- "foo"
- match:
_type: "_doc"
- match: {}
- match: {}
- is_true: "replaced_value"
- is_false: "replaced_value"
- is_true: "value_not_to_replace"
- is_false: "value_not_to_replace"
""".stripIndent()).readAll()
expectedAll.eachWithIndex{ ObjectNode expected, int i ->
if(expected != actual.get(i)) {
println("\nTransformed Test:")
SequenceWriter sequenceWriter = WRITER.writeValues(System.out)
for (ObjectNode transformedTest : actual) {
sequenceWriter.write(transformedTest)
}
sequenceWriter.close()
}
assert expected == actual.get(i)
}
when:
result = gradleRunner(transformTask).build()
then:
result.task(transformTask).outcome == TaskOutcome.UP_TO_DATE
when:
buildFile.write(buildFile.text.replace("blah", "baz"))
result = gradleRunner(transformTask).build()
then:
result.task(transformTask).outcome == TaskOutcome.SUCCESS
}
}

View file

@ -46,11 +46,8 @@ public class BuildPluginIT extends GradleIntegrationTestCase {
public void testLicenseAndNotice() throws IOException {
BuildResult result = getGradleRunner().withArguments("clean", "assemble").build();
assertTaskSuccessful(result, ":assemble");
assertBuildFileExists(result, projectName(), "distributions/elasticsearch.build.jar");
try (ZipFile zipFile = new ZipFile(new File(getBuildDir(projectName()), "distributions/elasticsearch.build.jar"))) {
ZipEntry licenseEntry = zipFile.getEntry("META-INF/LICENSE.txt");
ZipEntry noticeEntry = zipFile.getEntry("META-INF/NOTICE.txt");

View file

@ -0,0 +1,82 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.test;
import java.io.File;
import java.io.IOException;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Ownership;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
import net.bytebuddy.implementation.ExceptionMethod;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
import static org.junit.Assert.fail;
public class TestClasspathUtils {
public static void setupJarJdkClasspath(File projectRoot) {
generateJdkJarHellCheck(projectRoot, FixedValue.value(TypeDescription.VOID));
}
public static void setupJarJdkClasspath(File projectRoot, String errorMessage) {
generateJdkJarHellCheck(projectRoot,
ExceptionMethod.throwing(IllegalStateException.class, errorMessage));
}
private static void generateJdkJarHellCheck(File projectRoot, Implementation mainImplementation) {
DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("org.elasticsearch.bootstrap.JdkJarHellCheck")
.defineMethod("main", void.class, Visibility.PUBLIC, Ownership.STATIC)
.withParameters(String[].class)
.intercept(mainImplementation)
.make();
try {
dynamicType.toJar(targetFile(projectRoot));
} catch (IOException e) {
e.printStackTrace();
fail("Cannot setup jdk jar hell classpath");
}
}
private static File targetFile(File projectRoot) {
File targetFile = new File(
projectRoot,
"sample_jars/build/testrepo/org/elasticsearch/elasticsearch-core/current/elasticsearch-core-current.jar"
);
targetFile.getParentFile().mkdirs();
return targetFile;
}
private static class InconsistentParameterReferenceMethod implements net.bytebuddy.implementation.Implementation {
@Override
public ByteCodeAppender appender(Target implementationTarget) {
return null;
}
@Override
public InstrumentedType prepare(InstrumentedType instrumentedType) {
return null;
}
}
public static class JdkJarHellBase {
public static void main(String[] args) {
System.out.println("args = " + args);
}
}
}

View file

@ -5,7 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.precommit;
package org.elasticsearch.gradle.jarhell;
import org.elasticsearch.gradle.internal.test.GradleIntegrationTestCase;
import org.gradle.testkit.runner.BuildResult;

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.precommit;
package org.elasticsearch.gradle.jarhell;
import org.elasticsearch.gradle.internal.test.GradleIntegrationTestCase;
import org.gradle.testkit.runner.BuildResult;
@ -26,7 +26,6 @@ public class ThirdPartyAuditTaskIT extends GradleIntegrationTestCase {
// Build the sample jars
getGradleRunner().withArguments(":sample_jars:build", "-s").build();
// propagate jdkjarhell jar
setupJarJdkClasspath(getProjectDir());
}
public void testElasticsearchIgnored() {
@ -44,6 +43,8 @@ public class ThirdPartyAuditTaskIT extends GradleIntegrationTestCase {
}
public void testViolationFoundAndCompileOnlyIgnored() {
setupJarJdkClasspath(getProjectDir());
BuildResult result = getGradleRunner().withArguments(
":clean",
":absurd",
@ -61,6 +62,7 @@ public class ThirdPartyAuditTaskIT extends GradleIntegrationTestCase {
}
public void testClassNotFoundAndCompileOnlyIgnored() {
setupJarJdkClasspath(getProjectDir());
BuildResult result = getGradleRunner().withArguments(
":clean",
":absurd",
@ -83,6 +85,10 @@ public class ThirdPartyAuditTaskIT extends GradleIntegrationTestCase {
}
public void testJarHellWithJDK() {
setupJarJdkClasspath(getProjectDir(), "> Audit of third party dependencies failed:" +
" Jar Hell with the JDK:" +
" * java.lang.String"
);
BuildResult result = getGradleRunner().withArguments(
":clean",
":absurd",

View file

@ -170,7 +170,7 @@ subprojects {
target 'src/**/*.java'
removeUnusedImports()
eclipse().configFile rootProject.file('buildSrc/formatterConfig.xml')
eclipse().configFile rootProject.file('build-tools-internal/formatterConfig.xml')
trimTrailingWhitespace()
// See CONTRIBUTING.md for details of when to enabled this.

View file

@ -13,17 +13,6 @@ import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:0.7"
}
}
allprojects {
apply plugin: 'idea'
@ -36,9 +25,9 @@ tasks.register('configureIdeCheckstyle') {
group = 'ide'
description = 'Generated a suitable checkstyle config for IDEs'
String checkstyleConfig = 'buildSrc/src/main/resources/checkstyle.xml'
String checkstyleSuppressions = 'buildSrc/src/main/resources/checkstyle_suppressions.xml'
String checkstyleIdeFragment = 'buildSrc/src/main/resources/checkstyle_ide_fragment.xml'
String checkstyleConfig = 'build-tools-internal/src/main/resources/checkstyle.xml'
String checkstyleSuppressions = 'build-tools-internal/src/main/resources/checkstyle_suppressions.xml'
String checkstyleIdeFragment = 'build-tools-internal/src/main/resources/checkstyle_ide_fragment.xml'
String checkstyleIdeConfig = "$rootDir/checkstyle_ide.xml"
inputs.files(file(checkstyleConfig), file(checkstyleIdeFragment))

View file

@ -16,7 +16,7 @@ import org.elasticsearch.gradle.internal.info.BuildParams
// apply plugin: 'elasticsearch.jdk-download'
if (BuildParams.getIsRuntimeJavaHomeSet()) {
configure(allprojects - project(':build-tools')) {
configure(allprojects) {
project.tasks.withType(Test).configureEach { Test test ->
if (BuildParams.getIsRuntimeJavaHomeSet()) {
test.executable = "${BuildParams.runtimeJavaHome}/bin/java"
@ -33,7 +33,7 @@ if (BuildParams.getIsRuntimeJavaHomeSet()) {
}
}
configure(allprojects - project(':build-tools')) {
configure(allprojects) {
project.tasks.withType(Test).configureEach { Test test ->
test.dependsOn(rootProject.jdks.provisioned_runtime)
test.executable = rootProject.jdks.provisioned_runtime.getBinJavaPath()

View file

@ -9,7 +9,6 @@
package org.elasticsearch.gradle.internal
import org.apache.tools.ant.taskdefs.condition.Os
import org.elasticsearch.gradle.FixtureStop
import org.elasticsearch.gradle.LoggedExec
import org.elasticsearch.gradle.internal.test.AntFixture
import org.gradle.api.file.FileSystemOperations

Some files were not shown because too many files have changed in this diff Show more