Skip to content

Commit

Permalink
Rename Test Visibility to Test Optimization + fix tags precedence
Browse files Browse the repository at this point in the history
  • Loading branch information
nikita-tkachenko-datadog committed Dec 5, 2024
1 parent 8463b71 commit 3897eaa
Show file tree
Hide file tree
Showing 20 changed files with 119 additions and 87 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ In declarative pipelines, add the step to a top-level `options` block like so:
pipeline {
agent any
options {
datadog(testVisibility: [
datadog(testOptimization: [
enabled: true,
serviceName: "my-service", // the name of service or library being tested
languages: ["JAVA"], // languages that should be instrumented (available options are "JAVA", "JAVASCRIPT", "PYTHON", "DOTNET")
Expand All @@ -269,7 +269,7 @@ pipeline {
In scripted pipelines, wrap the relevant section with the `datadog` step like so:

```groovy
datadog(testVisibility: [ enabled: true, serviceName: "my-service", languages: ["JAVA"], additionalVariables: [:] ]) {
datadog(testOptimization: [ enabled: true, serviceName: "my-service", languages: ["JAVA"], additionalVariables: [:] ]) {
node {
stage('Example') {
echo "Hello world."
Expand All @@ -278,7 +278,7 @@ datadog(testVisibility: [ enabled: true, serviceName: "my-service", languages: [
}
```

The other `datadog` settings, such as `collectLogs` or `tags` can be added alongside the `testVisibility` block.
The other `datadog` settings, such as `collectLogs` or `tags` can be added alongside the `testOptimization` block.

Please bear in mind that Test Optimization is a separate Datadog product that is billed separately.

Expand Down
2 changes: 2 additions & 0 deletions docker/controller-node/50-create-jobs.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Files.newDirectoryStream(Paths.get("/var/jenkins_home/sample-jobs")).forEach { p
TopLevelItem project = jenkins.getItemByFullName(jobName)
if (project != null) {
println("Job already exists: $jobName")
return

} else {
Class<? extends TopLevelItem> projectType
if (jobName.contains("freestyle")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,7 @@ public static Map<String, Set<String>> getTagsFromPipelineAction(Run<?, ?> run)
public static Map<String, Set<String>> getTagsFromPipelineAction(Run<?, ?> run, @Nullable FlowNode node) {
Map<String, Set<String>> mergedTags = new HashMap<>();
List<DatadogPipelineAction> actions = getDatadogPipelineActions(run, node);
// iterating from outer actions to inner ones to preserve priority
ListIterator<DatadogPipelineAction> it = actions.listIterator(actions.size());
while (it.hasPrevious()) {
DatadogPipelineAction action = it.previous();
for (DatadogPipelineAction action : actions) {
Map<String, Set<String>> tags = getTagsFromPipelineAction(action);
TagsUtil.merge(mergedTags, tags);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.datadog.jenkins.plugins.datadog.DatadogUtilities;
import org.datadog.jenkins.plugins.datadog.model.DatadogPluginAction;
import org.datadog.jenkins.plugins.datadog.steps.DatadogPipelineAction;
import org.datadog.jenkins.plugins.datadog.steps.TestVisibility;
import org.datadog.jenkins.plugins.datadog.steps.TestOptimization;
import org.jenkinsci.plugins.workflow.graph.FlowNode;

public class DatadogTracerConfigurator {
Expand All @@ -45,28 +45,28 @@ public DatadogTracerConfigurator() {
configurators.put(TracerLanguage.PYTHON, new PythonConfigurator());
}

private TestVisibility getTestVisibility(FlowNode node, Run<?, ?> run) {
private TestOptimization getTestOptimization(FlowNode node, Run<?, ?> run) {
List<DatadogPipelineAction> actions = DatadogUtilities.getDatadogPipelineActions(run, node);
for (DatadogPipelineAction action : actions) {
TestVisibility testVisibility = action.getTestVisibility();
if (testVisibility != null) {
return testVisibility;
TestOptimization testOptimization = action.getTestOptimization();
if (testOptimization != null) {
return testOptimization;
}
}

Job<?, ?> job = run.getParent();
DatadogTracerJobProperty<?> tracerJobProperty = job.getProperty(DatadogTracerJobProperty.class);
if (tracerJobProperty != null) {
// configured via UI
return tracerJobProperty.getTestVisibility();
return tracerJobProperty.getTestOptimization();
}

return null;
}

public Map<String, String> configure(Run<?, ?> run, Computer computer, Node node, FlowNode flowNode, EnvVars envs, TaskListener listener) {
TestVisibility testVisibility = getTestVisibility(flowNode, run);
if (testVisibility == null || !testVisibility.getEnabled()){
TestOptimization testOptimization = getTestOptimization(flowNode, run);
if (testOptimization == null || !testOptimization.getEnabled()){
return Collections.emptyMap();
}

Expand All @@ -78,7 +78,7 @@ public Map<String, String> configure(Run<?, ?> run, Computer computer, Node node
}

String nodeHostname = DatadogUtilities.getNodeHostname(envs, computer);
Collection<TracerLanguage> languages = testVisibility.getLanguages();
Collection<TracerLanguage> languages = testOptimization.getLanguages();
for (ConfigureTracerAction action : run.getActions(ConfigureTracerAction.class)) {
if (nodeHostname != null && nodeHostname.equals(action.nodeHostname) && action.languages.containsAll(languages)) {
boolean previousConfigurationValid = true;
Expand All @@ -100,7 +100,7 @@ public Map<String, String> configure(Run<?, ?> run, Computer computer, Node node
return Collections.emptyMap();
}

Map<String, String> variables = new HashMap<>(getCommonEnvVariables(datadogConfig, testVisibility));
Map<String, String> variables = new HashMap<>(getCommonEnvVariables(datadogConfig, testOptimization));
for (TracerLanguage language : languages) {
TracerConfigurator tracerConfigurator = configurators.get(language);
if (tracerConfigurator == null) {
Expand All @@ -109,7 +109,7 @@ public Map<String, String> configure(Run<?, ?> run, Computer computer, Node node
}

try {
Map<String, String> languageVariables = tracerConfigurator.configure(testVisibility, node, workspacePath, envs, listener);
Map<String, String> languageVariables = tracerConfigurator.configure(testOptimization, node, workspacePath, envs, listener);
variables.putAll(languageVariables);
} catch (Exception e) {
ExceptionUtils.printRootCauseStackTrace(e, listener.error("[datadog] Error while configuring " + language + " Datadog Tracer for run " + run + " and node " + node));
Expand Down Expand Up @@ -140,12 +140,12 @@ private static TopLevelItem getTopLevelItem(Run<?, ?> run) {
}

private static Map<String, String> getCommonEnvVariables(DatadogGlobalConfiguration datadogConfig,
TestVisibility testVisibility) {
TestOptimization testOptimization) {
Map<String, String> variables = new HashMap<>();
variables.put("DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER", "jenkins");
variables.put("DD_CIVISIBILITY_ENABLED", "true");
variables.put("DD_ENV", "ci");
variables.put("DD_SERVICE", testVisibility.getServiceName());
variables.put("DD_SERVICE", testOptimization.getServiceName());

DatadogClient.ClientType clientType = DatadogClient.ClientType.valueOf(datadogConfig.getReportWith());
switch (clientType) {
Expand All @@ -162,7 +162,7 @@ private static Map<String, String> getCommonEnvVariables(DatadogGlobalConfigurat
throw new IllegalArgumentException("Unexpected client type: " + clientType);
}

Map<String, String> additionalVariables = testVisibility.getAdditionalVariables();
Map<String, String> additionalVariables = testOptimization.getAdditionalVariables();
if (additionalVariables != null) {
variables.putAll(additionalVariables);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
import java.util.Set;
import javax.annotation.Nonnull;
import net.sf.json.JSONObject;
import org.datadog.jenkins.plugins.datadog.steps.TestVisibility;
import org.datadog.jenkins.plugins.datadog.steps.TestOptimization;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

public class DatadogTracerJobProperty<T extends Job<?, ?>> extends JobProperty<T> {

private static final String DISPLAY_NAME = "Enable Datadog Test Visibility";
private static final String DISPLAY_NAME = "Enable Datadog Test Optimization";

private final boolean on;
private final String serviceName;
Expand Down Expand Up @@ -61,8 +61,8 @@ public List<DatadogTracerEnvironmentProperty> getAdditionalVariablesAsList() {
return list;
}

public TestVisibility getTestVisibility() {
return new TestVisibility(on, serviceName, languages, additionalVariables);
public TestOptimization getTestOptimization() {
return new TestOptimization(on, serviceName, languages, additionalVariables);
}

@Extension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import hudson.FilePath;
import hudson.model.Node;
import hudson.model.TaskListener;
import org.datadog.jenkins.plugins.datadog.steps.TestVisibility;
import org.datadog.jenkins.plugins.datadog.steps.TestOptimization;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -15,7 +15,7 @@ public class DotnetConfigurator implements TracerConfigurator {
private static final int SHOW_TRACER_VARS_TIMEOUT_MILLIS = 30_000;

@Override
public Map<String, String> configure(TestVisibility testVisibility, Node node, FilePath workspacePath, Map<String, String> envs, TaskListener listener) throws Exception {
public Map<String, String> configure(TestOptimization testOptimization, Node node, FilePath workspacePath, Map<String, String> envs, TaskListener listener) throws Exception {
String dotnetVersion = workspacePath.act(new ShellCommandCallable(Collections.emptyMap(), GET_DOTNET_VERSION_TIMEOUT_MILLIS, "dotnet", "--version"));
listener.getLogger().println("[datadog] Configuring DD .NET tracer: got .NET version " + dotnetVersion + " from " + workspacePath + " on " + node);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.datadog.jenkins.plugins.datadog.DatadogUtilities;
import org.datadog.jenkins.plugins.datadog.apm.signature.SignatureVerifier;
import org.datadog.jenkins.plugins.datadog.clients.HttpClient;
import org.datadog.jenkins.plugins.datadog.steps.TestVisibility;
import org.datadog.jenkins.plugins.datadog.steps.TestOptimization;

import java.io.ByteArrayInputStream;
import java.io.IOException;
Expand Down Expand Up @@ -40,21 +40,21 @@ final class JavaConfigurator implements TracerConfigurator {
private final HttpClient httpClient = new HttpClient(TRACER_DOWNLOAD_TIMEOUT_MILLIS);

@Override
public Map<String, String> configure(TestVisibility testVisibility, Node node, FilePath workspacePath, Map<String, String> envs, TaskListener listener) throws Exception {
FilePath tracerFile = downloadTracer(testVisibility, workspacePath,node, listener);
return getEnvVariables(testVisibility, node, tracerFile, envs);
public Map<String, String> configure(TestOptimization testOptimization, Node node, FilePath workspacePath, Map<String, String> envs, TaskListener listener) throws Exception {
FilePath tracerFile = downloadTracer(testOptimization, workspacePath,node, listener);
return getEnvVariables(testOptimization, node, tracerFile, envs);
}

private FilePath downloadTracer(TestVisibility testVisibility, FilePath workspacePath, Node node, TaskListener listener) throws Exception {
private FilePath downloadTracer(TestOptimization testOptimization, FilePath workspacePath, Node node, TaskListener listener) throws Exception {
FilePath datadogTracerFile = getDatadogTracerFile(workspacePath);
long minutesSinceModification = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - datadogTracerFile.lastModified());
if (minutesSinceModification < getTracerJarCacheTtlMinutes(testVisibility)) {
if (minutesSinceModification < getTracerJarCacheTtlMinutes(testOptimization)) {
listener.getLogger().println("[datadog] Configuring DD Java tracer: using existing tracer available at " + datadogTracerFile);
// downloaded tracer is fresh enough
return datadogTracerFile.absolutize();
}

String tracerDistributionUrl = getTracerDistributionUrl(testVisibility);
String tracerDistributionUrl = getTracerDistributionUrl(testOptimization);
httpClient.getBinary(tracerDistributionUrl, Collections.emptyMap(), is -> {
try {
datadogTracerFile.copyFrom(is);
Expand All @@ -68,7 +68,7 @@ private FilePath downloadTracer(TestVisibility testVisibility, FilePath workspac
if (!DEFAULT_TRACER_DISTRIBUTION_URL.equals(tracerDistributionUrl)) {
// verify signature if downloading from Maven Central
String signatureFileUrl = tracerDistributionUrl + ".asc";
byte[] signaturePublicKey = getTracerSignaturePublicKey(testVisibility);
byte[] signaturePublicKey = getTracerSignaturePublicKey(testOptimization);

httpClient.getBinary(signatureFileUrl, Collections.emptyMap(), signatureStream -> {
try (InputStream tracerStream = datadogTracerFile.read();
Expand All @@ -92,20 +92,20 @@ private static FilePath getDatadogTracerFile(FilePath workspacePath) throws IOEx
return datadogFolder.child(TRACER_FILE_NAME);
}

private int getTracerJarCacheTtlMinutes(TestVisibility testVisibility) {
return getSetting(testVisibility, TRACER_JAR_CACHE_TTL_ENV_VAR, DEFAULT_TRACER_JAR_CACHE_TTL_MINUTES, Integer::parseInt);
private int getTracerJarCacheTtlMinutes(TestOptimization testOptimization) {
return getSetting(testOptimization, TRACER_JAR_CACHE_TTL_ENV_VAR, DEFAULT_TRACER_JAR_CACHE_TTL_MINUTES, Integer::parseInt);
}

private String getTracerDistributionUrl(TestVisibility testVisibility) {
return getSetting(testVisibility, TRACER_DISTRIBUTION_URL_ENV_VAR, DEFAULT_TRACER_DISTRIBUTION_URL, this::validateUserSuppliedTracerUrl);
private String getTracerDistributionUrl(TestOptimization testOptimization) {
return getSetting(testOptimization, TRACER_DISTRIBUTION_URL_ENV_VAR, DEFAULT_TRACER_DISTRIBUTION_URL, this::validateUserSuppliedTracerUrl);
}

private byte[] getTracerSignaturePublicKey(TestVisibility testVisibility) {
return getSetting(testVisibility, DATADOG_PUBLIC_KEY_ENV_VAR, SignatureVerifier.DATADOG_PUBLIC_KEY.getBytes(StandardCharsets.UTF_8), String::getBytes);
private byte[] getTracerSignaturePublicKey(TestOptimization testOptimization) {
return getSetting(testOptimization, DATADOG_PUBLIC_KEY_ENV_VAR, SignatureVerifier.DATADOG_PUBLIC_KEY.getBytes(StandardCharsets.UTF_8), String::getBytes);
}

private <T> T getSetting(TestVisibility testVisibility, String envVariableName, T defaultValue, Function<String, T> parser) {
String envVariable = getEnvVariable(testVisibility, envVariableName);
private <T> T getSetting(TestOptimization testOptimization, String envVariableName, T defaultValue, Function<String, T> parser) {
String envVariable = getEnvVariable(testOptimization, envVariableName);
if (envVariable != null) {
try {
return parser.apply(envVariable);
Expand All @@ -117,8 +117,8 @@ private <T> T getSetting(TestVisibility testVisibility, String envVariableName,
return defaultValue;
}

private String getEnvVariable(TestVisibility testVisibility, String name) {
Map<String, String> additionalVariables = testVisibility.getAdditionalVariables();
private String getEnvVariable(TestOptimization testOptimization, String name) {
Map<String, String> additionalVariables = testOptimization.getAdditionalVariables();
if (additionalVariables != null) {
String envVariable = additionalVariables.get(name);
if (envVariable != null) {
Expand All @@ -137,7 +137,7 @@ private String validateUserSuppliedTracerUrl(String distributionUrl) {
}
}

private static Map<String, String> getEnvVariables(TestVisibility testVisibility,
private static Map<String, String> getEnvVariables(TestOptimization testOptimization,
Node node,
FilePath tracerFile,
Map<String, String> envs) {
Expand All @@ -150,20 +150,20 @@ private static Map<String, String> getEnvVariables(TestVisibility testVisibility
variables.put("ANT_OPTS", PropertyUtils.prepend(envs, "ANT_OPTS", tracerAgent));
variables.put("GRADLE_OPTS", PropertyUtils.prepend(envs, "GRADLE_OPTS", "-Dorg.gradle.jvmargs=" + tracerAgent));

String proxyConfiguration = getProxyConfiguration(testVisibility, node);
String proxyConfiguration = getProxyConfiguration(testOptimization, node);
if (proxyConfiguration != null) {
variables.put("JAVA_TOOL_OPTIONS", PropertyUtils.prepend(variables, "JAVA_TOOL_OPTIONS", proxyConfiguration));
}

Map<String, String> additionalVariables = testVisibility.getAdditionalVariables();
Map<String, String> additionalVariables = testOptimization.getAdditionalVariables();
if (additionalVariables != null) {
variables.putAll(additionalVariables);
}

return variables;
}

private static String getProxyConfiguration(TestVisibility testVisibility, Node node) {
private static String getProxyConfiguration(TestOptimization testOptimization, Node node) {
if (!(node instanceof Jenkins)) {
// only apply Jenkins proxy settings if tracer will be run on master node
return null;
Expand All @@ -178,7 +178,7 @@ private static String getProxyConfiguration(TestVisibility testVisibility, Node
return null;
}

Map<String, String> additionalVariables = testVisibility.getAdditionalVariables();
Map<String, String> additionalVariables = testOptimization.getAdditionalVariables();
if (Boolean.parseBoolean(additionalVariables.get(TRACER_IGNORE_JENKINS_PROXY_ENV_VAR))) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import org.datadog.jenkins.plugins.datadog.DatadogUtilities;
import org.datadog.jenkins.plugins.datadog.steps.TestVisibility;
import org.datadog.jenkins.plugins.datadog.steps.TestOptimization;

final class JavascriptConfigurator implements TracerConfigurator {

Expand All @@ -23,7 +23,7 @@ final class JavascriptConfigurator implements TracerConfigurator {
private static final String RELATIVE_TRACER_PATH = "lib/node_modules/dd-trace";

@Override
public Map<String, String> configure(TestVisibility testVisibility, Node node, FilePath workspacePath, Map<String, String> envs, TaskListener listener) throws Exception {
public Map<String, String> configure(TestOptimization testOptimization, Node node, FilePath workspacePath, Map<String, String> envs, TaskListener listener) throws Exception {
String nodeVersion = workspacePath.act(new ShellCommandCallable(Collections.emptyMap(), GET_NPM_VERSION_TIMEOUT_MILLIS, "npm", "-v"));
listener.getLogger().println("[datadog] Configuring DD JS tracer: got npm version " + nodeVersion + " from " + workspacePath + " on " + node);

Expand Down
Loading

0 comments on commit 3897eaa

Please sign in to comment.