diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt index a35d00f6c63..c5bb333da6f 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt @@ -155,17 +155,21 @@ internal object MuzzleMavenRepoUtils { var attemptCount = 0 var range: VersionRangeResult? = null var failure: VersionRangeResolutionException? = null + val resultExceptions = mutableListOf>>() fun attemptResolve(): VersionRangeResult? { attemptCount++ - return try { - range = system.resolveVersionRange(session, rangeRequest) + val result = try { failure = null - range?.takeIf { it.hasBounds() } + system.resolveVersionRange(session, rangeRequest) } catch (e: VersionRangeResolutionException) { failure = e - range = e.result ?: range - null + e.result ?: return null } + range = result + if (result.exceptions.isNotEmpty()) { + resultExceptions += attemptCount to result.exceptions.toList() + } + return result.takeIf { failure == null && it.hasBounds() } } repeat(4) { @@ -195,6 +199,7 @@ internal object MuzzleMavenRepoUtils { rangeRequest.repositories, range, failure, + resultExceptions, attemptCount, waitedSeconds, enableBackoffRetries @@ -275,6 +280,7 @@ internal object MuzzleMavenRepoUtils { repositories: List, range: VersionRangeResult?, failure: VersionRangeResolutionException?, + resultExceptions: List>>, attemptCount: Int, waitedSeconds: Long, enableBackoffRetries: Boolean @@ -303,6 +309,15 @@ internal object MuzzleMavenRepoUtils { appendLine(" highestVersion=${range.highestVersion ?: ""}") appendLine(" versionCount=${range.versions.size}") } + if (resultExceptions.isNotEmpty()) { + appendLine("Resolution result exceptions:") + resultExceptions.forEach { (attempt, exceptions) -> + appendLine(" Attempt $attempt:") + exceptions.forEach { exception -> + appendException(exception, " ") + } + } + } if (failure != null) { appendLine("Last resolution failure:") appendLine(" ${failure.javaClass.name}: ${failure.message ?: ""}") @@ -313,6 +328,20 @@ internal object MuzzleMavenRepoUtils { }.trimEnd() } + private fun StringBuilder.appendException(exception: Throwable, indent: String) { + var current: Throwable? = exception + var currentIndent = indent + var depth = 0 + while (current != null && depth < 10) { + val prefix = if (depth == 0) "" else "Caused by: " + appendLine("$currentIndent$prefix${current.javaClass.name}: ${current.message ?: ""}") + val cause = current.cause + current = cause?.takeUnless { it === current } + currentIndent += " " + depth++ + } + } + private fun artifactCoordinates(artifact: Artifact): String { val classifier = artifact.classifier?.takeUnless { it.isEmpty() } return listOfNotNull( diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtilsTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtilsTest.kt index 682b8e29f49..d53cc5e5d80 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtilsTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtilsTest.kt @@ -17,6 +17,7 @@ import org.junit.jupiter.api.io.TempDir import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource import java.io.File +import java.io.IOException import java.lang.reflect.Proxy import java.util.concurrent.atomic.AtomicInteger import org.assertj.core.api.Assertions.assertThat @@ -71,7 +72,7 @@ class MuzzleMavenRepoUtilsTest { versions = "[1.0,)" } val attempts = AtomicInteger() - val retryingSystem = repositorySystemThrowingThenResolving( + val retryingSystem = repositorySystemReturningAfterFailures( failuresBeforeSuccess = 3, result = createVersionRangeResult("1.0.0"), attempts = attempts @@ -149,7 +150,7 @@ class MuzzleMavenRepoUtilsTest { versions = "[1.0,)" } val attempts = AtomicInteger() - val throwingSystem = repositorySystemThrowingThenResolving( + val throwingSystem = repositorySystemReturningAfterFailures( failuresBeforeSuccess = 4, result = createVersionRangeResult("1.0.0"), attempts = attempts @@ -171,6 +172,41 @@ class MuzzleMavenRepoUtilsTest { assertThat(attempts).hasValue(4) } + @Test + fun `resolveVersionRange failure includes embedded result exceptions from every attempt`() { + val directive = MuzzleDirective().apply { + group = "com.example" + module = "mylib" + versions = "[1.0,)" + } + val attempts = AtomicInteger() + val emptyResult = createVersionRangeResult().apply { + addException( + IllegalStateException( + "metadata failure", + IOException("download failure") + ) + ) + } + val failingSystem = repositorySystemReturningAfterFailures(0, emptyResult, attempts) + + assertThatThrownBy { + MuzzleMavenRepoUtils.resolveVersionRange( + directive, + failingSystem, + newSession(), + emptyList(), + enableBackoffRetries = false + ) + }.isInstanceOf(IllegalStateException::class.java) + .hasMessageContaining("Resolution result exceptions:") + .hasMessageContaining("Attempt 1:") + .hasMessageContaining("Attempt 4:") + .hasMessageContaining("java.lang.IllegalStateException: metadata failure") + .hasMessageContaining("Caused by: java.io.IOException: download failure") + assertThat(attempts).hasValue(4) + } + @Test fun `resolveVersionRange includes directive extra repositories`() { val repoA = publishAndGetRepo("com.example", "mylib", listOf("1.0.0", "2.0.0"), subDir = "repoA") @@ -328,7 +364,7 @@ class MuzzleMavenRepoUtilsTest { return VersionRangeResult(request).apply { this.versions = versions } } - private fun repositorySystemThrowingThenResolving( + private fun repositorySystemReturningAfterFailures( failuresBeforeSuccess: Int, result: VersionRangeResult, attempts: AtomicInteger @@ -349,8 +385,9 @@ class MuzzleMavenRepoUtilsTest { } result } - "toString" -> "repositorySystemThrowingThenResolving" + "toString" -> "repositorySystemReturningAfterFailures" else -> throw UnsupportedOperationException(method.name) } } as RepositorySystem + }