Skip to content

Commit 46e91f1

Browse files
committed
Fix dependency reporting
This has been broken since 9.0.3. likely due to some swallowed api change in Gradle. This fixes and adds test coverage to dependency reporting used in DRA artifacts building Fix interdependency to Licenses task
1 parent ebd868b commit 46e91f1

File tree

17 files changed

+129
-62
lines changed

17 files changed

+129
-62
lines changed

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
5353
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.""".stripIndent()
5454

5555
def setup() {
56-
configurationCacheCompatible = false
5756
buildFile << """
5857
plugins {
5958
id 'java'
@@ -167,6 +166,25 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
167166
result.task(":loggerUsageCheck").outcome == TaskOutcome.SKIPPED
168167
}
169168

169+
def "can generate dependency infos file"() {
170+
given:
171+
repository.generateJar("junit", "junit", "4.12", 'org.acme.JunitMock')
172+
repository.configureBuild(buildFile)
173+
file("licenses/junit-4.12.jar.sha1").text = "2973d150c0dc1fefe998f834810d68f278ea58ec"
174+
file("licenses/junit-LICENSE.txt").text = EXAMPLE_LICENSE
175+
file("licenses/junit-NOTICE.txt").text = "mock notice"
176+
buildFile << """
177+
dependencies {
178+
api "junit:junit:4.12"
179+
}
180+
"""
181+
when:
182+
def result = gradleRunner("dependenciesInfo").build()
183+
then:
184+
result.task(":dependenciesInfo").outcome == TaskOutcome.SUCCESS
185+
file("build/reports/dependencies/dependencies.csv").text == "junit:junit,4.12,https://repo1.maven.org/maven2/junit/junit/4.12,BSD-3-Clause,\n"
186+
}
187+
170188
def assertValidJar(File jar) {
171189
try (ZipFile zipFile = new ZipFile(jar)) {
172190
ZipEntry licenseEntry = zipFile.getEntry("META-INF/LICENSE.txt")
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.DefaultTask;
13+
import org.gradle.api.InvalidUserDataException;
14+
import org.gradle.api.provider.MapProperty;
15+
import org.gradle.api.tasks.Input;
16+
import org.gradle.api.tasks.Optional;
17+
18+
import java.util.Map;
19+
20+
public abstract class AbstractDependenciesTask extends DefaultTask {
21+
22+
@Input
23+
@Optional
24+
public abstract MapProperty<String, String> getMappings();
25+
26+
/**
27+
* Add a mapping from a regex pattern for the jar name, to a prefix to find
28+
* the LICENSE and NOTICE file for that jar.
29+
*/
30+
public void mapping(Map<String, String> props) {
31+
String from = props.get("from");
32+
if (from == null) {
33+
throw new InvalidUserDataException("Missing \"from\" setting for license name mapping");
34+
}
35+
String to = props.get("to");
36+
if (to == null) {
37+
throw new InvalidUserDataException("Missing \"to\" setting for license name mapping");
38+
}
39+
if (props.size() > 2) {
40+
throw new InvalidUserDataException("Unknown properties for mapping on dependencyLicenses: " + props.keySet());
41+
}
42+
getMappings().put(from, to);
43+
}
44+
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import org.gradle.api.attributes.Usage;
1818
import org.gradle.api.plugins.JavaPlugin;
1919

20+
import static org.elasticsearch.gradle.internal.util.DependenciesUtils.createNonTransitiveArtifactsView;
21+
2022
public class DependenciesInfoPlugin implements Plugin<Project> {
2123

2224
public static String USAGE_ATTRIBUTE = "DependenciesInfo";
@@ -25,16 +27,15 @@ public class DependenciesInfoPlugin implements Plugin<Project> {
2527
public void apply(final Project project) {
2628
project.getPlugins().apply(CompileOnlyResolvePlugin.class);
2729
var depsInfo = project.getTasks().register("dependenciesInfo", DependenciesInfoTask.class);
28-
2930
depsInfo.configure(t -> {
3031
var runtimeConfiguration = project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);
31-
t.getRuntimeArtifacts().set(project.getProviders().provider(() -> runtimeConfiguration.getIncoming().getArtifacts()));
32+
t.getRuntimeArtifacts()
33+
.set(project.getProviders().provider(() -> createNonTransitiveArtifactsView(runtimeConfiguration).getArtifacts()));
3234
t.getClasspath().from(runtimeConfiguration);
3335
var compileOnlyConfiguration = project.getConfigurations()
3436
.getByName(CompileOnlyResolvePlugin.RESOLVEABLE_COMPILE_ONLY_CONFIGURATION_NAME);
3537
t.getCompileOnlyArtifacts().set(project.getProviders().provider(() -> compileOnlyConfiguration.getIncoming().getArtifacts()));
3638
t.getClasspath().from(compileOnlyConfiguration);
37-
3839
});
3940
Configuration dependenciesInfoFilesConfiguration = project.getConfigurations().create("dependenciesInfoFiles");
4041
dependenciesInfoFilesConfiguration.setCanBeResolved(false);

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,23 @@
1717
import org.gradle.api.file.ConfigurableFileCollection;
1818
import org.gradle.api.file.DirectoryProperty;
1919
import org.gradle.api.file.ProjectLayout;
20-
import org.gradle.api.internal.ConventionTask;
2120
import org.gradle.api.model.ObjectFactory;
22-
import org.gradle.api.provider.MapProperty;
2321
import org.gradle.api.provider.Property;
2422
import org.gradle.api.provider.Provider;
2523
import org.gradle.api.provider.ProviderFactory;
24+
import org.gradle.api.tasks.CacheableTask;
25+
import org.gradle.api.tasks.Classpath;
2626
import org.gradle.api.tasks.Input;
2727
import org.gradle.api.tasks.InputDirectory;
2828
import org.gradle.api.tasks.InputFiles;
2929
import org.gradle.api.tasks.Internal;
3030
import org.gradle.api.tasks.Optional;
3131
import org.gradle.api.tasks.OutputFile;
32+
import org.gradle.api.tasks.PathSensitive;
33+
import org.gradle.api.tasks.PathSensitivity;
3234
import org.gradle.api.tasks.TaskAction;
35+
import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier;
36+
import org.gradle.model.Path;
3337

3438
import java.io.File;
3539
import java.io.IOException;
@@ -55,7 +59,8 @@
5559
* <li>license: <a href="https://spdx.org/licenses/">SPDX license</a> identifier, custom license or UNKNOWN.</li>
5660
* </ul>
5761
*/
58-
public abstract class DependenciesInfoTask extends ConventionTask {
62+
@CacheableTask
63+
public abstract class DependenciesInfoTask extends AbstractDependenciesTask {
5964

6065
@Inject
6166
public abstract ProviderFactory getProviderFactory();
@@ -86,16 +91,17 @@ public Provider<Set<ModuleComponentIdentifier>> getCompileOnlyModules() {
8691
* artifact transforms that might be applied and fail due to missing task dependency to jar
8792
* generating tasks.
8893
* */
89-
@InputFiles
94+
@Classpath
9095
abstract ConfigurableFileCollection getClasspath();
9196

9297
private Provider<Set<ModuleComponentIdentifier>> mapToModuleComponentIdentifiers(ArtifactCollection artifacts) {
9398
return getProviderFactory().provider(
9499
() -> artifacts.getArtifacts()
95100
.stream()
96101
.map(r -> r.getId())
97-
.filter(id -> id instanceof ModuleComponentIdentifier)
98-
.map(id -> (ModuleComponentIdentifier) id)
102+
.filter(mcaId -> mcaId instanceof ModuleComponentArtifactIdentifier)
103+
.map(mcaId -> (ModuleComponentArtifactIdentifier) mcaId)
104+
.map(it -> it.getComponentIdentifier())
99105
.collect(Collectors.toSet())
100106
);
101107
}
@@ -111,6 +117,7 @@ private Provider<Set<ModuleComponentIdentifier>> mapToModuleComponentIdentifiers
111117
* Directory to read license files
112118
*/
113119
@Optional
120+
@PathSensitive(PathSensitivity.RELATIVE)
114121
@InputDirectory
115122
public File getLicensesDir() {
116123
File asFile = licensesDir.get().getAsFile();
@@ -143,7 +150,6 @@ public DependenciesInfoTask(ProjectLayout projectLayout, ObjectFactory objectFac
143150

144151
@TaskAction
145152
public void generateDependenciesInfo() throws IOException {
146-
147153
final Set<String> compileOnlyIds = getCompileOnlyModules().map(
148154
set -> set.stream()
149155
.map(id -> id.getModuleIdentifier().getGroup() + ":" + id.getModuleIdentifier().getName() + ":" + id.getVersion())
@@ -166,18 +172,13 @@ public void generateDependenciesInfo() throws IOException {
166172
final String url = createURL(dep.getGroup(), moduleName, dep.getVersion());
167173
final String dependencyName = DependencyLicensesTask.getDependencyName(mappings, moduleName);
168174
getLogger().info("mapped dependency " + dep.getGroup() + ":" + moduleName + " to " + dependencyName + " for license info");
169-
170175
final String licenseType = getLicenseType(dep.getGroup(), dependencyName);
171176
output.append(dep.getGroup() + ":" + moduleName + "," + dep.getVersion() + "," + url + "," + licenseType + "\n");
172177
}
173178

174179
Files.writeString(outputFile.toPath(), output.toString(), StandardOpenOption.CREATE);
175180
}
176181

177-
@Input
178-
@Optional
179-
public abstract MapProperty<String, String> getMappings();
180-
181182
/**
182183
* Create an URL on <a href="https://repo1.maven.org/maven2/">Maven Central</a>
183184
* based on dependency coordinates.

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

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
*/
99
package org.elasticsearch.gradle.internal.precommit;
1010

11+
import org.elasticsearch.gradle.internal.AbstractDependenciesTask;
1112
import org.elasticsearch.gradle.internal.precommit.LicenseAnalyzer.LicenseInfo;
12-
import org.gradle.api.DefaultTask;
1313
import org.gradle.api.GradleException;
14-
import org.gradle.api.InvalidUserDataException;
1514
import org.gradle.api.artifacts.Configuration;
1615
import org.gradle.api.artifacts.component.ComponentIdentifier;
1716
import org.gradle.api.file.Directory;
@@ -39,7 +38,6 @@
3938
import java.util.Arrays;
4039
import java.util.HashMap;
4140
import java.util.HashSet;
42-
import java.util.LinkedHashMap;
4341
import java.util.LinkedHashSet;
4442
import java.util.List;
4543
import java.util.Map;
@@ -94,7 +92,7 @@
9492
* comply with the license terms.
9593
*/
9694
@CacheableTask
97-
public abstract class DependencyLicensesTask extends DefaultTask {
95+
public abstract class DependencyLicensesTask extends AbstractDependenciesTask {
9896

9997
private final Pattern regex = Pattern.compile("-v?\\d+.*");
10098

@@ -112,11 +110,6 @@ public abstract class DependencyLicensesTask extends DefaultTask {
112110
*/
113111
private final DirectoryProperty licensesDir;
114112

115-
/**
116-
* A map of patterns to prefix, used to find the LICENSE and NOTICE file.
117-
*/
118-
private Map<String, String> mappings = new LinkedHashMap<>();
119-
120113
/**
121114
* Names of dependencies whose shas should not exist.
122115
*/
@@ -128,24 +121,7 @@ public abstract class DependencyLicensesTask extends DefaultTask {
128121
private LinkedHashSet<String> ignoreFiles = new LinkedHashSet<>();
129122
private ProjectLayout projectLayout;
130123

131-
/**
132-
* Add a mapping from a regex pattern for the jar name, to a prefix to find
133-
* the LICENSE and NOTICE file for that jar.
134-
*/
135-
public void mapping(Map<String, String> props) {
136-
String from = props.get("from");
137-
if (from == null) {
138-
throw new InvalidUserDataException("Missing \"from\" setting for license name mapping");
139-
}
140-
String to = props.get("to");
141-
if (to == null) {
142-
throw new InvalidUserDataException("Missing \"to\" setting for license name mapping");
143-
}
144-
if (props.size() > 2) {
145-
throw new InvalidUserDataException("Unknown properties for mapping on dependencyLicenses: " + props.keySet());
146-
}
147-
mappings.put(from, to);
148-
}
124+
149125

150126
@Inject
151127
public DependencyLicensesTask(ObjectFactory objects, ProjectLayout projectLayout) {
@@ -267,7 +243,7 @@ private void checkDependencies(Map<String, Boolean> licenses, Map<String, Boolea
267243
for (File dependency : dependencies) {
268244
String jarName = dependency.getName();
269245
String depName = regex.matcher(jarName).replaceFirst("");
270-
String dependencyName = getDependencyName(mappings, depName);
246+
String dependencyName = getDependencyName(getMappings().get(), depName);
271247
logger.info("mapped dependency name {} to {} for license/notice check", depName, dependencyName);
272248
checkFile(dependencyName, jarName, licenses, "LICENSE");
273249
checkFile(dependencyName, jarName, notices, "NOTICE");
@@ -321,11 +297,6 @@ public LinkedHashSet<String> getIgnoreFiles() {
321297
return new LinkedHashSet<>(ignoreFiles);
322298
}
323299

324-
@Input
325-
public LinkedHashMap<String, String> getMappings() {
326-
return new LinkedHashMap<>(mappings);
327-
}
328-
329300
/**
330301
* Convencience method for configuring dependencies to be checked and ignoring transitive dependencies for now.
331302
* */

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin;
1313

14+
import org.gradle.api.artifacts.ArtifactView;
1415
import org.gradle.api.artifacts.Configuration;
1516
import org.gradle.api.artifacts.ResolvableDependencies;
1617
import org.gradle.api.artifacts.component.ComponentIdentifier;
@@ -31,6 +32,14 @@ public static FileCollection createFileCollectionFromNonTransitiveArtifactsView(
3132
Configuration configuration,
3233
Spec<ComponentIdentifier> componentFilter
3334
) {
35+
return createNonTransitiveArtifactsView(configuration, componentFilter).getFiles();
36+
}
37+
38+
public static ArtifactView createNonTransitiveArtifactsView(Configuration configuration) {
39+
return createNonTransitiveArtifactsView(configuration, identifier -> true);
40+
}
41+
42+
public static ArtifactView createNonTransitiveArtifactsView(Configuration configuration, Spec<ComponentIdentifier> componentFilter) {
3443
ResolvableDependencies incoming = configuration.getIncoming();
3544
return incoming.artifactView(viewConfiguration -> {
3645
Provider<Set<ComponentIdentifier>> firstLevelDependencyComponents = incoming.getResolutionResult()
@@ -47,7 +56,7 @@ public static FileCollection createFileCollectionFromNonTransitiveArtifactsView(
4756
viewConfiguration.componentFilter(
4857
new AndSpec<>(identifier -> firstLevelDependencyComponents.get().contains(identifier), componentFilter)
4958
);
50-
}).getFiles();
59+
});
5160
}
5261

5362
/**

client/sniffer/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* under the License.
1818
*/
1919
import org.elasticsearch.gradle.internal.conventions.precommit.LicenseHeadersTask
20+
import org.elasticsearch.gradle.internal.AbstractDependenciesTask
2021

2122
apply plugin: 'elasticsearch.build'
2223
apply plugin: 'elasticsearch.publish'
@@ -67,7 +68,7 @@ tasks.named('forbiddenApisTest').configure {
6768
replaceSignatureFiles 'jdk-signatures'
6869
}
6970

70-
tasks.named("dependencyLicenses").configure {
71+
tasks.withType(AbstractDependenciesTask).configureEach {
7172
mapping from: /http.*/, to: 'httpclient'
7273
mapping from: /commons-.*/, to: 'commons'
7374
}

distribution/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ tasks.register("generateDependenciesReport", ConcatFilesTask) {
8383
'https://oss-dependencies.elastic.co/red-hat-universal-base-image-minimal/9/ubi-minimal-9-source.tar.gz'
8484
]
8585
additionalLines << rhelUbiFields.join(',')
86+
doLast {
87+
if(target.text.readLines().size() < 100) {
88+
throw new GradleException("Suspiciously low number of dependencies. Double check.")
89+
}
90+
}
8691
}
8792

8893
/*****************************************************************************

modules/ingest-geoip/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import org.elasticsearch.gradle.OS
11+
import org.elasticsearch.gradle.internal.AbstractDependenciesTask
1112

1213
apply plugin: 'elasticsearch.internal-yaml-rest-test'
1314
apply plugin: 'elasticsearch.yaml-rest-compat-test'
@@ -81,10 +82,13 @@ tasks.named("forbiddenPatterns").configure {
8182
exclude '**/*.mmdb'
8283
}
8384

84-
tasks.named("dependencyLicenses").configure {
85+
tasks.withType(AbstractDependenciesTask).configureEach {
8586
mapping from: /geoip.*/, to: 'maxmind-geolite2-eula'
8687
mapping from: /maxmind-db.*/, to: 'maxmind-db-reader'
8788
mapping from: /jackson.*/, to: 'jackson'
89+
}
90+
91+
tasks.named("dependencyLicenses").configure {
8892
ignoreFile 'elastic-geoip-database-service-agreement-LICENSE.txt'
8993
}
9094

modules/repository-s3/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
import org.apache.tools.ant.filters.ReplaceTokens
1010
import org.elasticsearch.gradle.internal.test.InternalClusterTestPlugin
11+
import org.elasticsearch.gradle.internal.AbstractDependenciesTask
1112

1213
apply plugin: 'elasticsearch.internal-yaml-rest-test'
1314
apply plugin: 'elasticsearch.internal-cluster-test'
@@ -89,7 +90,7 @@ restResources {
8990
}
9091
}
9192

92-
tasks.named("dependencyLicenses").configure {
93+
tasks.withType(AbstractDependenciesTask).configureEach {
9394
mapping from: 'annotations', to: 'aws-sdk-2'
9495
mapping from: 'apache-client', to: 'aws-sdk-2'
9596
mapping from: 'arns', to: 'aws-sdk-2'

0 commit comments

Comments
 (0)