Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect SDK dependency version mismatches #126

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/sentry-maven-plugin-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@
<skipSourceBundle>false</skipSourceBundle>
<skipAutoInstall>false</skipAutoInstall>
<skipTelemetry>false</skipTelemetry>
<skipValidateSdkDependencyVersions>false</skipValidateSdkDependencyVersions>
</configuration>
<executions>
<execution>
<goals>
<goal>uploadSourceBundle</goal>
<goal>reportDependencies</goal>
<goal>validateSdkDependencyVersions</goal>
</goals>
</execution>
</executions>
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/io/sentry/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.sentry;

import org.jetbrains.annotations.NotNull;

public class Constants {
public static final @NotNull String SENTRY_GROUP_ID = "io.sentry";
public static final @NotNull String SENTRY_SDK_ARTIFACT_ID = "sentry";
public static final @NotNull String SENTRY_PLUGIN_ARTIFACT_ID = "sentry-maven-plugin";
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.sentry;

import static io.sentry.autoinstall.Constants.SENTRY_GROUP_ID;
import static io.sentry.Constants.SENTRY_GROUP_ID;
import static io.sentry.autoinstall.graphql.Graphql22InstallStrategy.SENTRY_GRAPHQL_22_ID;
import static io.sentry.autoinstall.graphql.GraphqlInstallStrategy.SENTRY_GRAPHQL_ID;
import static io.sentry.autoinstall.jdbc.JdbcInstallStrategy.SENTRY_JDBC_ID;
Expand Down
129 changes: 129 additions & 0 deletions src/main/java/io/sentry/ValidateSdkDependencyVersionsMojo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package io.sentry;

import static io.sentry.Constants.SENTRY_GROUP_ID;
import static io.sentry.Constants.SENTRY_PLUGIN_ARTIFACT_ID;
import static io.sentry.Constants.SENTRY_SDK_ARTIFACT_ID;
import static io.sentry.config.PluginConfig.DEFAULT_SKIP_STRING;
import static io.sentry.config.PluginConfig.DEFAULT_SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS_STRING;

import io.sentry.telemetry.SentryTelemetryService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.DependencyResolutionException;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.artifact.Artifact;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Mojo(name = "validateSdkDependencyVersions", defaultPhase = LifecyclePhase.VALIDATE)
public class ValidateSdkDependencyVersionsMojo extends AbstractMojo {

@Parameter(defaultValue = DEFAULT_SKIP_STRING)
private boolean skip;

@Parameter(defaultValue = DEFAULT_SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS_STRING)
private boolean skipValidateSdkDependencyVersions;

private static final @NotNull Logger logger =
LoggerFactory.getLogger(ValidateSdkDependencyVersionsMojo.class);

private static final String ERROR_MESSAGE = "Detected a mismatch in Sentry dependency versions.";
private static final String RESOLUTION_MESSAGE =
"Please remove any dependencies in the "
+ SENTRY_GROUP_ID
+ " group from your `pom.xml`, or ensure that all of them have the same version.";
private static final String ESCAPE_HATCH_MESSAGE =
"You can disable this check by setting `<skipValidateSdkDependencyVersions>true</skipValidateSdkDependencyVersions>` in your configuration for "
+ SENTRY_GROUP_ID
+ ":"
+ SENTRY_PLUGIN_ARTIFACT_ID
+ ".";

@SuppressWarnings("NullAway")
@Parameter(defaultValue = "${project}", readonly = true)
private @NotNull MavenProject mavenProject;

@SuppressWarnings("NullAway")
@Parameter(defaultValue = "${session}", readonly = true)
private @NotNull MavenSession mavenSession;

@Inject protected @NotNull ArtifactResolver artifactResolver;

@Override
public void execute() throws MojoExecutionException {
if (skip || skipValidateSdkDependencyVersions) {
logger.info("Skipping Sentry SDK dependency versions validation.");
return;
}
logger.info("Validating Sentry SDK dependency versions.");
final @Nullable ISpan span =
SentryTelemetryService.getInstance().startTask("validateSdkDependencyVersions");

try {
validateSdkDependencyVersions();
} catch (MojoExecutionException e) {
throw e;
} catch (DependencyResolutionException e) {
SentryTelemetryService.getInstance().captureError(e, "validateSdkDependencyVersions");
throw new RuntimeException(e);
} catch (Throwable t) {
SentryTelemetryService.getInstance().captureError(t, "validateSdkDependencyVersions");
throw t;
} finally {
SentryTelemetryService.getInstance().endTask(span);
}
}

private void validateSdkDependencyVersions()
throws MojoExecutionException, DependencyResolutionException {

Map<String, List<Artifact>> versionToArtifacts = new HashMap<>();
Set<Artifact> dependencies =
new HashSet<>(artifactResolver.resolveArtifactsForProject(mavenProject, mavenSession));
for (Artifact artifact : dependencies) {
if (!artifact.getGroupId().equals(SENTRY_GROUP_ID)) {
continue;
}
if (artifact.getArtifactId().equals(SENTRY_SDK_ARTIFACT_ID)
|| artifact.getArtifactId().equals(SENTRY_PLUGIN_ARTIFACT_ID)) {
continue;
}
versionToArtifacts
.computeIfAbsent(artifact.getVersion(), v -> new ArrayList<>())
.add(artifact);
}

if (versionToArtifacts.size() > 1) {
StringBuilder exceptionMessage = new StringBuilder(ERROR_MESSAGE).append('\n');
versionToArtifacts.forEach(
(version, artifacts) ->
exceptionMessage.append(
String.format(
"Version %s required for: %s\n",
version,
artifacts.stream()
.map((artifact) -> artifact.getGroupId() + ":" + artifact.getArtifactId())
.collect(Collectors.joining(", ")))));
exceptionMessage.append(RESOLUTION_MESSAGE).append("\n\n");
exceptionMessage.append(ESCAPE_HATCH_MESSAGE);
logger.error("Found inconsistency in Sentry SDK dependency versions.");
throw new MojoExecutionException(exceptionMessage.toString());
}

logger.info("Sentry SDK dependency versions are all consistent.");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.sentry.autoinstall;

import static io.sentry.autoinstall.Constants.SENTRY_GROUP_ID;
import static io.sentry.Constants.SENTRY_GROUP_ID;

import io.sentry.semver.Version;
import java.util.List;
Expand Down
6 changes: 0 additions & 6 deletions src/main/java/io/sentry/autoinstall/Constants.java

This file was deleted.

8 changes: 4 additions & 4 deletions src/main/java/io/sentry/autoinstall/SentryInstaller.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.sentry.autoinstall;

import static io.sentry.autoinstall.Constants.SENTRY_ARTIFACT_ID;
import static io.sentry.autoinstall.Constants.SENTRY_GROUP_ID;
import static io.sentry.Constants.SENTRY_GROUP_ID;
import static io.sentry.Constants.SENTRY_SDK_ARTIFACT_ID;

import io.sentry.autoinstall.util.SdkVersionInfo;
import java.util.List;
Expand Down Expand Up @@ -32,7 +32,7 @@ public SentryInstaller(final @NotNull Logger logger) {
.filter(
(dep) ->
dep.getGroupId().equals(SENTRY_GROUP_ID)
&& dep.getArtifactId().equals(SENTRY_ARTIFACT_ID))
&& dep.getArtifactId().equals(SENTRY_SDK_ARTIFACT_ID))
.findFirst()
.orElse(null);

Expand All @@ -50,7 +50,7 @@ public SentryInstaller(final @NotNull Logger logger) {
logger.info("Installing Sentry with version " + sentryVersion);
final @NotNull Dependency newDep = new Dependency();
newDep.setGroupId(SENTRY_GROUP_ID);
newDep.setArtifactId(SENTRY_ARTIFACT_ID);
newDep.setArtifactId(SENTRY_SDK_ARTIFACT_ID);
newDep.setVersion(sentryVersion);

dependencyList.add(newDep);
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/io/sentry/config/ConfigParser.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.sentry.config;

import static io.sentry.autoinstall.Constants.SENTRY_GROUP_ID;
import static io.sentry.Constants.SENTRY_GROUP_ID;
import static io.sentry.Constants.SENTRY_PLUGIN_ARTIFACT_ID;

import org.apache.maven.model.Plugin;
import org.apache.maven.project.MavenProject;
Expand All @@ -10,12 +11,13 @@

public class ConfigParser {

private static final @NotNull String SENTRY_PLUGIN_ARTIFACT = "sentry-maven-plugin";
private static final @NotNull String SKIP_ALL_FLAG = "skip";
private static final @NotNull String SKIP_AUTO_INSTALL_FLAG = "skipAutoInstall";
private static final @NotNull String SKIP_TELEMETRY_FLAG = "skipTelemetry";
private static final @NotNull String SKIP_REPORT_DEPENDENCIES_FLAG = "skipReportDependencies";
private static final @NotNull String SKIP_SOURCE_BUNDLE_FLAG = "skipSourceBundle";
private static final @NotNull String SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS_OPTION =
"skipValidateSdkDependencyVersions";
private static final @NotNull String DEBUG_SENTRY_CLI_FLAG = "debugSentryCli";
private static final @NotNull String DEBUG_FLAG = "debug";
private static final @NotNull String ORG_OPTION = "org";
Expand All @@ -30,7 +32,7 @@ public class ConfigParser {
.filter(
(plugin) ->
plugin.getGroupId().equals(SENTRY_GROUP_ID)
&& plugin.getArtifactId().equals(SENTRY_PLUGIN_ARTIFACT))
&& plugin.getArtifactId().equals(SENTRY_PLUGIN_ARTIFACT_ID))
.findFirst()
.orElse(null);

Expand Down Expand Up @@ -83,6 +85,11 @@ public class ConfigParser {
dom.getChild(AUTH_TOKEN_OPTION) == null
? null
: dom.getChild(AUTH_TOKEN_OPTION).getValue());

pluginConfig.setSkipValidateSdkDependencyVersions(
dom.getChild(SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS_OPTION) != null
&& Boolean.parseBoolean(
dom.getChild(SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS_OPTION).getValue()));
}

return pluginConfig;
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/io/sentry/config/PluginConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public class PluginConfig {
public static final @NotNull String DEFAULT_DEBUG_SENTRY_CLI_STRING = "false";
public static final boolean DEFAULT_DEBUG = false;
public static final @NotNull String DEFAULT_DEBUG_STRING = "false";
public static final boolean DEFAULT_SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS = false;
public static final @NotNull String DEFAULT_SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS_STRING =
"false";

private boolean skip = DEFAULT_SKIP;
private boolean skipAutoInstall = DEFAULT_SKIP_AUTO_INSTALL;
Expand All @@ -26,6 +29,7 @@ public class PluginConfig {
private boolean skipSourceBundle = DEFAULT_SKIP_SOURCE_BUNDLE;
private boolean debugSentryCli = DEFAULT_DEBUG_SENTRY_CLI;
private boolean debug = DEFAULT_DEBUG;
private boolean skipValidateSdkDependencyVersions = DEFAULT_SKIP_VALIDATE_SDK_DEPENDENCY_VERSIONS;

private @Nullable String org;
private @Nullable String project;
Expand Down Expand Up @@ -81,6 +85,11 @@ public void setSkipSourceBundle(final boolean skipSourceBundle) {
this.skipSourceBundle = skipSourceBundle;
}

public void setSkipValidateSdkDependencyVersions(
final boolean skipValidateSdkDependencyVersions) {
this.skipValidateSdkDependencyVersions = skipValidateSdkDependencyVersions;
}

public boolean isSkipAutoInstall() {
return skipAutoInstall || skip;
}
Expand All @@ -97,6 +106,10 @@ public boolean isSkipSourceBundle() {
return skipSourceBundle || skip;
}

public boolean isSkipValidateSdkDependencyVersions() {
return skipValidateSdkDependencyVersions;
}

public @Nullable String getOrg() {
return org;
}
Expand Down
Loading
Loading