Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
18c548d
Replace transport version utils with a build service
rjernst Aug 16, 2025
303ba81
[CI] Auto commit changes from spotless
Aug 16, 2025
4523585
Mute org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT test {…
elasticsearchmachine Aug 16, 2025
67effbd
Mute org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT test {…
elasticsearchmachine Aug 17, 2025
f1699d8
Enable doc partitioning by default for time-series queries (#133038)
dnhatn Aug 18, 2025
3f3a7c1
Streamline and optimize check to use decode or decode ordinals. (#133…
martijnvg Aug 18, 2025
9089ab5
Fix update expiration for async query (#133021)
dnhatn Aug 18, 2025
a10d8e3
Slightly improve TrackingPostingsInMemoryBytesCodec (#132905)
martijnvg Aug 18, 2025
88c3bcd
Mute org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT test {…
elasticsearchmachine Aug 18, 2025
052a93d
Remove DocumentParserContext#removeLastIgnoredField(...) (#132644)
martijnvg Aug 18, 2025
f371deb
Shorten metadata.name of PR benchmark pipeline (#133054)
gbanasiak Aug 18, 2025
896e383
Expose existing DLS cache x-pack usage statistics (#132845)
szybia Aug 18, 2025
5a2a931
Mute org.elasticsearch.upgrades.SyntheticSourceRollingUpgradeIT testI…
elasticsearchmachine Aug 18, 2025
905372d
Mute org.elasticsearch.upgrades.SyntheticSourceRollingUpgradeIT testI…
elasticsearchmachine Aug 18, 2025
b2bdea8
Document index setting around source metadata field. (#127000)
martijnvg Aug 18, 2025
a654a33
Fix typos in plugin-management.md (#133062)
LolloneS Aug 18, 2025
e96297a
Text field dynamic field tweak (#129332)
martijnvg Aug 18, 2025
499bba4
Adds BBQ documentation to the Reference content (#133066)
kosabogi Aug 18, 2025
4b10b7a
[ML] Disable child span for streaming tasks (#132945)
prwhelan Aug 18, 2025
754696b
Add index mode to resolve index response. (#132858)
seanzatzdev Aug 18, 2025
110f62d
Mute org.elasticsearch.xpack.test.rest.XPackRestIT test {p0=esql/60_u…
elasticsearchmachine Aug 18, 2025
61112c7
Esql dimension aware attributes (#131463)
not-napoleon Aug 18, 2025
d183b39
Update TasksIT for batched execution (#132762)
benchaplin Aug 18, 2025
190757e
Change reporting_user role to leverage reserved kibana privileges (#1…
legrego Aug 18, 2025
3d141fe
Expose APIs needed by flush during translog replay (#132960)
lkts Aug 18, 2025
0ba4a31
Enable `exclude_source_vectors` by default for new indices (#131907)
jimczi Aug 18, 2025
ca2b79d
migrate ml_rollover_legacy_indices transport version (#133008)
jdconrad Aug 18, 2025
09b6d9c
address feedback
rjernst Aug 18, 2025
e6cec60
reword
rjernst Aug 18, 2025
2743bbc
Merge branch 'main' into transport/build_service
rjernst Aug 18, 2025
bfd07d4
Merge branch 'main' into transport/build_service
rjernst Aug 18, 2025
2874ff0
[CI] Auto commit changes from spotless
Aug 18, 2025
1d151ea
Merge branch 'main' into transport/build_service
rjernst Aug 19, 2025
e5f5101
fix
rjernst Aug 19, 2025
c67a164
skip non-existing
rjernst Aug 19, 2025
ac9ce1b
use correct path
rjernst Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
package org.elasticsearch.gradle.internal.transport;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.services.ServiceReference;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskAction;

import java.io.IOException;
Expand All @@ -24,15 +28,24 @@
import java.nio.file.attribute.BasicFileAttributes;

public abstract class GenerateTransportVersionManifestTask extends DefaultTask {

@ServiceReference("transportVersionResources")
abstract Property<TransportVersionResourcesService> getTransportResources();

@InputDirectory
public abstract DirectoryProperty getDefinitionsDirectory();
@Optional
@PathSensitive(PathSensitivity.RELATIVE)
public Path getDefinitionsDirectory() {
return getTransportResources().get().getDefinitionsDir();
}

@OutputFile
public abstract RegularFileProperty getManifestFile();

@TaskAction
public void generateTransportVersionManifest() throws IOException {
Path definitionsDir = getDefinitionsDirectory().get().getAsFile().toPath();

Path definitionsDir = getDefinitionsDirectory();
Path manifestFile = getManifestFile().get().getAsFile().toPath();
try (var writer = Files.newBufferedWriter(manifestFile)) {
Files.walkFileTree(definitionsDir, new SimpleFileVisitor<>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
import org.gradle.api.attributes.Attribute;
import org.gradle.api.attributes.AttributeContainer;

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.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static org.gradle.api.artifacts.type.ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE;

Expand All @@ -43,6 +46,14 @@ static void addArtifactAttribute(AttributeContainer attributes) {
attributes.attribute(REFERENCES_ATTRIBUTE, true);
}

static Set<String> collectNames(Iterable<File> referencesFiles) throws IOException {
Set<String> names = new HashSet<>();
for (var referencesFile : referencesFiles) {
listFromFile(referencesFile.toPath()).stream().map(TransportVersionReference::name).forEach(names::add);
}
return names;
}

@Override
public String toString() {
return name + "," + location;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.Directory;
import org.gradle.api.tasks.SourceSet;
import org.gradle.language.base.plugins.LifecycleBasePlugin;

import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getDefinitionsDirectory;
import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getResourcesDirectory;

public class TransportVersionReferencesPlugin implements Plugin<Project> {

@Override
Expand All @@ -46,10 +42,6 @@ public void apply(Project project) {
.register("validateTransportVersionReferences", ValidateTransportVersionReferencesTask.class, t -> {
t.setGroup("Transport Versions");
t.setDescription("Validates that all TransportVersion references used in the project have an associated definition file");
Directory definitionsDir = getDefinitionsDirectory(getResourcesDirectory(project));
if (definitionsDir.getAsFile().exists()) {
t.getDefinitionsDirectory().set(definitionsDir);
}
t.getReferencesFile().set(collectTask.get().getOutputFile());
});
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME).configure(t -> t.dependsOn(validateTask));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,22 @@

import java.util.Map;

import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getDefinitionsDirectory;
import static org.elasticsearch.gradle.internal.transport.TransportVersionUtils.getResourcesDirectory;

public class TransportVersionResourcesPlugin implements Plugin<Project> {

@Override
public void apply(Project project) {
project.getPluginManager().apply(LifecycleBasePlugin.class);

String resourceRoot = getResourceRoot(project);

project.getGradle()
.getSharedServices()
.registerIfAbsent("transportVersionResources", TransportVersionResourcesService.class, spec -> {
Directory transportResources = project.getLayout().getProjectDirectory().dir("src/main/resources/" + resourceRoot);
spec.getParameters().getTransportResourcesDirectory().set(transportResources);
spec.getParameters().getRootDirectory().set(project.getRootProject().getRootDir());
});

DependencyHandler depsHandler = project.getDependencies();
Configuration tvReferencesConfig = project.getConfigurations().create("globalTvReferences");
tvReferencesConfig.setCanBeConsumed(false);
Expand All @@ -46,10 +53,6 @@ public void apply(Project project) {
.register("validateTransportVersionDefinitions", ValidateTransportVersionResourcesTask.class, t -> {
t.setGroup("Transport Versions");
t.setDescription("Validates that all defined TransportVersion constants are used in at least one project");
Directory resourcesDir = getResourcesDirectory(project);
if (resourcesDir.getAsFile().exists()) {
t.getResourcesDirectory().set(resourcesDir);
}
t.getReferencesFiles().setFrom(tvReferencesConfig);
});
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME).configure(t -> t.dependsOn(validateTask));
Expand All @@ -58,12 +61,18 @@ public void apply(Project project) {
.register("generateTransportVersionManifest", GenerateTransportVersionManifestTask.class, t -> {
t.setGroup("Transport Versions");
t.setDescription("Generate a manifest resource for all the known transport version definitions");
t.getDefinitionsDirectory().set(getDefinitionsDirectory(getResourcesDirectory(project)));
t.getManifestFile().set(project.getLayout().getBuildDirectory().file("generated-resources/manifest.txt"));
});
String resourceRoot = TransportVersionUtils.getResourceRoot(project);
project.getTasks().named(JavaPlugin.PROCESS_RESOURCES_TASK_NAME, Copy.class).configure(t -> {
t.into(resourceRoot + "/definitions", c -> c.from(generateManifestTask));
});
}

private static String getResourceRoot(Project project) {
var resourceRoot = project.findProperty("org.elasticsearch.transport.resourceRoot");
if (resourceRoot == null) {
resourceRoot = "transport";
}
return resourceRoot.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.gradle.internal.transport;

import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.services.BuildService;
import org.gradle.api.services.BuildServiceParameters;
import org.gradle.process.ExecOperations;
import org.gradle.process.ExecResult;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;

import javax.inject.Inject;

/**
* An encapsulation of operations on transport version resources.
*
* <p>These are resource files to describe transport versions that will be loaded at Elasticsearch runtime. They exist
* as jar resource files at runtime, and as a directory of resources at build time.
*
* <p>The layout of the transport version resources are as follows:
* <ul>
* <li><b>/transport/definitions/named/</b>
* - Definitions that can be looked up by name. The name is the filename before the .csv suffix.</li>
* <li><b>/transport/definitions/unreferenced/</b>
* - Definitions which contain ids that are known at runtime, but cannot be looked up by name.</li>
* <li><b>/transport/latest/</b>
* - The latest transport version definition for each release branch.</li>
* </ul>
*/
public abstract class TransportVersionResourcesService implements BuildService<TransportVersionResourcesService.Parameters> {

public interface Parameters extends BuildServiceParameters {
DirectoryProperty getTransportResourcesDirectory();

DirectoryProperty getRootDirectory();
}

@Inject
public abstract ExecOperations getExecOperations();

private static final Path DEFINITIONS_DIR = Path.of("definitions");
private static final Path NAMED_DIR = DEFINITIONS_DIR.resolve("named");
private static final Path UNREFERENCED_DIR = DEFINITIONS_DIR.resolve("unreferenced");
private static final Path LATEST_DIR = Path.of("latest");

private final Path transportResourcesDir;
private final Path rootDir;
private final AtomicReference<Set<String>> mainResources = new AtomicReference<>(null);
private final AtomicReference<Set<String>> changedResources = new AtomicReference<>(null);

@Inject
public TransportVersionResourcesService(Parameters params) {
this.transportResourcesDir = params.getTransportResourcesDirectory().get().getAsFile().toPath();
this.rootDir = params.getRootDirectory().get().getAsFile().toPath();
}

/**
* Return the directory for this repository which contains transport version resources.
* This should be an input to any tasks reading resources from this service.
*/
Path getTransportResourcesDir() {
return transportResourcesDir;
}

/**
* Return the transport version definitions directory for this repository.
* This should be an input to any tasks that only read definitions from this service.
*/
Path getDefinitionsDir() {
return transportResourcesDir.resolve(DEFINITIONS_DIR);
}

// return the path, relative to the resources dir, of a named definition
private Path getNamedDefinitionRelativePath(String name) {
return NAMED_DIR.resolve(name + ".csv");
}

/** Return all named definitions, mapped by their name. */
Map<String, TransportVersionDefinition> getNamedDefinitions() throws IOException {
Map<String, TransportVersionDefinition> definitions = new HashMap<>();
// temporarily include unreferenced in named until validation understands the distinction
for (var dir : List.of(NAMED_DIR, UNREFERENCED_DIR)) {
Path path = transportResourcesDir.resolve(dir);
if (Files.isDirectory(path) == false) {
continue;
}
try (var definitionsStream = Files.list(path)) {
for (var definitionFile : definitionsStream.toList()) {
String contents = Files.readString(definitionFile, StandardCharsets.UTF_8).strip();
var definition = TransportVersionDefinition.fromString(definitionFile.getFileName().toString(), contents);
definitions.put(definition.name(), definition);
}
}
}
return definitions;
}

/** Test whether the given named definition exists */
TransportVersionDefinition getNamedDefinitionFromMain(String name) {
String resourcePath = getNamedDefinitionRelativePath(name).toString();
return getMainFile(resourcePath, TransportVersionDefinition::fromString);
}

/** Test whether the given named definition exists */
boolean namedDefinitionExists(String name) {
return Files.exists(transportResourcesDir.resolve(getNamedDefinitionRelativePath(name)));
}

/** Return the path within the repository of the given named definition */
Path getRepositoryPath(TransportVersionDefinition definition) {
return rootDir.relativize(transportResourcesDir.resolve(getNamedDefinitionRelativePath(definition.name())));
}

/** Read all latest files and return them mapped by their release branch */
Map<String, TransportVersionLatest> getLatestByReleaseBranch() throws IOException {
Map<String, TransportVersionLatest> latests = new HashMap<>();
try (var stream = Files.list(transportResourcesDir.resolve(LATEST_DIR))) {
for (var latestFile : stream.toList()) {
String contents = Files.readString(latestFile, StandardCharsets.UTF_8).strip();
var latest = TransportVersionLatest.fromString(latestFile.getFileName().toString(), contents);
latests.put(latest.name(), latest);
}
}
return latests;
}

/** Retrieve the latest transport version for the given release branch on main */
TransportVersionLatest getLatestFromMain(String releaseBranch) {
String resourcePath = getLatestRelativePath(releaseBranch).toString();
return getMainFile(resourcePath, TransportVersionLatest::fromString);
}

/** Return the path within the repository of the given latest */
Path getRepositoryPath(TransportVersionLatest latest) {
return rootDir.relativize(transportResourcesDir.resolve(getLatestRelativePath(latest.branch())));
}

private Path getLatestRelativePath(String releaseBranch) {
return LATEST_DIR.resolve(releaseBranch + ".csv");
}

// Return the transport version resources paths that exist in main
private Set<String> getMainResources() {
if (mainResources.get() == null) {
synchronized (mainResources) {
String output = gitCommand("ls-tree", "--name-only", "-r", "main", ".");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to use relative paths here, then we should explicitly set the working directory when calling exec. There's no real guarantee that this is the workspace directory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We set the working directory in gitCommand using -C


HashSet<String> resources = new HashSet<>();
Collections.addAll(resources, output.split(System.lineSeparator()));
mainResources.set(resources);
}
}
return mainResources.get();
}

// Return the transport version resources paths that have been changed relative to main
private Set<String> getChangedResources() {
if (changedResources.get() == null) {
synchronized (changedResources) {
String output = gitCommand("diff", "--name-only", "main", ".");

HashSet<String> resources = new HashSet<>();
Collections.addAll(resources, output.split(System.lineSeparator()));
changedResources.set(resources);
}
}
return changedResources.get();
}

// Read a transport version resource from the main branch, or return null if it doesn't exist on main
private <T> T getMainFile(String resourcePath, BiFunction<String, String, T> parser) {
if (getMainResources().contains(resourcePath) == false) {
return null;
}
String content = gitCommand("show", "main:./" + resourcePath).strip();
return parser.apply(resourcePath, content);
}

// run a git command, relative to the transport version resources directory
private String gitCommand(String... args) {
ByteArrayOutputStream stdout = new ByteArrayOutputStream();

List<String> command = new ArrayList<>();
Collections.addAll(command, "git", "-C", getTransportResourcesDir().toString());
Collections.addAll(command, args);

ExecResult result = getExecOperations().exec(spec -> {
spec.setCommandLine(command);
spec.setStandardOutput(stdout);
spec.setErrorOutput(stdout);
spec.setIgnoreExitValue(true);
});

if (result.getExitValue() != 0) {
throw new RuntimeException(
"git command failed with exit code "
+ result.getExitValue()
+ System.lineSeparator()
+ "command: "
+ String.join(" ", command)
+ System.lineSeparator()
+ "output:"
+ System.lineSeparator()
+ stdout.toString(StandardCharsets.UTF_8)
);
}

return stdout.toString(StandardCharsets.UTF_8);
}
}
Loading