Skip to content

Commit a6efcdf

Browse files
authored
Merge branch '8.18' into backport/8.18/pr-134597
2 parents 47e65ac + 7338354 commit a6efcdf

File tree

30 files changed

+1046
-147
lines changed

30 files changed

+1046
-147
lines changed

.buildkite/pipelines/periodic-java-ea.template.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
env:
2-
JAVA_EA_VERSION: "${JAVA_EA_VERSION:-25-pre}"
2+
JAVA_EA_VERSION: "${JAVA_EA_VERSION:-26-pre}"
33

44
steps:
55
- group: bwc

.buildkite/pipelines/periodic-java-ea.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is auto-generated. See .buildkite/pipelines/periodic-java-ea.template.yml
22
env:
3-
JAVA_EA_VERSION: "${JAVA_EA_VERSION:-25-pre}"
3+
JAVA_EA_VERSION: "${JAVA_EA_VERSION:-26-pre}"
44

55
steps:
66
- group: bwc

BUILDING.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,70 @@ will have the `origin` attribute been set to `Generated by Gradle`.
9797
> If you want to add a level of verification you can manually confirm the checksum (e.g. by looking it up on the website of the library)
9898
> Please replace the content of the `origin` attribute by `official site` in that case.
9999
100+
##### Handling transitive dependencies
101+
102+
Dependency management is a critical aspect of maintaining a secure and reliable build system, requiring explicit control over what we rely on. The Elasticsearch build mainly uses component metadata rules declared in the `ComponentMetadataRulesPlugin`
103+
plugin to manage transitive dependencies and avoid version conflicts.
104+
This approach ensures we have explicit control over all dependencies used in the build.
105+
106+
###### General Guidelines
107+
108+
1. **Avoid unused transitive dependencies** - Dependencies that are not actually used by our code should be excluded to reduce the attack surface and avoid potential conflicts.
109+
110+
2. **Prefer versions declared in `build-tools-internal/version.properties`** - All dependency versions should be centrally managed in this file to ensure consistency across the entire build.
111+
112+
3. **Libraries required to compile our code should be direct dependencies** - If we directly use a library in our source code, it should be declared as a direct dependency rather than relying on it being transitively available.
113+
114+
###### Component Metadata Rules
115+
116+
We use two main types of component metadata rules at this point to manage transitive dependencies:
117+
118+
- **`ExcludeAllTransitivesRule`** - Excludes all transitive dependencies for libraries where we want complete control over dependencies or the transitive dependencies are unused.
119+
120+
- **`ExcludeOtherGroupsTransitiveRule`** - Excludes transitive dependencies that don't belong to the same group as the direct dependency, while keeping same-group dependencies.
121+
-
122+
- **`ExcludeByGroup`** - Excludes transitive dependencies that match a specific groupId while keeping all other transitive dependencies with different groupIds.
123+
124+
Examples from the `ComponentMetadataRulesPlugin`:
125+
126+
```gradle
127+
// Exclude all transitives - used when transitive deps are unused or problematic
128+
components.withModule("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor", ExcludeAllTransitivesRule.class);
129+
130+
// Exclude other groups - used when we want same-group deps but not external ones
131+
components.withModule("com.azure:azure-core", ExcludeOtherGroupsTransitiveRule.class);
132+
133+
// Exclude only specific groups - used when we want exclude specific group of transitive deps.
134+
components.withModule("org.apache.logging.log4j:log4j-api", ExcludeByGroup.class, rule -> {
135+
rule.params(List.of("biz.aQute.bnd", "org.osgi"));
136+
});
137+
```
138+
139+
###### Common Scenarios
140+
141+
**Version Conflicts**: When a transitive dependency brings in a different version than what we use:
142+
```gradle
143+
// brings in jackson-databind and jackson-annotations not used
144+
components.withModule("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor", ExcludeAllTransitivesRule.class);
145+
```
146+
147+
**Unused Dependencies**: When transitive dependencies are not actually used:
148+
```gradle
149+
// brings in azure-core-http-netty. not used
150+
components.withModule("com.azure:azure-core-http-netty", ExcludeAllTransitivesRule.class);
151+
```
152+
153+
**Mismatching Version Dependencies**: When other versions are required:
154+
```gradle
155+
// brings in org.slf4j:slf4j-api:1.7.25. We use 2.0.6
156+
components.withModule("org.apache.directory.api:api-asn1-ber", ExcludeOtherGroupsTransitiveRule.class);
157+
```
158+
159+
When adding or updating dependencies, ensure that any required transitive dependencies are either:
160+
1. Already available as direct dependencies with compatible versions
161+
2. Added as direct dependencies if they're actually used by our code
162+
3. Properly excluded if they're not needed
163+
100164
#### Custom plugin and task implementations
101165

