[maven-extension] Capture details on mojo goal executions: `deploy:deploy`, `spring-boot:build-image`, `jib:build`, `snyk:test`, `snyk:monitor` (#146)
* Capture details on mojo goal executions: deploy:deploy, spring-boot:build-image * Update screenshot * Make spotless happy * Clarify TODO + better class name * Improve code * Code cleanup * Code cleanup * Add handlers for `snyk:test` and `snyk:monitor` * Add support for the Google Maven Jib Plugin * Add unit tests, code cleanup * Better README.md * Better README.md * Cleanup code * Iterate on the semantic conventions * Replace Optional by `@Nullable * Make the built-in MojoGoalExecutionHandlers non-public while keeping the SPI mechanism * Make the built-in MojoGoalExecutionHandlers non-public while keeping the SPI mechanism * spotless apply * Stop capturing auth username waiting for config flag to disable this * Fix Javadocs * Fix typo
This commit is contained in:
parent
8cf71605a5
commit
2c02e42003
|
@ -57,42 +57,126 @@ mvn verify
|
|||
|
||||
Without this setting, the traces won't be exported and the OpenTelemetry Maven Extension will behave as a NoOp extension. `otlp` is currently the only supported exporter.
|
||||
|
||||
The Maven OpenTelemetry Extension supports a subset of the [OpenTelemetry auto configuration environment variables and JVM system properties](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure).
|
||||
The Maven OpenTelemetry Extension supports a subset of the [OpenTelemetry autoconfiguration environment variables and JVM system properties](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure).
|
||||
|
||||
|
||||
| System property | Environment variable | Default value | Description |
|
||||
|------------------------------|-----------------------------|-------------------------|---------------------------------------------------------------------------|
|
||||
| otel.traces.exporter | OTEL_TRACES_EXPORTER | `none` | Select the OpenTelemetry exporter for tracing, the currently only supported values are `none` and `otlp`. `none` makes the instrumentation NoOp |
|
||||
| otel.exporter.otlp.endpoint | OTEL_EXPORTER_OTLP_ENDPOINT | `http://localhost:4317` | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. |
|
||||
| otel.exporter.otlp.headers | OTEL_EXPORTER_OTLP_HEADERS | | Key-value pairs separated by commas to pass as request headers on OTLP trace and metrics requests. |
|
||||
| otel.exporter.otlp.timeout | OTEL_EXPORTER_OTLP_TIMEOUT | `10000` | The maximum waiting time, in milliseconds, allowed to send each OTLP trace and metric batch. |
|
||||
| otel.resource.attributes | OTEL_RESOURCE_ATTRIBUTES | | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
|
||||
| otel.instrumentation.maven.mojo.enabled | OTEL_INSTRUMENTATION_MAVEN_MOJO_ENABLED | `true` | Whether to create spans for mojo goal executions, `true` or `false`. Can be configured to reduce the number of spans created for large builds. |
|
||||
| System property <br /> Environment variable | Default value | Description |
|
||||
|--------------------------------------------------------------------------------------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `otel.traces.exporter` <br /> `OTEL_TRACES_EXPORTER` | `none` | Select the OpenTelemetry exporter for tracing, the currently only supported values are `none` and `otlp`. `none` makes the instrumentation NoOp |
|
||||
| `otel.exporter.otlp.endpoint` <br /> `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4317` | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. |
|
||||
| `otel.exporter.otlp.headers` <br /> `OTEL_EXPORTER_OTLP_HEADERS` | | Key-value pairs separated by commas to pass as request headers on OTLP trace and metrics requests. |
|
||||
| `otel.exporter.otlp.timeout` <br /> `OTEL_EXPORTER_OTLP_TIMEOUT` | `10000` | The maximum waiting time, in milliseconds, allowed to send each OTLP trace and metric batch. |
|
||||
| `otel.resource.attributes` <br /> `OTEL_RESOURCE_ATTRIBUTES` | | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
|
||||
| `otel.instrumentation.maven.mojo.enabled` <br /> `OTEL_INSTRUMENTATION_MAVEN_MOJO_ENABLED` | `true` | Whether to create spans for mojo goal executions, `true` or `false`. Can be configured to reduce the number of spans created for large builds. |
|
||||
|
||||
|
||||
ℹ️ The `service.name` is set to `maven` and the `service.version` to the version of the Maven runtime in use.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Example of a trace of a Maven build.
|
||||
|
||||

|
||||
|
||||
## Example of a distributed trace of a Jenkins pipeline executing a Maven build
|
||||
### Example of a distributed trace of a Jenkins pipeline executing a Maven build
|
||||
|
||||
Distributed trace of a Jenkins pipeline invoking a Maven build instrumented with the [Jenkins OpenTelemetry plugin](https://plugins.jenkins.io/opentelemetry/) and the OpenTelemetry Maven Extension and visualized with [Jaeger Tracing](https://www.jaegertracing.io/)
|
||||
|
||||

|
||||
|
||||
# Other CI/CD Tools supporting OpenTelemetry traces
|
||||
## Span attributes per Maven plugin goal execution
|
||||
|
||||
### Span attributes captured for every Maven plugin goal execution
|
||||
|
||||
| Span attribute | Type | Description |
|
||||
|----------------------------------|--------|----------------------------------------------------------------------|
|
||||
| `maven.project.groupId` | string | Group ID of the Maven project on which the Maven goal is executed |
|
||||
| `maven.project.artifactId` | string | Artifact ID of the Maven project on which the Maven goal is executed |
|
||||
| `maven.project.version` | string | Version of the Maven project on which the Maven goal is executed |
|
||||
| `maven.plugin.groupId` | string | Group ID of the Maven plugin on which the Maven goal is executed |
|
||||
| `maven.plugin.artifactId` | string | Artifact ID of the Maven plugin on which the Maven goal is executed |
|
||||
| `maven.plugin.version` | string | Version of the Maven plugin on which the Maven goal is executed |
|
||||
| `maven.execution.goal` | string | Goal that is being executed |
|
||||
| `maven.execution.id` | string | ID of the execution |
|
||||
| `maven.execution.lifecyclePhase` | string | Lifecycle phase to which belong the execution |
|
||||
|
||||
### `deploy:deploy`
|
||||
|
||||
In addition to the span attributes captured on every Maven plugin goal execution as described above:
|
||||
|
||||
| Span attribute | Type | Description |
|
||||
|----------------------------------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `http.method` | string | `POST` |
|
||||
| `http.url` | string | Base URL of the uploaded artifact `${maven.build.repository.url}/${groupId}/${artifactId}/${version}` where the `.` of `${groupId}` are replaced by `/` |
|
||||
| `maven.build.repository.id` | string | ID of the Maven repository to which the artifact is deployed. See [Maven POM reference / Repository](https://maven.apache.org/pom.html#repository) |
|
||||
| `maven.build.repository.url` | string | URL of the Maven repository to which the artifact is deployed. See [Maven POM reference / Repository](https://maven.apache.org/pom.html#repository) |
|
||||
| `peer.service` | string | Maven repository hostname deduced from the Repository URL |
|
||||
|
||||
The `span.kind` is set to `client`
|
||||
|
||||
### `jib:build`
|
||||
|
||||
| Span attribute | Type | Description |
|
||||
|-------------------------------------------------|----------|------------------------------------------------------------------------------------------------------------|
|
||||
| `http.method` | string | `POST` |
|
||||
| `http.url` | string | URL on the Docker registry deduced from the Docker image specified in the `build` goal configuration. |
|
||||
| `maven.build.container.image.name` | string | Name of the produced Docker image |
|
||||
| `maven.build.container.image.tags` | string[] | Tags of the produced Docker image |
|
||||
| `maven.build.container.registry.url` | string | URL of the container registry to which this image is uploaded. |
|
||||
| `peer.service` | string | Docker Registry hostname. |
|
||||
|
||||
The `span.kind` is set to `client`
|
||||
|
||||
|
||||
### `snyk:monitor`
|
||||
|
||||
See https://github.com/snyk/snyk-maven-plugin
|
||||
|
||||
| Span attribute | Type | Description |
|
||||
|----------------|--------|------------------------------------------------------------------------------------------------|
|
||||
| `http.method` | string | `POST` |
|
||||
| `http.url` | string | `https://snyk.io/api/v1/monitor/maven` the underlying Snyk API URL invoked by the Maven plugin.|
|
||||
| `rpc.method` | string | `monitor`, the underlying Snyk CLI command invoked by the Maven plugin.|
|
||||
| `peer.service` | string | `snyk.io` |
|
||||
|
||||
The `span.kind` is set to `client`
|
||||
|
||||
### `snyk:test`
|
||||
|
||||
See https://github.com/snyk/snyk-maven-plugin
|
||||
|
||||
| Span attribute | Type | Description |
|
||||
|----------------|--------|----------------------------------------------------------------------|
|
||||
| `http.method` | string | `POST` |
|
||||
| `http.url` | string | `https://snyk.io/api/v1/test-dep-graph` |
|
||||
| `rpc.method` | string | `test`, the underlying Snyk CLI command invoked by the Maven plugin. |
|
||||
| `peer.service` | string | `snyk.io` |
|
||||
|
||||
|
||||
The `span.kind` is set to `client`
|
||||
|
||||
### `spring-boot:build-image`
|
||||
|
||||
| Span attribute | Type | Description |
|
||||
|------------------------------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `http.method` | string | `POST`. Attribute only added when the `build-image` goal publishes the Docker image. |
|
||||
| `http.url` | string | URL on the Docker registry, deduced from the Docker image. Attribute only added when the `build-image` goal publishes the Docker image. |
|
||||
| `maven.build.container.image.name` | string | Name of the produced Docker image. Attribute only added when the `build-image` goal publishes the Docker image. |
|
||||
| `maven.build.container.image.tags` | string[] | Tags of the produced Docker image. Attribute only added when the `build-image` goal publishes the Docker image. |
|
||||
| `maven.build.container.registry.url` | string | URL of the container registry to which this image is uploaded. Attribute only added when the `build-image` goal publishes the Docker image.|
|
||||
| `peer.service` | string | Docker Registry hostname. Attribute only added when the `build-image` goal publishes the Docker image. |
|
||||
|
||||
The `span.kind` is set to `client`
|
||||
|
||||
|
||||
## Other CI/CD Tools supporting OpenTelemetry traces
|
||||
|
||||
List of other CI/CD tools that support OpenTelemetry traces and integrate with the Maven OpenTelemetry Extension creating a distributed traces providing end to end visibility.
|
||||
|
||||
## Jenkins OpenTelemetry Plugin
|
||||
### Jenkins OpenTelemetry Plugin
|
||||
|
||||
The [Jenkins OpenTelemetry Plugin](https://plugins.jenkins.io/opentelemetry/) exposes Jenkins pipelines & jobs as OpenTelemetry traces and exposes Jenkins health indicators as OpenTelemetry metrics.
|
||||
|
||||
## Otel CLI
|
||||
### Otel CLI
|
||||
|
||||
The [`otel-cli`](https://github.com/equinix-labs/otel-cli) is a command line wrapper to observe the execution of a shell command as an OpenTelemetry trace.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 616 KiB |
Binary file not shown.
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 519 KiB |
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import org.apache.maven.plugin.MojoExecution;
|
||||
|
||||
@AutoValue
|
||||
public abstract class MavenGoal {
|
||||
public static MavenGoal create(String groupId, String artifactId, String goal) {
|
||||
return new AutoValue_MavenGoal(groupId, artifactId, goal);
|
||||
}
|
||||
|
||||
public static MavenGoal create(MojoExecution mojoExecution) {
|
||||
return create(
|
||||
mojoExecution.getGroupId(), mojoExecution.getArtifactId(), mojoExecution.getGoal());
|
||||
}
|
||||
|
||||
abstract String groupId();
|
||||
|
||||
abstract String artifactId();
|
||||
|
||||
abstract String goal();
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return "MavenGoal{ "
|
||||
+ groupId()
|
||||
+ ":"
|
||||
+ MavenUtils.getPluginArtifactIdShortName(artifactId())
|
||||
+ ":"
|
||||
+ goal()
|
||||
+ "}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import org.apache.maven.plugin.MojoExecution;
|
||||
|
||||
final class MavenUtils {
|
||||
private MavenUtils() {}
|
||||
|
||||
/**
|
||||
* Shorten plugin identifiers.
|
||||
*
|
||||
* <p>Examples:
|
||||
*
|
||||
* <ul>
|
||||
* <li>maven-clean-plugin -> clean
|
||||
* <li>sisu-maven-plugin -> sisu
|
||||
* <li>spotbugs-maven-plugin -> spotbugs
|
||||
* </ul>
|
||||
*
|
||||
* @param pluginArtifactId the artifact ID of the mojo {@link MojoExecution#getArtifactId()}
|
||||
* @return shortened name
|
||||
*/
|
||||
static String getPluginArtifactIdShortName(String pluginArtifactId) {
|
||||
if (pluginArtifactId.endsWith("-maven-plugin")) {
|
||||
return pluginArtifactId.substring(0, pluginArtifactId.length() - "-maven-plugin".length());
|
||||
} else if (pluginArtifactId.startsWith("maven-") && pluginArtifactId.endsWith("-plugin")) {
|
||||
return pluginArtifactId.substring(
|
||||
"maven-".length(), pluginArtifactId.length() - "-plugin".length());
|
||||
} else {
|
||||
return pluginArtifactId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,19 +6,25 @@
|
|||
package io.opentelemetry.maven;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapGetter;
|
||||
import io.opentelemetry.maven.handler.MojoGoalExecutionHandler;
|
||||
import io.opentelemetry.maven.handler.MojoGoalExecutionHandlerConfiguration;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import org.apache.maven.execution.AbstractExecutionListener;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
import org.apache.maven.execution.ExecutionListener;
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.apache.maven.lifecycle.LifecycleExecutionException;
|
||||
import org.apache.maven.plugin.MojoExecution;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.component.annotations.Component;
|
||||
|
@ -27,7 +33,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Close the OpenTelemetry SDK (see {@link OpenTelemetrySdkService#dispose()} on the end of
|
||||
* Close the OpenTelemetry SDK (see {@link OpenTelemetrySdkService#dispose()}) on the end of
|
||||
* execution of the last project ({@link #projectSucceeded(ExecutionEvent)} and {@link
|
||||
* #projectFailed(ExecutionEvent)}) rather than on the end of the Maven session {@link
|
||||
* #sessionEnded(ExecutionEvent)} because OpenTelemetry and GRPC classes are unloaded by the Maven
|
||||
|
@ -47,6 +53,22 @@ public final class OtelExecutionListener extends AbstractExecutionListener {
|
|||
@Requirement
|
||||
private OpenTelemetrySdkService openTelemetrySdkService;
|
||||
|
||||
private Map<MavenGoal, MojoGoalExecutionHandler> mojoGoalExecutionHandlers = new HashMap<>();
|
||||
|
||||
public OtelExecutionListener() {
|
||||
this.mojoGoalExecutionHandlers =
|
||||
MojoGoalExecutionHandlerConfiguration.loadMojoGoalExecutionHandler(
|
||||
OtelExecutionListener.class.getClassLoader());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"OpenTelemetry: mojoGoalExecutionHandlers: "
|
||||
+ mojoGoalExecutionHandlers.entrySet().stream()
|
||||
.map(entry -> entry.getKey().toString() + ": " + entry.getValue().toString())
|
||||
.collect(Collectors.joining(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register in given {@link OtelExecutionListener} to the lifecycle of the given {@link
|
||||
* MavenSession}
|
||||
|
@ -168,16 +190,16 @@ public final class OtelExecutionListener extends AbstractExecutionListener {
|
|||
Span rootSpan = spanRegistry.getSpan(executionEvent.getProject());
|
||||
|
||||
final String spanName =
|
||||
getPluginArtifactIdShortName(mojoExecution.getArtifactId())
|
||||
MavenUtils.getPluginArtifactIdShortName(mojoExecution.getArtifactId())
|
||||
+ ":"
|
||||
+ mojoExecution.getGoal()
|
||||
+ " ("
|
||||
+ executionEvent.getMojoExecution().getExecutionId()
|
||||
+ mojoExecution.getExecutionId()
|
||||
+ ")"
|
||||
+ " @ "
|
||||
+ executionEvent.getProject().getArtifactId();
|
||||
logger.debug("OpenTelemetry: Start mojo execution: span {}", spanName);
|
||||
Span span =
|
||||
SpanBuilder spanBuilder =
|
||||
this.openTelemetrySdkService
|
||||
.getTracer()
|
||||
.spanBuilder(spanName)
|
||||
|
@ -205,8 +227,16 @@ public final class OtelExecutionListener extends AbstractExecutionListener {
|
|||
MavenOtelSemanticAttributes.MAVEN_EXECUTION_ID, mojoExecution.getExecutionId())
|
||||
.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_EXECUTION_LIFECYCLE_PHASE,
|
||||
mojoExecution.getLifecyclePhase())
|
||||
.startSpan();
|
||||
mojoExecution.getLifecyclePhase());
|
||||
// enrich spans with MojoGoalExecutionHandler
|
||||
MojoGoalExecutionHandler handler =
|
||||
this.mojoGoalExecutionHandlers.get(MavenGoal.create(mojoExecution));
|
||||
logger.debug("OpenTelemetry: {} handler {}", executionEvent, handler);
|
||||
if (handler != null) {
|
||||
handler.enrichSpan(spanBuilder, executionEvent);
|
||||
}
|
||||
|
||||
Span span = spanBuilder.startSpan();
|
||||
spanRegistry.putSpan(span, mojoExecution, executionEvent.getProject());
|
||||
}
|
||||
|
||||
|
@ -238,6 +268,13 @@ public final class OtelExecutionListener extends AbstractExecutionListener {
|
|||
executionEvent.getProject());
|
||||
Span mojoExecutionSpan = spanRegistry.removeSpan(mojoExecution, executionEvent.getProject());
|
||||
mojoExecutionSpan.setStatus(StatusCode.ERROR, "Mojo Failed"); // TODO verify description
|
||||
Throwable exception = executionEvent.getException();
|
||||
if (exception instanceof LifecycleExecutionException) {
|
||||
LifecycleExecutionException executionException = (LifecycleExecutionException) exception;
|
||||
// we already capture the context, no need to capture it again
|
||||
exception = executionException.getCause();
|
||||
}
|
||||
mojoExecutionSpan.recordException(exception);
|
||||
mojoExecutionSpan.end();
|
||||
}
|
||||
|
||||
|
@ -247,32 +284,6 @@ public final class OtelExecutionListener extends AbstractExecutionListener {
|
|||
spanRegistry.removeRootSpan().end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten plugin identifiers.
|
||||
*
|
||||
* <p>Examples:
|
||||
*
|
||||
* <ul>
|
||||
* <li>maven-clean-plugin -> clean
|
||||
* <li>sisu-maven-plugin -> sisu
|
||||
* <li>spotbugs-maven-plugin -> spotbugs
|
||||
* </ul>
|
||||
*
|
||||
* @param pluginArtifactId the artifact ID of the mojo {@link MojoExecution#getArtifactId()}
|
||||
* @return shortened name
|
||||
*/
|
||||
// Visible for testing
|
||||
String getPluginArtifactIdShortName(String pluginArtifactId) {
|
||||
if (pluginArtifactId.endsWith("-maven-plugin")) {
|
||||
return pluginArtifactId.substring(0, pluginArtifactId.length() - "-maven-plugin".length());
|
||||
} else if (pluginArtifactId.startsWith("maven-") && pluginArtifactId.endsWith("-plugin")) {
|
||||
return pluginArtifactId.substring(
|
||||
"maven-".length(), pluginArtifactId.length() - "-plugin".length());
|
||||
} else {
|
||||
return pluginArtifactId;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ToUpperCaseTextMapGetter implements TextMapGetter<Map<String, String>> {
|
||||
@Override
|
||||
public Iterable<String> keys(Map<String, String> environmentVariables) {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** See https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin */
|
||||
final class GoogleJibBuildHandler implements MojoGoalExecutionHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(GoogleJibBuildHandler.class);
|
||||
|
||||
@Override
|
||||
public List<MavenGoal> getSupportedGoals() {
|
||||
return Collections.singletonList(
|
||||
MavenGoal.create("com.google.cloud.tools", "jib-maven-plugin", "build"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enrichSpan(SpanBuilder spanBuilder, ExecutionEvent executionEvent) {
|
||||
spanBuilder.setSpanKind(SpanKind.CLIENT);
|
||||
|
||||
Xpp3Dom pluginNode = executionEvent.getMojoExecution().getConfiguration();
|
||||
if (pluginNode == null) {
|
||||
logger.debug("OpenTelemetry: GoogleJibBuildHandler: config node not found");
|
||||
return;
|
||||
}
|
||||
Xpp3Dom toNode = pluginNode.getChild("to");
|
||||
if (pluginNode == null) {
|
||||
logger.debug("OpenTelemetry: GoogleJibBuildHandler: 'to' node not found");
|
||||
return;
|
||||
}
|
||||
Xpp3Dom imageNode = toNode.getChild("image");
|
||||
if (pluginNode == null) {
|
||||
logger.debug("OpenTelemetry: GoogleJibBuildHandler: 'to/image' node not found");
|
||||
return;
|
||||
}
|
||||
String imageNameAndTagValue = imageNode.getValue();
|
||||
if (imageNameAndTagValue == null) {
|
||||
logger.debug("OpenTelemetry: GoogleJibBuildHandler: value of node 'to/image' is null");
|
||||
return;
|
||||
}
|
||||
|
||||
String imageName;
|
||||
List<String> imageTags = new ArrayList<>();
|
||||
|
||||
int colonIdx = imageNameAndTagValue.indexOf(':');
|
||||
if (colonIdx == -1) {
|
||||
imageName = imageNameAndTagValue;
|
||||
// imageTag not specified
|
||||
} else {
|
||||
imageName = imageNameAndTagValue.substring(0, colonIdx);
|
||||
imageTags.add(imageNameAndTagValue.substring(colonIdx + 1));
|
||||
}
|
||||
|
||||
Xpp3Dom tagsNode = toNode.getChild("tags");
|
||||
Xpp3Dom[] tagNodes = tagsNode == null ? new Xpp3Dom[0] : tagsNode.getChildren("tag");
|
||||
Arrays.stream(tagNodes).map(Xpp3Dom::getValue).forEach(imageTags::add);
|
||||
|
||||
if (imageTags.isEmpty()) {
|
||||
// default value
|
||||
imageTags.add(executionEvent.getProject().getVersion());
|
||||
}
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_NAME, imageName);
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_TAGS, imageTags);
|
||||
|
||||
// REGISTRY URL
|
||||
String registryHostname =
|
||||
imageName.indexOf('/') == -1 ? "docker.io" : imageName.substring(0, imageName.indexOf('/'));
|
||||
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_REGISTRY_URL,
|
||||
"https://" + registryHostname);
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_URL, "https://" + registryHostname);
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_METHOD, "POST");
|
||||
// Note: setting the "peer.service" helps visualization on Jaeger but
|
||||
// may not fully comply with the OTel "peer.service" spec as we don't know if the remote
|
||||
// service will be instrumented and what it "service.name" would be
|
||||
spanBuilder.setAttribute(SemanticAttributes.PEER_SERVICE, registryHostname);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Note: Later, we may prefer to have one span per actual upload than a generic span. We could
|
||||
* achieve this instrumenting the <a
|
||||
* href="https://projects.eclipse.org/projects/technology.aether">Aether library</a>
|
||||
*/
|
||||
final class MavenDeployHandler implements MojoGoalExecutionHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MavenDeployHandler.class);
|
||||
|
||||
@Override
|
||||
public void enrichSpan(SpanBuilder spanBuilder, ExecutionEvent execution) {
|
||||
spanBuilder.setSpanKind(SpanKind.CLIENT);
|
||||
|
||||
MavenProject project = execution.getProject();
|
||||
ArtifactRepository optRepository = project.getDistributionManagementArtifactRepository();
|
||||
|
||||
if (optRepository == null) {
|
||||
return;
|
||||
}
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_REPOSITORY_ID, optRepository.getId());
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_REPOSITORY_URL, optRepository.getUrl());
|
||||
|
||||
String artifactRepositoryUrl = optRepository.getUrl();
|
||||
if (artifactRepositoryUrl != null
|
||||
&& (artifactRepositoryUrl.startsWith("https://")
|
||||
|| artifactRepositoryUrl.startsWith("http://"))) {
|
||||
try {
|
||||
// Note: setting the "peer.service" helps visualization on Jaeger but
|
||||
// may not fully comply with the OTel "peer.service" spec as we don't know if the remote
|
||||
// service will be instrumented and what it "service.name" would be
|
||||
spanBuilder.setAttribute(
|
||||
SemanticAttributes.PEER_SERVICE, new URL(artifactRepositoryUrl).getHost());
|
||||
} catch (MalformedURLException e) {
|
||||
logger.debug("Ignore exception parsing artifact repository URL", e);
|
||||
}
|
||||
Artifact artifact = project.getArtifact();
|
||||
String artifactRootUrl = artifactRepositoryUrl;
|
||||
if (!artifactRootUrl.endsWith("/")) {
|
||||
artifactRootUrl += '/';
|
||||
}
|
||||
artifactRootUrl +=
|
||||
artifact.getGroupId().replace('.', '/')
|
||||
+ '/'
|
||||
+ artifact.getArtifactId()
|
||||
+ '/'
|
||||
+ artifact.getVersion();
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_URL, artifactRootUrl);
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_METHOD, "POST");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MavenGoal> getSupportedGoals() {
|
||||
return Collections.singletonList(
|
||||
MavenGoal.create("org.apache.maven.plugins", "maven-deploy-plugin", "deploy"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import java.util.List;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
|
||||
public interface MojoGoalExecutionHandler {
|
||||
|
||||
default void enrichSpan(SpanBuilder spanBuilder, ExecutionEvent executionEvent) {}
|
||||
|
||||
List<MavenGoal> getSupportedGoals();
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MojoGoalExecutionHandlerConfiguration {
|
||||
|
||||
public static Map<MavenGoal, MojoGoalExecutionHandler> loadMojoGoalExecutionHandler(
|
||||
ClassLoader classLoader) {
|
||||
|
||||
// built-in handlers
|
||||
List<MojoGoalExecutionHandler> builtInHandlers =
|
||||
Arrays.asList(
|
||||
new GoogleJibBuildHandler(),
|
||||
new MavenDeployHandler(),
|
||||
new SnykMonitorHandler(),
|
||||
new SnykTestHandler(),
|
||||
new SpringBootBuildImageHandler());
|
||||
|
||||
List<MojoGoalExecutionHandler> spiHandlers = new ArrayList();
|
||||
// Must use the classloader of the class rather the default ThreadContextClassloader to prevent
|
||||
// java.util.ServiceConfigurationError:
|
||||
// io.opentelemetry.maven.handler.MojoGoalExecutionHandler:
|
||||
// io.opentelemetry.maven.handler.SpringBootBuildImageHandler not a subtype
|
||||
ServiceLoader.load(MojoGoalExecutionHandler.class, classLoader)
|
||||
.forEach(handler -> spiHandlers.add(handler));
|
||||
|
||||
Map<MavenGoal, MojoGoalExecutionHandler> mojoGoalExecutionHandlers = new HashMap<>();
|
||||
|
||||
Stream.concat(builtInHandlers.stream(), spiHandlers.stream())
|
||||
.forEach(
|
||||
handler ->
|
||||
handler
|
||||
.getSupportedGoals()
|
||||
.forEach(
|
||||
goal -> {
|
||||
MojoGoalExecutionHandler previousHandler =
|
||||
mojoGoalExecutionHandlers.put(goal, handler);
|
||||
if (previousHandler != null) {
|
||||
throw new IllegalStateException(
|
||||
"More than one handler found for maven goal "
|
||||
+ goal
|
||||
+ ": "
|
||||
+ previousHandler
|
||||
+ ", "
|
||||
+ handler);
|
||||
}
|
||||
}));
|
||||
return mojoGoalExecutionHandlers;
|
||||
}
|
||||
|
||||
private MojoGoalExecutionHandlerConfiguration() {}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
|
||||
/** See https://github.com/snyk/snyk-maven-plugin */
|
||||
final class SnykMonitorHandler implements MojoGoalExecutionHandler {
|
||||
|
||||
/**
|
||||
* Snyk command "reversed engineered" invoking the Snyk CLI on a Maven project with the `-d` debug
|
||||
* flag `snyk -d monitor`. See <a href="https://snyk.io/blog/snyk-cli-cheat-sheet/">Snyk CLI Cheat
|
||||
* Sheet</a>
|
||||
*/
|
||||
@Override
|
||||
public void enrichSpan(SpanBuilder spanBuilder, ExecutionEvent executionEvent) {
|
||||
spanBuilder.setSpanKind(SpanKind.CLIENT);
|
||||
spanBuilder.setAttribute(SemanticAttributes.PEER_SERVICE, "snyk.io");
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_URL, "https://snyk.io/api/v1/monitor/maven");
|
||||
spanBuilder.setAttribute(SemanticAttributes.RPC_METHOD, "monitor");
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_METHOD, "POST");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MavenGoal> getSupportedGoals() {
|
||||
return Collections.singletonList(MavenGoal.create("io.snyk", "snyk-maven-plugin", "monitor"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
|
||||
/** See https://github.com/snyk/snyk-maven-plugin */
|
||||
final class SnykTestHandler implements MojoGoalExecutionHandler {
|
||||
|
||||
/**
|
||||
* Snyk command "reversed engineered" invoking the Snyk CLI on a Maven project with the `-d` debug
|
||||
* flag `snyk -d test`. See <a href="https://snyk.io/blog/snyk-cli-cheat-sheet/">Snyk CLI Cheat
|
||||
* Sheet</a>
|
||||
*/
|
||||
@Override
|
||||
public void enrichSpan(SpanBuilder spanBuilder, ExecutionEvent executionEvent) {
|
||||
spanBuilder.setSpanKind(SpanKind.CLIENT);
|
||||
spanBuilder.setAttribute(SemanticAttributes.PEER_SERVICE, "snyk.io");
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_URL, "https://snyk.io/api/v1/test-dep-graph");
|
||||
spanBuilder.setAttribute(SemanticAttributes.RPC_METHOD, "test");
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_METHOD, "POST");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MavenGoal> getSupportedGoals() {
|
||||
return Collections.singletonList(MavenGoal.create("io.snyk", "snyk-maven-plugin", "test"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* See
|
||||
*
|
||||
* <ul>
|
||||
* <li><a
|
||||
* href="https://docs.spring.io/spring-boot/docs/2.6.1/maven-plugin/reference/htmlsingle/">Spring
|
||||
* Boot Maven Plugin</a>
|
||||
* <li><a
|
||||
* href="https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin">GitHub
|
||||
* : spring-boot/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/</a>
|
||||
* </ul>
|
||||
*/
|
||||
final class SpringBootBuildImageHandler implements MojoGoalExecutionHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpringBootBuildImageHandler.class);
|
||||
|
||||
@Override
|
||||
public List<MavenGoal> getSupportedGoals() {
|
||||
return Collections.singletonList(
|
||||
MavenGoal.create("org.springframework.boot", "spring-boot-maven-plugin", "build-image"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enrichSpan(SpanBuilder spanBuilder, ExecutionEvent executionEvent) {
|
||||
|
||||
spanBuilder.setSpanKind(SpanKind.CLIENT);
|
||||
|
||||
Xpp3Dom pluginNode = executionEvent.getMojoExecution().getConfiguration();
|
||||
|
||||
String imageNameAndTag = null;
|
||||
if (pluginNode != null) {
|
||||
Xpp3Dom imageNode = pluginNode.getChild("image");
|
||||
if (imageNode != null) {
|
||||
Xpp3Dom nameNode = imageNode.getChild("name");
|
||||
if (nameNode != null) {
|
||||
imageNameAndTag = nameNode.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String imageName;
|
||||
String imageTag;
|
||||
if (imageNameAndTag == null) {
|
||||
// default image name docker.io/library/${project.artifactId}:${project.version}
|
||||
// see
|
||||
// https://docs.spring.io/spring-boot/docs/2.6.1/maven-plugin/reference/htmlsingle/#build-image.customization
|
||||
imageName = "docker.io/library/" + executionEvent.getProject().getArtifactId();
|
||||
imageTag = executionEvent.getProject().getVersion();
|
||||
} else {
|
||||
int colonIdx = imageNameAndTag.indexOf(':');
|
||||
if (colonIdx == -1) {
|
||||
imageName = imageNameAndTag;
|
||||
imageTag = "latest";
|
||||
} else {
|
||||
imageTag = imageNameAndTag.substring(colonIdx + 1);
|
||||
imageName = imageNameAndTag.substring(0, colonIdx);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO handle use cases when additional additional `tags` are provided
|
||||
// cyrille didn't understand from the Spring docs how to define multiple tags in the plugin cfg
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_NAME, imageName);
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_TAGS,
|
||||
Collections.singletonList(imageTag));
|
||||
|
||||
Xpp3Dom publishNode = pluginNode == null ? null : pluginNode.getChild("publish");
|
||||
if (publishNode != null && Boolean.parseBoolean(publishNode.getValue())) {
|
||||
Xpp3Dom dockerNode = pluginNode.getChild("docker");
|
||||
Xpp3Dom registryNode = dockerNode == null ? null : dockerNode.getChild("publishRegistry");
|
||||
|
||||
if (registryNode != null) {
|
||||
Xpp3Dom registryUrlNode = registryNode.getChild("url");
|
||||
String registryUrl = registryUrlNode == null ? null : registryUrlNode.getValue();
|
||||
|
||||
// REGISTRY URL
|
||||
if (registryUrl != null
|
||||
&& (registryUrl.startsWith("http://") || registryUrl.startsWith("https://"))) {
|
||||
spanBuilder.setAttribute(
|
||||
MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_REGISTRY_URL, registryUrl);
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_URL, registryUrl);
|
||||
spanBuilder.setAttribute(SemanticAttributes.HTTP_METHOD, "POST");
|
||||
try {
|
||||
// Note: setting the "peer.service" helps visualization on Jaeger but
|
||||
// may not fully comply with the OTel "peer.service" spec as we don't know if the remote
|
||||
// service will be instrumented and what it "service.name" would be
|
||||
spanBuilder.setAttribute(
|
||||
SemanticAttributes.PEER_SERVICE, new URL(registryUrl).getHost());
|
||||
} catch (MalformedURLException e) {
|
||||
logger.debug("Ignore exception parsing container registry URL", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,9 +5,12 @@
|
|||
|
||||
package io.opentelemetry.maven.semconv;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Semantic attributes for Maven executions.
|
||||
|
@ -15,22 +18,37 @@ import io.opentelemetry.api.common.AttributeKey;
|
|||
* @see io.opentelemetry.api.common.Attributes
|
||||
* @see io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||
*/
|
||||
public final class MavenOtelSemanticAttributes {
|
||||
public class MavenOtelSemanticAttributes {
|
||||
|
||||
/** See {@link ResourceAttributes#CONTAINER_IMAGE_NAME} */
|
||||
public static final AttributeKey<String> MAVEN_BUILD_CONTAINER_IMAGE_NAME =
|
||||
stringKey("maven.build.container.image.name");
|
||||
/** See {@link ResourceAttributes#CONTAINER_IMAGE_TAG} */
|
||||
public static final AttributeKey<List<String>> MAVEN_BUILD_CONTAINER_IMAGE_TAGS =
|
||||
stringArrayKey("maven.build.container.image.tags");
|
||||
|
||||
public static final AttributeKey<String> MAVEN_BUILD_CONTAINER_REGISTRY_URL =
|
||||
stringKey("maven.build.container.registry.url");
|
||||
public static final AttributeKey<String> MAVEN_BUILD_REPOSITORY_ID =
|
||||
stringKey("maven.build.repository.id");
|
||||
public static final AttributeKey<String> MAVEN_BUILD_REPOSITORY_URL =
|
||||
stringKey("maven.build.repository.url");
|
||||
public static final AttributeKey<String> MAVEN_EXECUTION_GOAL = stringKey("maven.execution.goal");
|
||||
|
||||
public static final AttributeKey<String> MAVEN_EXECUTION_ID = stringKey("maven.execution.id");
|
||||
public static final AttributeKey<String> MAVEN_EXECUTION_LIFECYCLE_PHASE =
|
||||
stringKey("maven.execution.lifecyclePhase");
|
||||
public static final AttributeKey<String> MAVEN_PLUGIN_ARTIFACT_ID =
|
||||
stringKey("maven.plugin.artifactId");
|
||||
public static final AttributeKey<String> MAVEN_PLUGIN_GROUP_ID =
|
||||
stringKey("maven.plugin.groupId");
|
||||
public static final AttributeKey<String> MAVEN_PLUGIN_VERSION = stringKey("maven.plugin.version");
|
||||
public static final AttributeKey<String> MAVEN_PROJECT_ARTIFACT_ID =
|
||||
stringKey("maven.project.artifactId");
|
||||
public static final AttributeKey<String> MAVEN_PROJECT_GROUP_ID =
|
||||
stringKey("maven.project.groupId");
|
||||
public static final AttributeKey<String> MAVEN_PROJECT_VERSION =
|
||||
stringKey("maven.project.version");
|
||||
public static final AttributeKey<String> MAVEN_PLUGIN_ARTIFACT_ID =
|
||||
stringKey("maven.plugin.artifactId");
|
||||
public static final AttributeKey<String> MAVEN_PLUGIN_GROUP_ID =
|
||||
stringKey("maven.plugin.groupId");
|
||||
public static final AttributeKey<String> MAVEN_PLUGIN_VERSION = stringKey("maven.plugin.version");
|
||||
public static final AttributeKey<String> MAVEN_EXECUTION_GOAL = stringKey("maven.execution.goal");
|
||||
public static final AttributeKey<String> MAVEN_EXECUTION_LIFECYCLE_PHASE =
|
||||
stringKey("maven.execution.lifecyclePhase");
|
||||
|
||||
public static final String SERVICE_NAME_VALUE = "maven";
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -9,20 +9,18 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class OtelExecutionListenerTest {
|
||||
public class MavenUtilsTests {
|
||||
|
||||
@Test
|
||||
public void getPluginArtifactIdShortName_builtinPluginName() {
|
||||
OtelExecutionListener otelEventSpy = new OtelExecutionListener();
|
||||
String actual = otelEventSpy.getPluginArtifactIdShortName("maven-clean-plugin");
|
||||
String actual = MavenUtils.getPluginArtifactIdShortName("maven-clean-plugin");
|
||||
String expected = "clean";
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPluginArtifactIdShortName_thirdPartyPluginName() {
|
||||
OtelExecutionListener otelEventSpy = new OtelExecutionListener();
|
||||
String actual = otelEventSpy.getPluginArtifactIdShortName("spotbugs-maven-plugin");
|
||||
String actual = MavenUtils.getPluginArtifactIdShortName("spotbugs-maven-plugin");
|
||||
String expected = "spotbugs";
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import io.opentelemetry.maven.OtelExecutionListener;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MojoGoalExecutionHandlerConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void mojoGoalExecutionHandlers() {
|
||||
|
||||
final Map<MavenGoal, MojoGoalExecutionHandler> actual =
|
||||
MojoGoalExecutionHandlerConfiguration.loadMojoGoalExecutionHandler(
|
||||
OtelExecutionListener.class.getClassLoader());
|
||||
assertThat(actual.size()).isEqualTo(5);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven.handler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.maven.MavenGoal;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import io.opentelemetry.sdk.trace.ReadableSpan;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import org.apache.maven.artifact.InvalidRepositoryException;
|
||||
import org.apache.maven.bridge.MavenRepositorySystem;
|
||||
import org.apache.maven.execution.DefaultMavenExecutionRequest;
|
||||
import org.apache.maven.execution.DefaultMavenExecutionResult;
|
||||
import org.apache.maven.execution.ExecutionEvent;
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.apache.maven.model.DistributionManagement;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
|
||||
import org.apache.maven.plugin.MojoExecution;
|
||||
import org.apache.maven.plugin.descriptor.MojoDescriptor;
|
||||
import org.apache.maven.plugin.descriptor.PluginDescriptor;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.project.artifact.ProjectArtifact;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* TODO Find a better solution to instantiate a MavenProject and a MojoExecutionEvent. See
|
||||
* https://github.com/takari/takari-lifecycle/blob/master/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/PluginDescriptorMojoTest.java
|
||||
*/
|
||||
@SuppressWarnings("DeduplicateConstants")
|
||||
public class MojoGoalExecutionHandlerTest {
|
||||
|
||||
@Test
|
||||
public void testMavenDeploy() throws Exception {
|
||||
|
||||
String pomXmlPath = "projects/jar/pom.xml";
|
||||
String mojoGroupId = "org.apache.maven.plugins";
|
||||
String mojoArtifactId = "maven-deploy-plugin";
|
||||
String mojoVersion = "2.8.2";
|
||||
String mojoGoal = "deploy";
|
||||
|
||||
MavenProject project = newMavenProject(pomXmlPath);
|
||||
ExecutionEvent executionEvent =
|
||||
newMojoStartedExecutionEvent(project, mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal);
|
||||
|
||||
MavenDeployHandler mavenDeployHandler = new MavenDeployHandler();
|
||||
|
||||
List<MavenGoal> supportedGoals = mavenDeployHandler.getSupportedGoals();
|
||||
assertThat(supportedGoals)
|
||||
.isEqualTo(
|
||||
Collections.singletonList(MavenGoal.create(mojoGroupId, mojoArtifactId, mojoGoal)));
|
||||
|
||||
try (SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build()) {
|
||||
SpanBuilder spanBuilder =
|
||||
sdkTracerProvider.tracerBuilder("test-tracer").build().spanBuilder("deploy");
|
||||
|
||||
mavenDeployHandler.enrichSpan(spanBuilder, executionEvent);
|
||||
ReadableSpan span = (ReadableSpan) spanBuilder.startSpan();
|
||||
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_REPOSITORY_ID))
|
||||
.isEqualTo("snapshots");
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_METHOD)).isEqualTo("POST");
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_URL))
|
||||
.isEqualTo(
|
||||
"https://maven.example.com/repository/maven-snapshots/io/opentelemetry/contrib/maven/test-jar/1.0-SNAPSHOT");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_REPOSITORY_URL))
|
||||
.isEqualTo("https://maven.example.com/repository/maven-snapshots/");
|
||||
assertThat(span.getAttribute(SemanticAttributes.PEER_SERVICE)).isEqualTo("maven.example.com");
|
||||
|
||||
assertThat(span.getKind()).isEqualTo(SpanKind.CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringBootBuildImage_springboot_1() throws Exception {
|
||||
|
||||
String pomXmlPath = "projects/springboot_1/pom.xml";
|
||||
String mojoGroupId = "org.springframework.boot";
|
||||
String mojoArtifactId = "spring-boot-maven-plugin";
|
||||
String mojoVersion = "2.5.6";
|
||||
String mojoGoal = "build-image";
|
||||
|
||||
MavenProject project = newMavenProject(pomXmlPath);
|
||||
ExecutionEvent executionEvent =
|
||||
newMojoStartedExecutionEvent(project, mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal);
|
||||
|
||||
SpringBootBuildImageHandler buildImageHandler = new SpringBootBuildImageHandler();
|
||||
|
||||
List<MavenGoal> supportedGoals = buildImageHandler.getSupportedGoals();
|
||||
assertThat(supportedGoals)
|
||||
.isEqualTo(
|
||||
Collections.singletonList(MavenGoal.create(mojoGroupId, mojoArtifactId, mojoGoal)));
|
||||
|
||||
try (SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build()) {
|
||||
SpanBuilder spanBuilder =
|
||||
sdkTracerProvider
|
||||
.tracerBuilder("test-tracer")
|
||||
.build()
|
||||
.spanBuilder("spring-boot:build-image");
|
||||
|
||||
buildImageHandler.enrichSpan(spanBuilder, executionEvent);
|
||||
ReadableSpan span = (ReadableSpan) spanBuilder.startSpan();
|
||||
|
||||
// TODO improve the Maven test harness that interpolates the maven properties like
|
||||
// ${project.artifactId}
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_NAME))
|
||||
.isEqualTo("docker.io/john/${project.artifactId}");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_TAGS))
|
||||
.isEqualTo(Collections.singletonList("latest"));
|
||||
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_URL)).isEqualTo("https://docker.io");
|
||||
assertThat(span.getAttribute(SemanticAttributes.PEER_SERVICE)).isEqualTo("docker.io");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_REGISTRY_URL))
|
||||
.isEqualTo("https://docker.io");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringBootBuildImage_springboot_2() throws Exception {
|
||||
|
||||
String pomXmlPath = "projects/springboot_2/pom.xml";
|
||||
String mojoGroupId = "org.springframework.boot";
|
||||
String mojoArtifactId = "spring-boot-maven-plugin";
|
||||
String mojoVersion = "2.5.6";
|
||||
String mojoGoal = "build-image";
|
||||
|
||||
MavenProject project = newMavenProject(pomXmlPath);
|
||||
ExecutionEvent executionEvent =
|
||||
newMojoStartedExecutionEvent(project, mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal);
|
||||
|
||||
SpringBootBuildImageHandler buildImageHandler = new SpringBootBuildImageHandler();
|
||||
|
||||
List<MavenGoal> supportedGoals = buildImageHandler.getSupportedGoals();
|
||||
assertThat(supportedGoals)
|
||||
.isEqualTo(
|
||||
Collections.singletonList(MavenGoal.create(mojoGroupId, mojoArtifactId, mojoGoal)));
|
||||
|
||||
try (SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build()) {
|
||||
SpanBuilder spanBuilder =
|
||||
sdkTracerProvider
|
||||
.tracerBuilder("test-tracer")
|
||||
.build()
|
||||
.spanBuilder("spring-boot:build-image");
|
||||
|
||||
buildImageHandler.enrichSpan(spanBuilder, executionEvent);
|
||||
ReadableSpan span = (ReadableSpan) spanBuilder.startSpan();
|
||||
|
||||
// TODO improve the Maven test harness that interpolates the maven properties like
|
||||
// ${project.artifactId}
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_NAME))
|
||||
.isEqualTo("docker.io/john/${project.artifactId}");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_TAGS))
|
||||
.isEqualTo(Collections.singletonList("${project.version}"));
|
||||
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_URL)).isEqualTo("https://docker.io");
|
||||
assertThat(span.getAttribute(SemanticAttributes.PEER_SERVICE)).isEqualTo("docker.io");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_REGISTRY_URL))
|
||||
.isEqualTo("https://docker.io");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoogleJibBuild_jib_1() throws Exception {
|
||||
|
||||
String pomXmlPath = "projects/jib_1/pom.xml";
|
||||
String mojoGroupId = "com.google.cloud.tools";
|
||||
String mojoArtifactId = "jib-maven-plugin";
|
||||
String mojoVersion = "3.1.4";
|
||||
String mojoGoal = "build";
|
||||
|
||||
MavenProject project = newMavenProject(pomXmlPath);
|
||||
ExecutionEvent executionEvent =
|
||||
newMojoStartedExecutionEvent(project, mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal);
|
||||
|
||||
GoogleJibBuildHandler buildImageHandler = new GoogleJibBuildHandler();
|
||||
|
||||
List<MavenGoal> supportedGoals = buildImageHandler.getSupportedGoals();
|
||||
assertThat(supportedGoals)
|
||||
.isEqualTo(
|
||||
Collections.singletonList(MavenGoal.create(mojoGroupId, mojoArtifactId, mojoGoal)));
|
||||
|
||||
try (SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build()) {
|
||||
SpanBuilder spanBuilder =
|
||||
sdkTracerProvider.tracerBuilder("test-tracer").build().spanBuilder("jib:build");
|
||||
|
||||
buildImageHandler.enrichSpan(spanBuilder, executionEvent);
|
||||
ReadableSpan span = (ReadableSpan) spanBuilder.startSpan();
|
||||
|
||||
// TODO improve the Maven test harness that interpolates the maven properties like
|
||||
// ${project.artifactId}
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_NAME))
|
||||
.isEqualTo("docker.io/john/${project.artifactId}");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_TAGS))
|
||||
.isEqualTo(Arrays.asList("latest", "${project.version}"));
|
||||
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_URL)).isEqualTo("https://docker.io");
|
||||
assertThat(span.getAttribute(SemanticAttributes.PEER_SERVICE)).isEqualTo("docker.io");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_REGISTRY_URL))
|
||||
.isEqualTo("https://docker.io");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoogleJibBuild_jib_2() throws Exception {
|
||||
|
||||
String pomXmlPath = "projects/jib_2/pom.xml";
|
||||
String mojoGroupId = "com.google.cloud.tools";
|
||||
String mojoArtifactId = "jib-maven-plugin";
|
||||
String mojoVersion = "3.1.4";
|
||||
String mojoGoal = "build";
|
||||
|
||||
MavenProject project = newMavenProject(pomXmlPath);
|
||||
ExecutionEvent executionEvent =
|
||||
newMojoStartedExecutionEvent(project, mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal);
|
||||
|
||||
GoogleJibBuildHandler buildImageHandler = new GoogleJibBuildHandler();
|
||||
|
||||
List<MavenGoal> supportedGoals = buildImageHandler.getSupportedGoals();
|
||||
assertThat(supportedGoals)
|
||||
.isEqualTo(
|
||||
Collections.singletonList(MavenGoal.create(mojoGroupId, mojoArtifactId, mojoGoal)));
|
||||
|
||||
try (SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build()) {
|
||||
SpanBuilder spanBuilder =
|
||||
sdkTracerProvider.tracerBuilder("test-tracer").build().spanBuilder("jib:build");
|
||||
|
||||
buildImageHandler.enrichSpan(spanBuilder, executionEvent);
|
||||
ReadableSpan span = (ReadableSpan) spanBuilder.startSpan();
|
||||
|
||||
// TODO improve the Maven test harness that interpolates the maven properties like
|
||||
// ${project.artifactId}
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_NAME))
|
||||
.isEqualTo("gcr.io/my-gcp-project/my-app");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_IMAGE_TAGS))
|
||||
.isEqualTo(Collections.singletonList("1.0-SNAPSHOT"));
|
||||
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_URL)).isEqualTo("https://gcr.io");
|
||||
assertThat(span.getAttribute(SemanticAttributes.PEER_SERVICE)).isEqualTo("gcr.io");
|
||||
assertThat(span.getAttribute(MavenOtelSemanticAttributes.MAVEN_BUILD_CONTAINER_REGISTRY_URL))
|
||||
.isEqualTo("https://gcr.io");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnykTest_snyk_1() throws Exception {
|
||||
|
||||
String pomXmlPath = "projects/snyk_1/pom.xml";
|
||||
String mojoGroupId = "io.snyk";
|
||||
String mojoArtifactId = "snyk-maven-plugin";
|
||||
String mojoVersion = "2.0.0";
|
||||
String mojoGoal = "test";
|
||||
|
||||
MavenProject project = newMavenProject(pomXmlPath);
|
||||
ExecutionEvent executionEvent =
|
||||
newMojoStartedExecutionEvent(project, mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal);
|
||||
|
||||
SnykTestHandler snykTestHandler = new SnykTestHandler();
|
||||
|
||||
List<MavenGoal> supportedGoals = snykTestHandler.getSupportedGoals();
|
||||
assertThat(supportedGoals)
|
||||
.isEqualTo(
|
||||
Collections.singletonList(MavenGoal.create(mojoGroupId, mojoArtifactId, mojoGoal)));
|
||||
|
||||
try (SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build()) {
|
||||
SpanBuilder spanBuilder =
|
||||
sdkTracerProvider.tracerBuilder("test-tracer").build().spanBuilder("snyk:test");
|
||||
|
||||
snykTestHandler.enrichSpan(spanBuilder, executionEvent);
|
||||
ReadableSpan span = (ReadableSpan) spanBuilder.startSpan();
|
||||
|
||||
assertThat(span.getKind()).isEqualTo(SpanKind.CLIENT);
|
||||
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_URL))
|
||||
.isEqualTo("https://snyk.io/api/v1/test-dep-graph");
|
||||
assertThat(span.getAttribute(SemanticAttributes.PEER_SERVICE)).isEqualTo("snyk.io");
|
||||
assertThat(span.getAttribute(SemanticAttributes.RPC_METHOD)).isEqualTo("test");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnykMonitor_snyk_1() throws Exception {
|
||||
|
||||
String pomXmlPath = "projects/snyk_1/pom.xml";
|
||||
String mojoGroupId = "io.snyk";
|
||||
String mojoArtifactId = "snyk-maven-plugin";
|
||||
String mojoVersion = "2.0.0";
|
||||
String mojoGoal = "monitor";
|
||||
|
||||
MavenProject project = newMavenProject(pomXmlPath);
|
||||
ExecutionEvent executionEvent =
|
||||
newMojoStartedExecutionEvent(project, mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal);
|
||||
|
||||
SnykMonitorHandler snykTestHandler = new SnykMonitorHandler();
|
||||
|
||||
List<MavenGoal> supportedGoals = snykTestHandler.getSupportedGoals();
|
||||
assertThat(supportedGoals)
|
||||
.isEqualTo(
|
||||
Collections.singletonList(MavenGoal.create(mojoGroupId, mojoArtifactId, mojoGoal)));
|
||||
|
||||
try (SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build()) {
|
||||
SpanBuilder spanBuilder =
|
||||
sdkTracerProvider.tracerBuilder("test-tracer").build().spanBuilder("snyk:monitor");
|
||||
|
||||
snykTestHandler.enrichSpan(spanBuilder, executionEvent);
|
||||
ReadableSpan span = (ReadableSpan) spanBuilder.startSpan();
|
||||
|
||||
assertThat(span.getKind()).isEqualTo(SpanKind.CLIENT);
|
||||
|
||||
assertThat(span.getAttribute(SemanticAttributes.HTTP_URL))
|
||||
.isEqualTo("https://snyk.io/api/v1/monitor/maven");
|
||||
assertThat(span.getAttribute(SemanticAttributes.PEER_SERVICE)).isEqualTo("snyk.io");
|
||||
assertThat(span.getAttribute(SemanticAttributes.RPC_METHOD)).isEqualTo("monitor");
|
||||
}
|
||||
}
|
||||
|
||||
ExecutionEvent newMojoStartedExecutionEvent(
|
||||
MavenProject project,
|
||||
String mojoGroupId,
|
||||
String mojoArtifactId,
|
||||
String mojoVersion,
|
||||
String mojoGoal) {
|
||||
|
||||
MojoExecution mojoExecution =
|
||||
newMojoExecution(mojoGroupId, mojoArtifactId, mojoVersion, mojoGoal, project);
|
||||
|
||||
MavenSession session =
|
||||
new MavenSession(
|
||||
null, null, new DefaultMavenExecutionRequest(), new DefaultMavenExecutionResult());
|
||||
session.setCurrentProject(project);
|
||||
|
||||
return new MockExecutionEvent(ExecutionEvent.Type.MojoStarted, project, session, mojoExecution);
|
||||
}
|
||||
|
||||
MavenProject newMavenProject(String pomXmlPath)
|
||||
throws IOException, XmlPullParserException, InvalidRepositoryException {
|
||||
InputStream pomXmlAsStream =
|
||||
Thread.currentThread().getContextClassLoader().getResourceAsStream(pomXmlPath);
|
||||
|
||||
MavenXpp3Reader mavenXpp3Reader = new MavenXpp3Reader();
|
||||
Model model = mavenXpp3Reader.read(pomXmlAsStream);
|
||||
|
||||
MavenProject project = new MavenProject(model);
|
||||
project.setArtifact(new ProjectArtifact(project));
|
||||
|
||||
DistributionManagement distributionManagement = model.getDistributionManagement();
|
||||
if (distributionManagement != null) {
|
||||
project.setSnapshotArtifactRepository(
|
||||
MavenRepositorySystem.buildArtifactRepository(
|
||||
distributionManagement.getSnapshotRepository()));
|
||||
project.setReleaseArtifactRepository(
|
||||
MavenRepositorySystem.buildArtifactRepository(distributionManagement.getRepository()));
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
MojoExecution newMojoExecution(
|
||||
String groupId, String artifactId, String version, String goal, MavenProject project) {
|
||||
PluginDescriptor pluginDescriptor = new PluginDescriptor();
|
||||
pluginDescriptor.setGroupId(groupId);
|
||||
pluginDescriptor.setArtifactId(artifactId);
|
||||
pluginDescriptor.setVersion(version);
|
||||
MojoDescriptor mojoDescriptor = new MojoDescriptor();
|
||||
mojoDescriptor.setGoal(goal);
|
||||
mojoDescriptor.setPluginDescriptor(pluginDescriptor);
|
||||
MojoExecution mojoExecution = new MojoExecution(mojoDescriptor);
|
||||
|
||||
Plugin plugin = new Plugin();
|
||||
plugin.setGroupId(groupId);
|
||||
plugin.setArtifactId(artifactId);
|
||||
plugin.setVersion(version);
|
||||
|
||||
final Plugin configuredPlugin = project.getPlugin(plugin.getKey());
|
||||
if (configuredPlugin != null) {
|
||||
mojoExecution.setConfiguration((Xpp3Dom) configuredPlugin.getConfiguration());
|
||||
}
|
||||
return mojoExecution;
|
||||
}
|
||||
|
||||
static class MockExecutionEvent implements ExecutionEvent {
|
||||
ExecutionEvent.Type type;
|
||||
MavenProject project;
|
||||
MavenSession session;
|
||||
MojoExecution mojoExecution;
|
||||
|
||||
public MockExecutionEvent(
|
||||
ExecutionEvent.Type type,
|
||||
MavenProject project,
|
||||
MavenSession session,
|
||||
MojoExecution mojoExecution) {
|
||||
this.type = type;
|
||||
this.project = project;
|
||||
this.session = session;
|
||||
this.mojoExecution = mojoExecution;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionEvent.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenSession getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenProject getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MojoExecution getMojoExecution() {
|
||||
return mojoExecution;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Exception getException() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.opentelemetry.contrib.maven</groupId>
|
||||
<artifactId>test-jar</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>releases</id>
|
||||
<url>https://maven.example.com/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>snapshots</id>
|
||||
<url>https://maven.example.com/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</project>
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.opentelemetry.contrib.maven</groupId>
|
||||
<artifactId>test-jib-1</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.google.cloud.tools</groupId>
|
||||
<artifactId>jib-maven-plugin</artifactId>
|
||||
<version>3.1.4</version>
|
||||
<configuration>
|
||||
<to>
|
||||
<image>docker.io/john/${project.artifactId}:latest</image>
|
||||
<tags>
|
||||
<tag>${project.version}</tag>
|
||||
</tags>
|
||||
<auth>
|
||||
<username>john</username>
|
||||
<password>doe</password>
|
||||
</auth>
|
||||
</to>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>releases</id>
|
||||
<url>https://maven.example.com/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>snapshots</id>
|
||||
<url>https://maven.example.com/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</project>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.opentelemetry.contrib.maven</groupId>
|
||||
<artifactId>test-jib-2</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.google.cloud.tools</groupId>
|
||||
<artifactId>jib-maven-plugin</artifactId>
|
||||
<version>3.1.4</version>
|
||||
<configuration>
|
||||
<to>
|
||||
<image>gcr.io/my-gcp-project/my-app</image>
|
||||
<credHelper>gcr</credHelper>
|
||||
</to>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>releases</id>
|
||||
<url>https://maven.example.com/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>snapshots</id>
|
||||
<url>https://maven.example.com/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</project>
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.opentelemetry.contrib.maven</groupId>
|
||||
<artifactId>test-snyk-1</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.snyk</groupId>
|
||||
<artifactId>snyk-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<configuration>
|
||||
<apiToken>${snyk.token}</apiToken>
|
||||
<args>
|
||||
<arg>--all-projects</arg>
|
||||
</args>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>releases</id>
|
||||
<url>https://maven.example.com/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>snapshots</id>
|
||||
<url>https://maven.example.com/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</project>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.1</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>io.opentelemetry.contrib.maven.test</groupId>
|
||||
<artifactId>springboot-test-1</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>springboot-test</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<properties>
|
||||
<java.version>11</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<image>
|
||||
<name>docker.io/john/${project.artifactId}</name>
|
||||
</image>
|
||||
<publish>true</publish>
|
||||
<docker>
|
||||
<publishRegistry>
|
||||
<username>john</username>
|
||||
<password>xxxx</password>
|
||||
<url>https://docker.io</url>
|
||||
</publishRegistry>
|
||||
</docker>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.maven.test.springboot;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringbootTestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringbootTestApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.maven.test.springboot;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class SpringbootTestApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.1</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>io.opentelemetry.contrib.maven.test</groupId>
|
||||
<artifactId>springboot-test-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>springboot-test</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<properties>
|
||||
<java.version>11</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<image>
|
||||
<name>docker.io/john/${project.artifactId}:${project.version}</name>
|
||||
</image>
|
||||
<publish>true</publish>
|
||||
<docker>
|
||||
<publishRegistry>
|
||||
<username>john</username>
|
||||
<password>xxxx</password>
|
||||
<url>https://docker.io</url>
|
||||
</publishRegistry>
|
||||
</docker>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.maven.test.springboot;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringbootTestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringbootTestApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.maven.test.springboot;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class SpringbootTestApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {}
|
||||
}
|
Loading…
Reference in New Issue