Skip to content

Commit

Permalink
Add Auto-Install for graphql-22 (#100)
Browse files Browse the repository at this point in the history
## 📜 Description
Add support for parsing versions with only major and minor parts (e.g.
22.5)
Add Auto-Install strategy for graphql-22


## 💡 Motivation and Context
Fixes [#3757](getsentry/sentry-java#3757)

## 💚 How did you test it?


## 📝 Checklist
<!--- Put an `x` in the boxes that apply -->
- [ ] I reviewed the submitted code
- [ ] I added tests to verify the changes
- [ ] I updated the docs if needed
- [ ] No breaking changes


## 🔮 Next steps

---------

Co-authored-by: Alexander Dinauer <[email protected]>
  • Loading branch information
lbloder and adinauer authored Nov 20, 2024
1 parent daa4fd9 commit bdb9fbd
Show file tree
Hide file tree
Showing 8 changed files with 313 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- Add AutoInstallStrategy for graphql-22 ([#100](https://github.com/getsentry/sentry-maven-plugin/pull/100))
- More lenient handling of empty Maven modules ([#103](https://github.com/getsentry/sentry-maven-plugin/pull/103))
- The Maven plugin now ignores Maven modules with empty source roots and instead of failing the build simply prints a log message
- This allows the plugin to be configured in the root POM even if it does not have sources
Expand Down
17 changes: 12 additions & 5 deletions src/main/java/io/sentry/SentryInstallerLifecycleParticipant.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.sentry;

import static io.sentry.autoinstall.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;
import static io.sentry.autoinstall.log4j2.Log4j2InstallStrategy.SENTRY_LOG4J2_ID;
Expand All @@ -14,6 +15,7 @@
import io.sentry.autoinstall.AbstractIntegrationInstaller;
import io.sentry.autoinstall.AutoInstallState;
import io.sentry.autoinstall.SentryInstaller;
import io.sentry.autoinstall.graphql.Graphql22InstallStrategy;
import io.sentry.autoinstall.graphql.GraphqlInstallStrategy;
import io.sentry.autoinstall.jdbc.JdbcInstallStrategy;
import io.sentry.autoinstall.log4j2.Log4j2InstallStrategy;
Expand Down Expand Up @@ -59,6 +61,7 @@ public class SentryInstallerLifecycleParticipant extends AbstractMavenLifecycleP
Log4j2InstallStrategy.class,
LogbackInstallStrategy.class,
GraphqlInstallStrategy.class,
Graphql22InstallStrategy.class,
JdbcInstallStrategy.class,
QuartzInstallStrategy.class)
.collect(Collectors.toList());
Expand Down Expand Up @@ -118,8 +121,7 @@ public void afterProjectsRead(final @NotNull MavenSession session)
autoInstallState.setInstallLogback(
!isModuleAvailable(resolvedArtifacts, SENTRY_LOGBACK_ID));
autoInstallState.setInstallLog4j2(!isModuleAvailable(resolvedArtifacts, SENTRY_LOG4J2_ID));
autoInstallState.setInstallGraphql(
!isModuleAvailable(resolvedArtifacts, SENTRY_GRAPHQL_ID));
autoInstallState.setInstallGraphql(shouldInstallGraphQL(resolvedArtifacts));
autoInstallState.setInstallJdbc(!isModuleAvailable(resolvedArtifacts, SENTRY_JDBC_ID));
autoInstallState.setInstallQuartz(!isModuleAvailable(resolvedArtifacts, SENTRY_QUARTZ_ID));

Expand All @@ -145,9 +147,14 @@ public void afterProjectsRead(final @NotNull MavenSession session)

private boolean shouldInstallSpring(final @NotNull List<Artifact> resolvedArtifacts) {
return !(isModuleAvailable(resolvedArtifacts, SENTRY_SPRING_5_ID)
&& isModuleAvailable(resolvedArtifacts, SENTRY_SPRING_6_ID)
&& isModuleAvailable(resolvedArtifacts, SENTRY_SPRING_BOOT_2_ID)
&& isModuleAvailable(resolvedArtifacts, SENTRY_SPRING_BOOT_3_ID));
|| isModuleAvailable(resolvedArtifacts, SENTRY_SPRING_6_ID)
|| isModuleAvailable(resolvedArtifacts, SENTRY_SPRING_BOOT_2_ID)
|| isModuleAvailable(resolvedArtifacts, SENTRY_SPRING_BOOT_3_ID));
}

private boolean shouldInstallGraphQL(final @NotNull List<Artifact> resolvedArtifacts) {
return !(isModuleAvailable(resolvedArtifacts, SENTRY_GRAPHQL_ID)
|| isModuleAvailable(resolvedArtifacts, SENTRY_GRAPHQL_22_ID));
}

public static boolean isModuleAvailable(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.sentry.autoinstall.graphql;

import io.sentry.autoinstall.AbstractIntegrationInstaller;
import io.sentry.autoinstall.AutoInstallState;
import io.sentry.semver.Version;
import java.util.List;
import org.eclipse.aether.artifact.Artifact;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Graphql22InstallStrategy extends AbstractIntegrationInstaller {
private static final @NotNull String GRAPHQL_GROUP = "com.graphql-java";
private static final @NotNull String GRAPHQL_ID = "graphql-java";
public static final @NotNull String SENTRY_GRAPHQL_22_ID = "sentry-graphql-22";

public Graphql22InstallStrategy() {
this(LoggerFactory.getLogger(Graphql22InstallStrategy.class));
}

public Graphql22InstallStrategy(final @NotNull Logger logger) {
super(logger);
}

@Override
protected @Nullable Artifact findThirdPartyDependency(
final @NotNull List<Artifact> resolvedArtifacts) {
return resolvedArtifacts.stream()
.filter(
(dep) ->
dep.getGroupId().equals(GRAPHQL_GROUP) && dep.getArtifactId().equals(GRAPHQL_ID))
.findFirst()
.orElse(null);
}

@Override
protected boolean shouldInstallModule(final @NotNull AutoInstallState autoInstallState) {
return autoInstallState.isInstallGraphql();
}

@Override
protected @Nullable Version minSupportedThirdPartyVersion() {
return Version.create(22, 0, 0);
}

@Override
protected @NotNull Version minSupportedSentryVersion() {
return Version.create(8, 0, 0);
}

@Override
protected @NotNull String sentryModuleId() {
return SENTRY_GRAPHQL_22_ID;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ protected boolean shouldInstallModule(final @NotNull AutoInstallState autoInstal
return autoInstallState.isInstallGraphql();
}

@Override
protected @Nullable Version maxSupportedThirdPartyVersion() {
return Version.create(21, 9999, 9999);
}

@Override
protected @NotNull Version minSupportedSentryVersion() {
return Version.create(6, 25, 2);
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/io/sentry/semver/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ private static Version parse(String s, boolean verifyOnly) {
if (c == '.') {
// single 0 is allowed
state = STATE_PATCH_INIT;
} else if (c == EOS) {
break loop;
} else if (c >= '0' && c <= '9') {
if (verifyOnly) {
return null;
Expand All @@ -281,6 +283,8 @@ private static Version parse(String s, boolean verifyOnly) {
case STATE_MINOR_DEFAULT:
if (c >= '0' && c <= '9') {
minor = minor * DECIMAL + Character.digit(c, DECIMAL);
} else if (c == EOS) {
break loop;
} else if (c == '.') {
state = STATE_PATCH_INIT;
} else if (verifyOnly) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package io.sentry.integration.autoinstall.spring

import basePom
import io.sentry.autoinstall.util.SdkVersionInfo
import io.sentry.integration.installMavenWrapper
import org.apache.maven.it.VerificationException
import org.apache.maven.it.Verifier
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.io.File
import java.io.IOException
import java.nio.file.Files
import java.nio.file.StandardOpenOption
import kotlin.io.path.Path

class SpringAutoInstallTestIT {
@TempDir()
lateinit var file: File

@BeforeEach
fun installWrapper() {
installMavenWrapper(file, "3.8.6")
}

fun getPOM(
installSpring: Boolean = true,
springVersion: String = "6.0.0",
sentrySpringArtifact: String = "sentry-spring-jakarta",
sentrySpringVersion: String = "6.28.0",
installedSentryVersion: String? = null,
): String {
var dependencies =
"""
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>$springVersion</version>
</dependency>
""".trimIndent()

if (!installSpring) {
dependencies =
dependencies.plus(
"""
<dependency>
<groupId>io.sentry</groupId>
<artifactId>$sentrySpringArtifact</artifactId>
<version>$sentrySpringVersion</version>
</dependency>
""".trimIndent(),
)
}

val pomContent = basePom(dependencies, installedSentryVersion)

Files.write(Path("${file.absolutePath}/pom.xml"), pomContent.toByteArray(), StandardOpenOption.CREATE)

return file.absolutePath
}

@Test
@Throws(VerificationException::class, IOException::class)
fun `when sentry-spring-jakarta is a direct dependency logs a message and does nothing`() {
val path = getPOM(false)
val verifier = Verifier(path)
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyTextInLog("sentry-spring-jakarta won't be installed because it was already installed directly")
verifier.resetStreams()
}

@Test
@Throws(VerificationException::class, IOException::class)
fun `when sentry-spring is a direct dependency logs a message and does nothing`() {
val path = getPOM(sentrySpringArtifact = "sentry-spring", installSpring = false)
val verifier = Verifier(path)
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyTextInLog("sentry-spring-jakarta won't be installed because it was already installed directly")
verifier.resetStreams()
}

@Test
@Throws(VerificationException::class, IOException::class)
fun `when sentry-spring-boot is a direct dependency logs a message and does nothing`() {
val path = getPOM(sentrySpringArtifact = "sentry-spring-boot", installSpring = false)
val verifier = Verifier(path)
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyTextInLog("sentry-spring-jakarta won't be installed because it was already installed directly")
verifier.resetStreams()
}

@Test
@Throws(VerificationException::class, IOException::class)
fun `when sentry-spring-boot-jakarta is a direct dependency logs a message and does nothing`() {
val path = getPOM(sentrySpringArtifact = "sentry-spring-boot-jakarta", installSpring = false)
val verifier = Verifier(path)
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyTextInLog("sentry-spring-jakarta won't be installed because it was already installed directly")
verifier.resetStreams()
}

@Test
@Throws(VerificationException::class, IOException::class)
fun `installs sentry-spring-jakarta with info message`() {
val path = getPOM()
val verifier = Verifier(path)
verifier.deleteDirectory("target")
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyTextInLog("sentry-spring-jakarta was successfully installed with version: ${SdkVersionInfo.getSentryVersion()}")
verifier.verifyFilePresent("target/lib/sentry-spring-jakarta-${SdkVersionInfo.getSentryVersion()}.jar")
verifier.resetStreams()
verifier.deleteDirectory(path)
}

@Test
@Throws(VerificationException::class, IOException::class)
fun `auto-installed sentry-spring-jakarta version matches sentry version`() {
val sentryVersion = "6.28.0"
val path = getPOM(installedSentryVersion = sentryVersion)
val verifier = Verifier(path)
verifier.deleteDirectory("target")
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyTextInLog("sentry-spring-jakarta was successfully installed with version: $sentryVersion")
verifier.verifyFilePresent("target/lib/sentry-spring-jakarta-$sentryVersion.jar")
verifier.resetStreams()
verifier.deleteDirectory(path)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package io.sentry.unit.autoinstall.graphql

import io.sentry.autoinstall.AutoInstallState
import io.sentry.autoinstall.graphql.Graphql22InstallStrategy
import io.sentry.unit.fakes.CapturingTestLogger
import org.apache.maven.model.Dependency
import org.eclipse.aether.artifact.Artifact
import org.eclipse.aether.artifact.DefaultArtifact
import org.junit.jupiter.api.Test
import org.slf4j.Logger
import kotlin.test.assertTrue

class Graphql22AutoInstallTest {
class Fixture {
val logger = CapturingTestLogger()
val dependencies = ArrayList<Dependency>()
val resolvedArtifacts = ArrayList<Artifact>()
lateinit var installState: AutoInstallState

fun getSut(
installGraphql: Boolean = true,
graphqlVersion: String = "22.0",
): Graphql22InstallStrategy {
installState = AutoInstallState("8.0.0")
installState.isInstallGraphql = installGraphql

resolvedArtifacts.add(
DefaultArtifact(
"com.graphql-java",
"graphql-java",
null,
graphqlVersion,
),
)

return Graphql22InstallStrategyImpl(logger)
}
}

private val fixture = Fixture()

@Test
fun `when sentry-graphql is a direct dependency logs a message and does nothing`() {
val sut = fixture.getSut(false)

sut.install(fixture.dependencies, fixture.resolvedArtifacts, fixture.installState)

assertTrue {
fixture.logger.capturedMessage ==
"sentry-graphql-22 won't be installed because it was already installed directly"
}

assertTrue(fixture.dependencies.none { it.groupId == "io.sentry" && it.artifactId == "sentry-graphql-22" })
}

@Test
fun `installs sentry-graphql with info message`() {
val sut = fixture.getSut()

sut.install(fixture.dependencies, fixture.resolvedArtifacts, fixture.installState)

assertTrue {
fixture.logger.capturedMessage ==
"sentry-graphql-22 was successfully installed with version: 8.0.0"
}

assertTrue(fixture.dependencies.any { it.groupId == "io.sentry" && it.artifactId == "sentry-graphql-22" })
}

@Test
fun `when graphql version is too low logs a message and does nothing`() {
val sut = fixture.getSut(graphqlVersion = "21.9")

sut.install(fixture.dependencies, fixture.resolvedArtifacts, fixture.installState)

assertTrue {
fixture.logger.capturedMessage ==
"sentry-graphql-22 won't be installed because the current " +
"version is lower than the minimum supported version 22.0.0"
}

assertTrue(fixture.dependencies.none { it.artifactId == "sentry-graphql-22" })
}

private class Graphql22InstallStrategyImpl(logger: Logger) : Graphql22InstallStrategy(logger)
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,20 @@ class GraphqlAutoInstallTest {
assertTrue(fixture.dependencies.any { it.groupId == "io.sentry" && it.artifactId == "sentry-graphql" })
}

@Test
fun `when graphql version is too high logs a message and does nothing`() {
val sut = fixture.getSut(graphqlVersion = "22.1")

sut.install(fixture.dependencies, fixture.resolvedArtifacts, fixture.installState)

assertTrue {
fixture.logger.capturedMessage ==
"sentry-graphql won't be installed because the current " +
"version is higher than the maximum supported version 21.9999.9999"
}

assertTrue(fixture.dependencies.none { it.artifactId == "sentry-graphql" })
}

private class GraphqlInstallStrategyImpl(logger: Logger) : GraphqlInstallStrategy(logger)
}

0 comments on commit bdb9fbd

Please sign in to comment.