102166
Build logic that is used across multiple subprojects should be considered to be moved into a Gradle plugin with according Gradle task implementation.

build-conventions/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ repositories {
7272
}
7373

7474
dependencies {
75+
constraints {
76+
api("org.slf4j:slf4j-api:2.0.6")
77+
}
7578
api buildLibs.maven.model
7679
api buildLibs.shadow.plugin
7780
api buildLibs.apache.rat

build-tools-internal/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ gradlePlugin {
4040
id = 'elasticsearch.build-complete'
4141
implementationClass = 'org.elasticsearch.gradle.internal.ElasticsearchBuildCompletePlugin'
4242
}
43+
componentMetadataRules {
44+
id = 'elasticsearch.component-metadata-rules'
45+
implementationClass = 'org.elasticsearch.gradle.internal.dependencies.rules.ComponentMetadataRulesPlugin'
46+
}
4347
distro {
4448
id = 'elasticsearch.distro'
4549
implementationClass = 'org.elasticsearch.gradle.internal.distribution.ElasticsearchDistributionPlugin'
@@ -281,6 +285,9 @@ dependencies {
281285
testImplementation buildLibs.asm
282286
integTestImplementation buildLibs.asm
283287
api(buildLibs.snakeyaml)
288+
api("org.slf4j:slf4j-api:2.0.6") {
289+
because("Align with what we use in production")
290+
}
284291
}
285292
// Forcefully downgrade the jackson platform as used in production
286293
api enforcedPlatform(buildLibs.jackson.platform)

build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/transport/AbstractTransportVersionFuncTest.groovy

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ class AbstractTransportVersionFuncTest extends AbstractGradleFuncTest {
152152
"""
153153

154154
setupLocalGitRepo()
155-
execute("git checkout -b main")
155+
String currentBranch = execute("git branch --show-current")
156+
if (currentBranch.strip().equals("main") == false) {
157+
// make sure a main branch exists, some CI doesn't have main set as the default branch
158+
execute("git checkout -b main")
159+
}
156160
execute("git checkout -b test")
157161
}
158162

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

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,14 @@
1616
import org.elasticsearch.gradle.internal.test.MutedTestPlugin;
1717
import org.elasticsearch.gradle.internal.test.TestUtil;
1818
import org.elasticsearch.gradle.test.SystemPropertyCommandLineArgumentProvider;
19-
import org.elasticsearch.gradle.util.GradleUtils;
2019
import org.gradle.api.JavaVersion;
2120
import org.gradle.api.Plugin;
2221
import org.gradle.api.Project;
2322
import org.gradle.api.artifacts.Configuration;
24-
import org.gradle.api.artifacts.ResolutionStrategy;
2523
import org.gradle.api.file.FileCollection;
2624
import org.gradle.api.plugins.JavaBasePlugin;
2725
import org.gradle.api.plugins.JavaPluginExtension;
2826
import org.gradle.api.provider.Provider;
29-
import org.gradle.api.tasks.SourceSet;
30-
import org.gradle.api.tasks.SourceSetContainer;
3127
import org.gradle.api.tasks.compile.AbstractCompile;
3228
import org.gradle.api.tasks.compile.CompileOptions;
3329
import org.gradle.api.tasks.compile.GroovyCompile;
@@ -67,8 +63,6 @@ public void apply(Project project) {
6763
project.getPluginManager().apply(ElasticsearchTestBasePlugin.class);
6864
project.getPluginManager().apply(PrecommitTaskPlugin.class);
6965
project.getPluginManager().apply(MutedTestPlugin.class);
70-
71-
configureConfigurations(project);
7266
configureCompile(project);
7367
configureInputNormalization(project);
7468
configureNativeLibraryPath(project);
@@ -77,54 +71,6 @@ public void apply(Project project) {
7771
project.getExtensions().getExtraProperties().set("versions", VersionProperties.getVersions());
7872
}
7973

80-
/**
81-
* Makes dependencies non-transitive.
82-
* <p>
83-
* Gradle allows setting all dependencies as non-transitive very easily.
84-
* Sadly this mechanism does not translate into maven pom generation. In order
85-
* to effectively make the pom act as if it has no transitive dependencies,
86-
* we must exclude each transitive dependency of each direct dependency.
87-
* <p>
88-
* Determining the transitive deps of a dependency which has been resolved as
89-
* non-transitive is difficult because the process of resolving removes the
90-
* transitive deps. To sidestep this issue, we create a configuration per
91-
* direct dependency version. This specially named and unique configuration
92-
* will contain all of the transitive dependencies of this particular
93-
* dependency. We can then use this configuration during pom generation
94-
* to iterate the transitive dependencies and add excludes.
95-
*/
96-
public static void configureConfigurations(Project project) {
97-
// we are not shipping these jars, we act like dumb consumers of these things
98-
if (project.getPath().startsWith(":test:fixtures") || project.getPath().equals(":build-tools")) {
99-
return;
100-
}
101-
// fail on any conflicting dependency versions
102-
project.getConfigurations().all(configuration -> {
103-
if (configuration.getName().endsWith("Fixture")) {
104-
// just a self contained test-fixture configuration, likely transitive and hellacious
105-
return;
106-
}
107-
configuration.resolutionStrategy(ResolutionStrategy::failOnVersionConflict);
108-
});
109-
110-
// disable transitive dependency management
111-
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
112-
sourceSets.all(sourceSet -> disableTransitiveDependenciesForSourceSet(project, sourceSet));
113-
}
114-
115-
private static void disableTransitiveDependenciesForSourceSet(Project project, SourceSet sourceSet) {
116-
List<String> sourceSetConfigurationNames = List.of(
117-
sourceSet.getApiConfigurationName(),
118-
sourceSet.getImplementationConfigurationName(),
119-
sourceSet.getCompileOnlyConfigurationName(),
120-
sourceSet.getRuntimeOnlyConfigurationName()
121-
);
122-
123-
project.getConfigurations()
124-
.matching(c -> sourceSetConfigurationNames.contains(c.getName()))
125-
.configureEach(GradleUtils::disableTransitiveDependencies);
126-
}
127-
12874
/**
12975
* Adds compiler settings to the project
13076
*/

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.gradle.api.artifacts.result.ResolvedComponentResult;
2222
import org.gradle.api.artifacts.result.ResolvedDependencyResult;
2323
import org.gradle.api.attributes.LibraryElements;
24+
import org.gradle.api.attributes.Usage;
2425
import org.gradle.api.file.FileCollection;
2526
import org.gradle.api.logging.Logger;
2627
import org.gradle.api.plugins.JavaPlugin;
@@ -75,12 +76,13 @@ void configureCompileModulePath(Project project) {
7576
it.extendsFrom(compileClasspath);
7677
it.setCanBeResolved(true);
7778
it.setCanBeConsumed(false); // we don't want this configuration used by dependent projects
78-
it.attributes(
79-
attrs -> attrs.attribute(
79+
it.attributes(attrs -> {
80+
attrs.attribute(
8081
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
8182
project.getObjects().named(LibraryElements.class, LibraryElements.CLASSES)
82-
)
83-
);
83+
);
84+
attrs.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_API));
85+
});
8486
}).getIncoming().artifactView(it -> {
8587
it.componentFilter(cf -> {
8688
var visited = new HashSet<ComponentIdentifier>();

0 commit comments

Comments
 (0)