GradleErrorDetector.kt
package com.depanalyzer.parser.gradle
object GradleErrorDetector {
fun detectError(output: String): GradleErrorInfo? {
return when {
isPluginIncompatible(output) -> {
val pluginName = extractPluginName(output) ?: "unknown plugin"
GradleErrorInfo(
type = GradleErrorType.PLUGIN_INCOMPATIBLE,
message = "Plugin $pluginName incompatible with current Gradle version",
suggestedFlags = listOf("--no-daemon", "--build-cache=off")
)
}
isJvmIncompatible(output) -> {
GradleErrorInfo(
type = GradleErrorType.JVM_INCOMPATIBLE,
message = "Gradle version or JVM incompatibility detected",
suggestedFlags = listOf("--no-daemon")
)
}
isClasspathError(output) -> {
val className = extractClasspathErrorClass(output) ?: "classpath resource"
GradleErrorInfo(
type = GradleErrorType.CLASSPATH_ERROR,
message = "Classpath error: $className not found",
suggestedFlags = listOf("--build-cache=off")
)
}
isNestedBuildMismatch(output) -> {
GradleErrorInfo(
type = GradleErrorType.NESTED_BUILD_MISMATCH,
message = "Target project is not part of parent Gradle settings build",
suggestedFlags = emptyList()
)
}
else -> null
}
}
private fun isPluginIncompatible(output: String): Boolean {
return output.contains("Could not create plugin of type", ignoreCase = true) ||
output.contains("SourceDirectorySetFactory", ignoreCase = true) ||
output.contains("Could not generate a decorated class", ignoreCase = true) ||
(output.contains("An exception occurred applying plugin request", ignoreCase = true) &&
output.contains("Failed to apply plugin", ignoreCase = true))
}
private fun isJvmIncompatible(output: String): Boolean {
return (output.contains("NoClassDefFoundError", ignoreCase = true) &&
output.contains("Groovy", ignoreCase = true)) ||
output.contains("Could not initialize class org.codehaus.groovy", ignoreCase = true) ||
output.contains("InvokerHelper", ignoreCase = true) ||
(output.contains("NoClassDefFoundError", ignoreCase = true) &&
output.contains("reflection", ignoreCase = true))
}
private fun isClasspathError(output: String): Boolean {
return output.contains("ClassNotFoundException", ignoreCase = true) ||
output.contains("Could not find class", ignoreCase = true) ||
output.contains("ClassDefNotFound", ignoreCase = true)
}
private fun isNestedBuildMismatch(output: String): Boolean {
return output.contains("is not part of the build defined by settings file", ignoreCase = true)
}
private fun extractPluginName(output: String): String? {
val regex = Regex("""(?:plugin of type|plugin request)\s+['\[]([^'"\]]+)['\]]""", RegexOption.IGNORE_CASE)
return regex.find(output)?.groupValues?.get(1)?.substringAfterLast('.')
}
private fun extractClasspathErrorClass(output: String): String? {
val regex = Regex("""(?:ClassNotFoundException|ClassDefNotFound|Could not find class)[\s:]*([A-Za-z0-9._$]+)""")
return regex.find(output)?.groupValues?.get(1)
}
}
data class GradleErrorInfo(
val type: GradleErrorType,
val message: String,
val suggestedFlags: List<String> = emptyList()
)
enum class GradleErrorType {
PLUGIN_INCOMPATIBLE,
JVM_INCOMPATIBLE,
CLASSPATH_ERROR,
NESTED_BUILD_MISMATCH,
UNKNOWN
}