Skip to content

Commit 8c70bc1

Browse files
authored
[Gradle] Some tweaks to transport related build logic (#133413) (#133694)
* [Gradle] Some tweaks to transport related build logic - We want to avoid project.allprojects - Implementing Verification task in the transport validation tasks - Allows better filtering for verification vs. other build failures. e.g. in Develocity Failures Overview - Use project.layout.settingsDirectory instead of project.rootProject.projectDir - Avoiding accessing other projects properties * Address some review feedback * Rework mapping project path list to dependencies * Some more review feedback * Minor tweak after review feedback
1 parent d74a55a commit 8c70bc1

7 files changed

+131
-27
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.gradle.internal;
11+
12+
import org.gradle.api.Project;
13+
import org.gradle.api.provider.Provider;
14+
import org.gradle.api.provider.ProviderFactory;
15+
import org.gradle.api.services.BuildService;
16+
import org.gradle.api.services.BuildServiceParameters;
17+
18+
import java.util.Collection;
19+
import java.util.HashMap;
20+
import java.util.Map;
21+
22+
import javax.inject.Inject;
23+
24+
public abstract class ProjectSubscribeBuildService implements BuildService<BuildServiceParameters.None> {
25+
26+
private final ProviderFactory providerFactory;
27+
28+
/**
29+
* The filling of this map depends on the order of #registerProjectForTopic being called.
30+
* This is usually done during configuration phase, but we do not enforce yet the time of this method call.
31+
* The values are LinkedHashSet to preserve the order of registration mostly to provide a predicatable order
32+
* when running consecutive builds.
33+
* */
34+
private final Map<String, Collection<String>> versionsByTopic = new HashMap<>();
35+
36+
@Inject
37+
public ProjectSubscribeBuildService(ProviderFactory providerFactory) {
38+
this.providerFactory = providerFactory;
39+
}
40+
41+
/**
42+
* Returning a provider so the evaluation of the map value is deferred to when the provider is queried.
43+
* */
44+
public Provider<Collection<String>> getProjectsByTopic(String topic) {
45+
return providerFactory.provider(() -> versionsByTopic.computeIfAbsent(topic, k -> new java.util.LinkedHashSet<>()));
46+
}
47+
48+
public void registerProjectForTopic(String topic, Project project) {
49+
versionsByTopic.computeIfAbsent(topic, k -> new java.util.LinkedHashSet<>()).add(project.getPath());
50+
}
51+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.gradle.internal;
11+
12+
import org.gradle.api.Plugin;
13+
import org.gradle.api.Project;
14+
import org.gradle.api.provider.Provider;
15+
16+
/**
17+
* This plugin registers a {@link ProjectSubscribeBuildService} to allow projects to
18+
* communicate with each other during the configuration phase.
19+
*
20+
* For example, a project can register itself as a publisher of a topic, and other
21+
* projects can resolve projects that have registered as publishers of that topic.
22+
*
23+
* The actual resolution of whatever data is usually done using dependency declarations.
24+
* Be aware the state of the list depends on the order of project configuration and
25+
* consuming on configuration phase before task graph calculation phase should be avoided.
26+
*
27+
* We want to avoid discouraged plugin api usage like project.allprojects or project.subprojects
28+
* in plugins to avoid unnecessary configuration of projects and not break project isolation and break
29+
* See https://docs.gradle.org/current/userguide/isolated_projects.html
30+
* */
31+
public class ProjectSubscribeServicePlugin implements Plugin<Project> {
32+
33+
private Provider<ProjectSubscribeBuildService> publishSubscribe;
34+
35+
@Override
36+
public void apply(Project project) {
37+
publishSubscribe = project.getGradle().getSharedServices().registerIfAbsent("publishSubscribe", ProjectSubscribeBuildService.class);
38+
}
39+
40+
public Provider<ProjectSubscribeBuildService> getService() {
41+
return publishSubscribe;
42+
}
43+
44+
}

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/GenerateTransportVersionManifestTask.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public Path getDefinitionsDirectory() {
4444

4545
@TaskAction
4646
public void generateTransportVersionManifest() throws IOException {
47-
4847
Path definitionsDir = getDefinitionsDirectory();
4948
Path manifestFile = getManifestFile().get().getAsFile().toPath();
5049
try (var writer = Files.newBufferedWriter(manifestFile)) {

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/TransportVersionReferencesPlugin.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,27 @@
99

1010
package org.elasticsearch.gradle.internal.transport;
1111

12+
import org.elasticsearch.gradle.internal.ProjectSubscribeServicePlugin;
1213
import org.elasticsearch.gradle.util.GradleUtils;
1314
import org.gradle.api.Plugin;
1415
import org.gradle.api.Project;
15-
import org.gradle.api.artifacts.Configuration;
1616
import org.gradle.api.tasks.SourceSet;
1717
import org.gradle.language.base.plugins.LifecycleBasePlugin;
1818

19+
import static org.elasticsearch.gradle.internal.transport.TransportVersionResourcesPlugin.TRANSPORT_REFERENCES_TOPIC;
20+
1921
public class TransportVersionReferencesPlugin implements Plugin<Project> {
2022

2123
@Override
2224
public void apply(Project project) {
2325
project.getPluginManager().apply(LifecycleBasePlugin.class);
2426

27+
project.getPlugins()
28+
.apply(ProjectSubscribeServicePlugin.class)
29+
.getService()
30+
.get()
31+
.registerProjectForTopic(TRANSPORT_REFERENCES_TOPIC, project);
32+
2533
var collectTask = project.getTasks()
2634
.register("collectTransportVersionReferences", CollectTransportVersionReferencesTask.class, t -> {
2735
t.setGroup("Transport Versions");
@@ -31,9 +39,7 @@ public void apply(Project project) {
3139
t.getOutputFile().set(project.getLayout().getBuildDirectory().file("transport-version/references.txt"));
3240
});
3341

34-
Configuration tvReferencesConfig = project.getConfigurations().create("transportVersionReferences", c -> {
35-
c.setCanBeConsumed(true);
36-
c.setCanBeResolved(false);
42+
var tvReferencesConfig = project.getConfigurations().consumable("transportVersionReferences", c -> {
3743
c.attributes(TransportVersionReference::addArtifactAttribute);
3844
});
3945
project.getArtifacts().add(tvReferencesConfig.getName(), collectTask);

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/TransportVersionResourcesPlugin.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99

1010
package org.elasticsearch.gradle.internal.transport;
1111

12+
import org.elasticsearch.gradle.internal.ProjectSubscribeServicePlugin;
1213
import org.gradle.api.Plugin;
1314
import org.gradle.api.Project;
14-
import org.gradle.api.artifacts.Configuration;
15-
import org.gradle.api.artifacts.dsl.DependencyHandler;
1615
import org.gradle.api.file.Directory;
1716
import org.gradle.api.plugins.JavaPlugin;
1817
import org.gradle.api.tasks.Copy;
@@ -22,32 +21,33 @@
2221

2322
public class TransportVersionResourcesPlugin implements Plugin<Project> {
2423

24+
public static final String TRANSPORT_REFERENCES_TOPIC = "transportReferences";
25+
2526
@Override
2627
public void apply(Project project) {
2728
project.getPluginManager().apply(LifecycleBasePlugin.class);
28-
29-
String resourceRoot = getResourceRoot(project);
29+
var psService = project.getPlugins().apply(ProjectSubscribeServicePlugin.class).getService();
30+
var resourceRoot = getResourceRoot(project);
3031

3132
project.getGradle()
3233
.getSharedServices()
3334
.registerIfAbsent("transportVersionResources", TransportVersionResourcesService.class, spec -> {
3435
Directory transportResources = project.getLayout().getProjectDirectory().dir("src/main/resources/" + resourceRoot);
3536
spec.getParameters().getTransportResourcesDirectory().set(transportResources);
36-
spec.getParameters().getRootDirectory().set(project.getRootProject().getRootDir());
37+
spec.getParameters().getRootDirectory().set(project.getLayout().getSettingsDirectory().getAsFile());
3738
});
3839

39-
DependencyHandler depsHandler = project.getDependencies();
40-
Configuration tvReferencesConfig = project.getConfigurations().create("globalTvReferences");
41-
tvReferencesConfig.setCanBeConsumed(false);
42-
tvReferencesConfig.setCanBeResolved(true);
43-
tvReferencesConfig.attributes(TransportVersionReference::addArtifactAttribute);
44-
45-
// iterate through all projects, and if the management plugin is applied, add that project back as a dep to check
46-
for (Project subProject : project.getRootProject().getSubprojects()) {
47-
subProject.getPlugins().withType(TransportVersionReferencesPlugin.class).configureEach(plugin -> {
48-
tvReferencesConfig.getDependencies().add(depsHandler.project(Map.of("path", subProject.getPath())));
49-
});
50-
}
40+
var depsHandler = project.getDependencies();
41+
var tvReferencesConfig = project.getConfigurations().create("globalTvReferences", c -> {
42+
c.setCanBeConsumed(false);
43+
c.setCanBeResolved(true);
44+
c.attributes(TransportVersionReference::addArtifactAttribute);
45+
c.getDependencies()
46+
.addAllLater(
47+
psService.flatMap(t -> t.getProjectsByTopic(TRANSPORT_REFERENCES_TOPIC))
48+
.map(projectPaths -> projectPaths.stream().map(path -> depsHandler.project(Map.of("path", path))).toList())
49+
);
50+
});
5151

5252
var validateTask = project.getTasks()
5353
.register("validateTransportVersionResources", ValidateTransportVersionResourcesTask.class, t -> {

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/ValidateTransportVersionReferencesTask.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.gradle.api.tasks.PathSensitive;
2121
import org.gradle.api.tasks.PathSensitivity;
2222
import org.gradle.api.tasks.TaskAction;
23+
import org.gradle.api.tasks.VerificationException;
24+
import org.gradle.api.tasks.VerificationTask;
2325

2426
import java.io.IOException;
2527
import java.nio.file.Path;
@@ -28,7 +30,7 @@
2830
* Validates that each transport version reference has a referable definition.
2931
*/
3032
@CacheableTask
31-
public abstract class ValidateTransportVersionReferencesTask extends DefaultTask {
33+
public abstract class ValidateTransportVersionReferencesTask extends DefaultTask implements VerificationTask {
3234

3335
@ServiceReference("transportVersionResources")
3436
abstract Property<TransportVersionResourcesService> getTransportResources();
@@ -51,7 +53,7 @@ public void validateTransportVersions() throws IOException {
5153

5254
for (var tvReference : TransportVersionReference.listFromFile(namesFile)) {
5355
if (resources.referableDefinitionExists(tvReference.name()) == false) {
54-
throw new RuntimeException(
56+
throw new VerificationException(
5557
"TransportVersion.fromName(\""
5658
+ tvReference.name()
5759
+ "\") was used at "

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/ValidateTransportVersionResourcesTask.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.gradle.api.tasks.PathSensitive;
2323
import org.gradle.api.tasks.PathSensitivity;
2424
import org.gradle.api.tasks.TaskAction;
25+
import org.gradle.api.tasks.VerificationException;
26+
import org.gradle.api.tasks.VerificationTask;
2527

2628
import java.io.IOException;
2729
import java.nio.file.Path;
@@ -38,7 +40,7 @@
3840
* Validates that each defined transport version constant is referenced by at least one project.
3941
*/
4042
@CacheableTask
41-
public abstract class ValidateTransportVersionResourcesTask extends DefaultTask {
43+
public abstract class ValidateTransportVersionResourcesTask extends DefaultTask implements VerificationTask {
4244

4345
@InputDirectory
4446
@Optional
@@ -255,11 +257,11 @@ private void validateBase(int base, List<IdAndDefinition> ids) {
255257

256258
private void throwDefinitionFailure(TransportVersionDefinition definition, String message) {
257259
Path relativePath = getResources().get().getReferableDefinitionRepositoryPath(definition);
258-
throw new IllegalStateException("Transport version definition file [" + relativePath + "] " + message);
260+
throw new VerificationException("Transport version definition file [" + relativePath + "] " + message);
259261
}
260262

261263
private void throwUpperBoundFailure(TransportVersionUpperBound upperBound, String message) {
262264
Path relativePath = getResources().get().getUpperBoundRepositoryPath(upperBound);
263-
throw new IllegalStateException("Transport version upper bound file [" + relativePath + "] " + message);
265+
throw new VerificationException("Transport version upper bound file [" + relativePath + "] " + message);
264266
}
265267
}

0 commit comments

Comments
 (0)