Skip to content

Commit 676f70b

Browse files
Allow Gradle verification of Test Optimization dependencies (#12077)
feat: allow skipping dependency verification disabling for test opt fix: limit warning to once per project build Co-authored-by: daniel.mohedano <daniel.mohedano@datadoghq.com>
1 parent 97bb5fc commit 676f70b

11 files changed

Lines changed: 185 additions & 30 deletions

File tree

dd-java-agent/instrumentation/gradle/gradle-3.0/src/main/groovy/datadog/trace/instrumentation/gradle/legacy/GradleProjectConfigurator.groovy

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class GradleProjectConfigurator {
4343
public static final GradleProjectConfigurator INSTANCE = new GradleProjectConfigurator()
4444

4545
private static final String JACOCO_PLUGIN_ID = 'jacoco'
46+
private static final String JACOCO_AGENT_CONFIGURATION_NAME = 'jacocoAgent'
47+
private static final String JACOCO_ANT_CONFIGURATION_NAME = 'jacocoAnt'
48+
private static final String DEPENDENCY_VERIFICATION_WARNING_EMITTED =
49+
'datadog.civisibility.dependency-verification-warning-emitted'
4650

4751
void configureTracer(Task task, Map<String, String> propagatedSystemProperties) {
4852
def config = Config.get()
@@ -130,15 +134,8 @@ class GradleProjectConfigurator {
130134
def ddJavacPlugin = project.configurations.detachedConfiguration(project.dependencies.create("com.datadoghq:dd-javac-plugin:$compilerPluginVersion"))
131135
def ddJavacPluginClient = project.configurations.detachedConfiguration(project.dependencies.create("com.datadoghq:dd-javac-plugin-client:$compilerPluginVersion"))
132136

133-
// if instrumented project does dependency verification,
134-
// we need to exclude the two detached configurations that we're adding
135-
// as corresponding entries are not in the project's verification-metadata.xml
136-
if (ddJavacPlugin.resolutionStrategy.respondsTo("disableDependencyVerification")) {
137-
ddJavacPlugin.resolutionStrategy.disableDependencyVerification()
138-
}
139-
if (ddJavacPluginClient.resolutionStrategy.respondsTo("disableDependencyVerification")) {
140-
ddJavacPluginClient.resolutionStrategy.disableDependencyVerification()
141-
}
137+
disableDependencyVerificationIfConfigured(project, ddJavacPlugin)
138+
disableDependencyVerificationIfConfigured(project, ddJavacPluginClient)
142139

143140
task.classpath = (task.classpath ?: project.files([])) + ddJavacPluginClient.asFileTree
144141

@@ -199,14 +196,11 @@ class GradleProjectConfigurator {
199196
project.apply("plugin": JACOCO_PLUGIN_ID)
200197
project.jacoco.toolVersion = config.ciVisibilityJacocoPluginVersion
201198

202-
// if instrumented project does dependency verification,
203-
// we need to exclude configurations added by Jacoco
204-
// as corresponding entries are not in the project's verification-metadata.xml
205-
def jacocoConfigurations = project.configurations.findAll { it.name.startsWith("jacoco") }
199+
def jacocoConfigurations = project.configurations.findAll {
200+
it.name == JACOCO_AGENT_CONFIGURATION_NAME || it.name == JACOCO_ANT_CONFIGURATION_NAME
201+
}
206202
for (def jacocoConfiguration : jacocoConfigurations) {
207-
if (jacocoConfiguration.resolutionStrategy.respondsTo("disableDependencyVerification")) {
208-
jacocoConfiguration.resolutionStrategy.disableDependencyVerification()
209-
}
203+
disableDependencyVerificationIfConfigured(project, jacocoConfiguration)
210204
}
211205

212206
def coverageIncludedPackages = sessionSettings.getCoverageIncludedPackages()
@@ -227,6 +221,28 @@ class GradleProjectConfigurator {
227221
}
228222
}
229223

224+
private static void disableDependencyVerificationIfConfigured(Project project, def configuration) {
225+
if (Config.get().ciVisibilityGradleDependencyVerificationEnabled
226+
|| !configuration.resolutionStrategy.respondsTo("disableDependencyVerification")) {
227+
return
228+
}
229+
230+
if (project.rootProject.file('gradle/verification-metadata.xml').isFile()) {
231+
def extraProperties = project.rootProject.extensions.extraProperties
232+
if (!extraProperties.has(DEPENDENCY_VERIFICATION_WARNING_EMITTED)) {
233+
extraProperties.set(DEPENDENCY_VERIFICATION_WARNING_EMITTED, true)
234+
project.logger.warn(
235+
"Datadog Test Optimization disabled Gradle dependency verification for dependencies "
236+
+ "injected into this build. To keep verification enabled, set "
237+
+ "DD_CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED=true and add "
238+
+ "the Datadog compiler plugin and injected JaCoCo dependencies to "
239+
+ "gradle/verification-metadata.xml. If the metadata is not updated, Gradle will "
240+
+ "fail the build while resolving these dependencies.")
241+
}
242+
}
243+
configuration.resolutionStrategy.disableDependencyVerification()
244+
}
245+
230246
private static void forEveryTestTask(Project project, Closure closure) {
231247
def c = { task ->
232248
if (GradleUtils.isTestTask(task)) {

dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityPlugin.java

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package datadog.trace.instrumentation.gradle;
22

3+
import datadog.trace.api.Config;
34
import datadog.trace.api.civisibility.domain.BuildModuleLayout;
45
import java.io.File;
56
import java.nio.file.Files;
@@ -30,6 +31,10 @@ public abstract class CiVisibilityPlugin implements Plugin<Project> {
3031

3132
private static final String PLUGIN_EXTENSION_NAME = "dd-ci-visibility";
3233
private static final String JACOCO_PLUGIN_ID = "jacoco";
34+
private static final String JACOCO_AGENT_CONFIGURATION_NAME = "jacocoAgent";
35+
private static final String JACOCO_ANT_CONFIGURATION_NAME = "jacocoAnt";
36+
private static final String DEPENDENCY_VERIFICATION_WARNING_EMITTED =
37+
"datadog.civisibility.dependency-verification-warning-emitted";
3338

3439
private Project project;
3540

@@ -105,14 +110,44 @@ public void addCompilerPluginConfigurations(CiVisibilityPluginExtension extensio
105110
"com.datadoghq:dd-javac-plugin-client:%s",
106111
extension.getCompilerPluginVersion())));
107112

108-
// if instrumented project does dependency verification,
109-
// we need to exclude the detached configurations that we're adding
110-
// as corresponding entries are not in the project's verification-metadata.xml
111-
configuration.getResolutionStrategy().disableDependencyVerification();
113+
disableDependencyVerificationIfConfigured(configuration);
112114

113115
extension.setCompilerPluginClasspath(configuration);
114116
}
115117

118+
private void disableDependencyVerificationIfConfigured(Configuration configuration) {
119+
if (Config.get().isCiVisibilityGradleDependencyVerificationEnabled()) {
120+
return;
121+
}
122+
123+
if (Files.isRegularFile(
124+
project
125+
.getRootProject()
126+
.getProjectDir()
127+
.toPath()
128+
.resolve("gradle/verification-metadata.xml"))) {
129+
if (!project
130+
.getRootProject()
131+
.getExtensions()
132+
.getExtraProperties()
133+
.has(DEPENDENCY_VERIFICATION_WARNING_EMITTED)) {
134+
project
135+
.getRootProject()
136+
.getExtensions()
137+
.getExtraProperties()
138+
.set(DEPENDENCY_VERIFICATION_WARNING_EMITTED, true);
139+
LOGGER.warn(
140+
"Datadog Test Optimization disabled Gradle dependency verification for dependencies "
141+
+ "injected into this build. To keep verification enabled, set "
142+
+ "DD_CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED=true and add "
143+
+ "the Datadog compiler plugin and injected JaCoCo dependencies to "
144+
+ "gradle/verification-metadata.xml. If the metadata is not updated, Gradle will "
145+
+ "fail the build while resolving these dependencies.");
146+
}
147+
}
148+
configuration.getResolutionStrategy().disableDependencyVerification();
149+
}
150+
116151
private void addModuleName(CiVisibilityPluginExtension extension) {
117152
extension.setModuleName(getModuleName());
118153
}
@@ -156,13 +191,13 @@ private void applyJacocoPlugin(CiVisibilityPluginExtension extension) {
156191

157192
List<Configuration> jacocoConfigurations =
158193
project.getConfigurations().stream()
159-
.filter(c -> c.getName().startsWith("jacoco"))
194+
.filter(
195+
c ->
196+
JACOCO_AGENT_CONFIGURATION_NAME.equals(c.getName())
197+
|| JACOCO_ANT_CONFIGURATION_NAME.equals(c.getName()))
160198
.collect(Collectors.toList());
161199
for (Configuration jacocoConfiguration : jacocoConfigurations) {
162-
// if instrumented project does dependency verification,
163-
// we need to exclude configurations added by Jacoco
164-
// as corresponding entries are not in the project's verification-metadata.xml
165-
jacocoConfiguration.getResolutionStrategy().disableDependencyVerification();
200+
disableDependencyVerificationIfConfigured(jacocoConfiguration);
166201
}
167202
}
168203

dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package datadog.smoketest;
22

3+
import static org.junit.jupiter.api.Assertions.assertEquals;
34
import static org.junit.jupiter.api.Assertions.assertFalse;
45
import static org.junit.jupiter.api.Assertions.assertNotNull;
56
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -161,6 +162,45 @@ void testRobolectric(String gradleVersion, String projectName, int expectedTrace
161162
mockBackend.waitForCoverages(0));
162163
}
163164

165+
@TableTest({
166+
"scenario | gradleVersion | verificationEnabled",
167+
"legacy-default | 7.6.4 | false ",
168+
"legacy-enabled | 7.6.4 | true ",
169+
"modern-default | 8.3 | false ",
170+
"modern-enabled | 8.3 | true "
171+
})
172+
@ParameterizedTest
173+
void testInjectedDependencyVerification(String gradleVersion, boolean verificationEnabled)
174+
throws IOException {
175+
givenGradleVersionIsCompatibleWithCurrentJvm(gradleVersion);
176+
givenGradleVersionIsSupportedByCurrentGradleTestKit(gradleVersion);
177+
givenGradleProjectFiles("test-gradle-dependency-verification");
178+
179+
Map<String, String> additionalArgs = new HashMap<>();
180+
if (verificationEnabled) {
181+
additionalArgs.put(
182+
CiVisibilityConfig.CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED, "true");
183+
}
184+
givenGradleProjectProperties(additionalArgs);
185+
ensureDependenciesDownloaded(gradleVersion);
186+
187+
BuildResult buildResult =
188+
runGradle(
189+
gradleVersion, Arrays.asList("compileJava", "--stacktrace"), !verificationEnabled);
190+
191+
if (verificationEnabled) {
192+
assertTrue(buildResult.getOutput().contains("Dependency verification failed"));
193+
} else {
194+
assertBuildSuccessful(buildResult);
195+
String warning =
196+
"Datadog Test Optimization disabled Gradle dependency verification for dependencies "
197+
+ "injected into this build.";
198+
int firstWarning = buildResult.getOutput().indexOf(warning);
199+
assertTrue(firstWarning >= 0);
200+
assertEquals(firstWarning, buildResult.getOutput().lastIndexOf(warning));
201+
}
202+
}
203+
164204
// TODO: add back LATEST_GRADLE_VERSION after fixing ordering on Gradle 9.3.0
165205
@TableTest({
166206
"scenario | gradleVersion | projectName | flakyTests | expectedOrder | eventsNumber",
@@ -280,14 +320,19 @@ private void runGradleTest(
280320
}
281321

282322
private void givenGradleProjectProperties() throws IOException {
323+
givenGradleProjectProperties(Collections.emptyMap());
324+
}
325+
326+
private void givenGradleProjectProperties(Map<String, String> additionalArgs) throws IOException {
283327
assertTrue(new java.io.File(AGENT_JAR).isFile());
284328

285329
Path ddApiKeyPath = testKitFolder.resolve(".dd.api.key");
286330
Files.write(ddApiKeyPath, "dummy".getBytes());
287331

288-
Map<String, String> additionalArgs = new HashMap<>();
289-
additionalArgs.put(GeneralConfig.API_KEY_FILE, ddApiKeyPath.toAbsolutePath().toString());
290-
additionalArgs.put(
332+
Map<String, String> effectiveAdditionalArgs = new HashMap<>(additionalArgs);
333+
effectiveAdditionalArgs.put(
334+
GeneralConfig.API_KEY_FILE, ddApiKeyPath.toAbsolutePath().toString());
335+
effectiveAdditionalArgs.put(
291336
CiVisibilityConfig.CIVISIBILITY_JACOCO_PLUGIN_VERSION, JACOCO_PLUGIN_VERSION);
292337
/*
293338
* Some of the smoke tests (in particular the one with the Gradle plugin), are using Gradle Test Kit for their tests.
@@ -298,9 +343,9 @@ private void givenGradleProjectProperties() throws IOException {
298343
* This causes the tests to fail because the number of reported traces is different.
299344
* To avoid this discrepancy between local and CI runs, we disable tracing instrumentations.
300345
*/
301-
additionalArgs.put(TraceInstrumentationConfig.TRACE_ENABLED, "false");
346+
effectiveAdditionalArgs.put(TraceInstrumentationConfig.TRACE_ENABLED, "false");
302347
List<String> arguments =
303-
buildJvmArguments(mockBackend.getIntakeUrl(), TEST_SERVICE_NAME, additionalArgs);
348+
buildJvmArguments(mockBackend.getIntakeUrl(), TEST_SERVICE_NAME, effectiveAdditionalArgs);
304349

305350
String gradleProperties = "org.gradle.jvmargs=" + String.join(" ", arguments);
306351
// Write to projectFolder (per-test) instead of testKitFolder (shared), so each
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apply plugin: 'java'
2+
3+
repositories {
4+
mavenLocal()
5+
6+
def proxyUrl = System.getenv("MAVEN_REPOSITORY_PROXY")
7+
if (proxyUrl) {
8+
println "Using proxy repository: $proxyUrl"
9+
maven {
10+
url = proxyUrl
11+
allowInsecureProtocol = true
12+
}
13+
}
14+
15+
mavenCentral()
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<verification-metadata xmlns="https://schema.gradle.org/dependency-verification"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.2.xsd">
5+
<configuration>
6+
<verify-metadata>true</verify-metadata>
7+
<verify-signatures>false</verify-signatures>
8+
</configuration>
9+
<components/>
10+
</verification-metadata>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rootProject.name = 'gradle-dependency-verification-test-project'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package datadog.smoke;
2+
3+
public class Calculator {
4+
5+
public int add(int left, int right) {
6+
return left + right;
7+
}
8+
}

dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ public final class ConfigDefaults {
201201
static final boolean DEFAULT_CIVISIBILITY_BUILD_INSTRUMENTATION_ENABLED = true;
202202
static final boolean DEFAULT_CIVISIBILITY_AUTO_CONFIGURATION_ENABLED = true;
203203
static final boolean DEFAULT_CIVISIBILITY_COMPILER_PLUGIN_AUTO_CONFIGURATION_ENABLED = true;
204+
static final boolean DEFAULT_CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED = false;
204205
static final String DEFAULT_CIVISIBILITY_COMPILER_PLUGIN_VERSION = "0.2.4";
205206
static final String DEFAULT_CIVISIBILITY_JACOCO_PLUGIN_VERSION = "0.8.15";
206207
static final String DEFAULT_CIVISIBILITY_JACOCO_PLUGIN_EXCLUDES =

dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ public final class CiVisibilityConfig {
8383
public static final String TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES =
8484
"test.management.attempt.to.fix.retries";
8585
public static final String TEST_FAILED_TEST_REPLAY_ENABLED = "test.failed.test.replay.enabled";
86+
public static final String CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED =
87+
"civisibility.gradle.dependency.verification.enabled";
8688

8789
/* Git PR info */
8890
public static final String GIT_PULL_REQUEST_BASE_BRANCH = "git.pull.request.base.branch";

internal-api/src/main/java/datadog/trace/api/Config.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import static datadog.trace.api.ConfigDefaults.DEFAULT_CIVISIBILITY_GIT_UNSHALLOW_ENABLED;
3636
import static datadog.trace.api.ConfigDefaults.DEFAULT_CIVISIBILITY_GIT_UPLOAD_ENABLED;
3737
import static datadog.trace.api.ConfigDefaults.DEFAULT_CIVISIBILITY_GIT_UPLOAD_TIMEOUT_MILLIS;
38+
import static datadog.trace.api.ConfigDefaults.DEFAULT_CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED;
3839
import static datadog.trace.api.ConfigDefaults.DEFAULT_CIVISIBILITY_JACOCO_PLUGIN_EXCLUDES;
3940
import static datadog.trace.api.ConfigDefaults.DEFAULT_CIVISIBILITY_JACOCO_PLUGIN_VERSION;
4041
import static datadog.trace.api.ConfigDefaults.DEFAULT_CIVISIBILITY_RESOURCE_FOLDER_NAMES;
@@ -279,6 +280,7 @@
279280
import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_GIT_UNSHALLOW_ENABLED;
280281
import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_GIT_UPLOAD_ENABLED;
281282
import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_GIT_UPLOAD_TIMEOUT_MILLIS;
283+
import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED;
282284
import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_GRADLE_SOURCE_SETS;
283285
import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_IMPACTED_TESTS_DETECTION_ENABLED;
284286
import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_INJECTED_TRACER_VERSION;
@@ -1163,6 +1165,7 @@ public static String getHostName() {
11631165
private final boolean ciVisibilityAutoConfigurationEnabled;
11641166
private final String ciVisibilityAdditionalChildProcessJvmArgs;
11651167
private final boolean ciVisibilityCompilerPluginAutoConfigurationEnabled;
1168+
private final boolean ciVisibilityGradleDependencyVerificationEnabled;
11661169
private final boolean ciVisibilityCodeCoverageEnabled;
11671170
private final Boolean ciVisibilityCoverageLinesEnabled;
11681171
private final String ciVisibilityCodeCoverageReportDumpDir;
@@ -2731,6 +2734,10 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment())
27312734
configProvider.getBoolean(
27322735
CIVISIBILITY_COMPILER_PLUGIN_AUTO_CONFIGURATION_ENABLED,
27332736
DEFAULT_CIVISIBILITY_COMPILER_PLUGIN_AUTO_CONFIGURATION_ENABLED);
2737+
ciVisibilityGradleDependencyVerificationEnabled =
2738+
configProvider.getBoolean(
2739+
CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED,
2740+
DEFAULT_CIVISIBILITY_GRADLE_DEPENDENCY_VERIFICATION_ENABLED);
27342741
ciVisibilityCodeCoverageEnabled =
27352742
configProvider.getBoolean(CIVISIBILITY_CODE_COVERAGE_ENABLED, true);
27362743
ciVisibilityCoverageLinesEnabled =
@@ -4571,6 +4578,10 @@ public List<String> getCiVisibilityJacocoGradleSourceSets() {
45714578
return ciVisibilityJacocoGradleSourceSets;
45724579
}
45734580

4581+
public boolean isCiVisibilityGradleDependencyVerificationEnabled() {
4582+
return ciVisibilityGradleDependencyVerificationEnabled;
4583+
}
4584+
45744585
public boolean isCiVisibilityCodeCoverageReportUploadEnabled() {
45754586
return ciVisibilityCodeCoverageReportUploadEnabled;
45764587
}
@@ -6986,6 +6997,8 @@ public String toString() {
69866997
+ otlpTracesCompression
69876998
+ ", otlpTracesTimeout="
69886999
+ otlpTracesTimeout
7000+
+ ", ciVisibilityGradleDependencyVerificationEnabled="
7001+
+ ciVisibilityGradleDependencyVerificationEnabled
69897002
+ ", serviceDiscoveryEnabled="
69907003
+ serviceDiscoveryEnabled
69917004
+ ", sfnInjectDatadogAttributeEnabled="

0 commit comments

Comments
 (0)