diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..45a325c --- /dev/null +++ b/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "**/exception/**" diff --git a/plugin/config/detekt-baseline.xml b/plugin/config/detekt-baseline.xml index 1dd9dbd..12d1909 100644 --- a/plugin/config/detekt-baseline.xml +++ b/plugin/config/detekt-baseline.xml @@ -4,12 +4,6 @@ EmptyFunctionBlock:VersionCatalogGeneratorPlugin.kt$VersionCatalogGeneratorPlugin${} MagicNumber:LocalDependencyResolver.kt$LocalDependencyResolver$3 - TooGenericExceptionThrown:FileCatalogParser.kt$FileCatalogParser$throw RuntimeException("${libraryName} not found in catalog file") - TooGenericExceptionThrown:FileCatalogParser.kt$FileCatalogParser$throw RuntimeException("Group not found ") - TooGenericExceptionThrown:FileCatalogParser.kt$FileCatalogParser$throw RuntimeException("Name not found") - TooGenericExceptionThrown:FileCatalogParser.kt$FileCatalogParser$throw RuntimeException("Version not found") - TooGenericExceptionThrown:FileCatalogParser.kt$FileCatalogParser$throw RuntimeException("Version ref '${it}' not found") - TooGenericExceptionThrown:GradleDependencyResolver.kt$GradleDependencyResolver$throw RuntimeException("Unable to resolve ${notation}") TooGenericExceptionThrown:LocalDependencyResolver.kt$LocalDependencyResolver$throw RuntimeException( "LocalDependencyResolver can only resolve File, Path, or Dependency notations", ) TooGenericExceptionThrown:LocalDependencyResolver.kt$LocalDependencyResolver$throw RuntimeException("Path ${filePath} does not exist") TooGenericExceptionThrown:LocalDependencyResolver.kt$LocalDependencyResolver$throw RuntimeException("Unable to parse notation '${notation}") diff --git a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/Generator.kt b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/Generator.kt index 00a4fd2..c4eafef 100644 --- a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/Generator.kt +++ b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/Generator.kt @@ -203,7 +203,14 @@ object Generator { seenModules: MutableSet = mutableSetOf(), filter: (Dependency) -> Boolean, ): Map> { - return model.dependencyManagement.dependencies + val deps = model.dependencyManagement?.dependencies ?: listOf() + if (deps.isEmpty()) { + logger.warn( + "${model.groupId}:${model.artifactId}:${model.version} does not have any dependencies defined " + + "in dependencyManagement", + ) + } + return deps .asSequence() .onEach { it.groupId = mapGroup(model, it.groupId) } .filter(filter) diff --git a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/exception/ConfigurationException.kt b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/exception/ConfigurationException.kt new file mode 100644 index 0000000..c0f1744 --- /dev/null +++ b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/exception/ConfigurationException.kt @@ -0,0 +1,18 @@ +package dev.aga.gradle.versioncatalogs.exception + +class ConfigurationException : RuntimeException { + constructor() : super() + + constructor(message: String) : super(message) + + constructor(message: String, cause: Throwable) : super(message, cause) + + constructor(cause: Throwable) : super(cause) + + constructor( + message: String, + cause: Throwable, + enableSuppression: Boolean, + writableStackTrace: Boolean, + ) : super(message, cause, enableSuppression, writableStackTrace) +} diff --git a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/exception/ResolutionException.kt b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/exception/ResolutionException.kt new file mode 100644 index 0000000..ca6c234 --- /dev/null +++ b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/exception/ResolutionException.kt @@ -0,0 +1,18 @@ +package dev.aga.gradle.versioncatalogs.exception + +class ResolutionException : RuntimeException { + constructor() : super() + + constructor(message: String) : super(message) + + constructor(message: String, cause: Throwable) : super(message, cause) + + constructor(cause: Throwable) : super(cause) + + constructor( + message: String, + cause: Throwable, + enableSuppression: Boolean, + writableStackTrace: Boolean, + ) : super(message, cause, enableSuppression, writableStackTrace) +} diff --git a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParser.kt b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParser.kt index b45b30e..e4eef94 100644 --- a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParser.kt +++ b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParser.kt @@ -1,5 +1,6 @@ package dev.aga.gradle.versioncatalogs.service +import dev.aga.gradle.versioncatalogs.exception.ConfigurationException import java.io.File import org.apache.maven.model.Dependency import org.tomlj.Toml @@ -19,14 +20,16 @@ internal class FileCatalogParser(private val file: File) : CatalogParser { ?.let { it as? TomlTable } ?.let { it[libraryName] } ?.let { it as? TomlTable } - ?: throw RuntimeException("${libraryName} not found in catalog file") + ?: throw ConfigurationException( + "${libraryName} not found in catalog file ${file.absolutePath}", + ) val versions = toml["versions"]?.let { it as? TomlTable } - return getGAV(library, versions) + return getGAV(libraryName, library, versions) } - private fun getGAV(library: TomlTable, versions: TomlTable?): Dependency { + private fun getGAV(libraryName: String, library: TomlTable, versions: TomlTable?): Dependency { val (group, name) = if (library["module"] is String) { val split = (library["module"] as String).split(":") @@ -34,14 +37,18 @@ internal class FileCatalogParser(private val file: File) : CatalogParser { } else { val group = library["group"]?.let { it as? String } - ?: throw RuntimeException("Group not found ") + ?: throw ConfigurationException( + "Group not found for library ${libraryName} in catalog file ${file.absolutePath}", + ) val name = library["name"]?.let { it as? String } - ?: throw RuntimeException("Name not found") + ?: throw ConfigurationException( + "Name not found for library ${libraryName} in catalog file ${file.absolutePath}", + ) group to name } - val version = getVersion(library, versions) + val version = getVersion(libraryName, library, versions) return Dependency().apply { groupId = group artifactId = name @@ -49,13 +56,22 @@ internal class FileCatalogParser(private val file: File) : CatalogParser { } } - private fun getVersion(library: TomlTable, versions: TomlTable?): String { - library.getString("version.ref")?.let { - return versions?.getString(it) - ?: throw RuntimeException("Version ref '${it}' not found") + private fun getVersion(libraryName: String, library: TomlTable, versions: TomlTable?): String { + if (library.isTable("version") && library.isString("version.ref")) { + val ref = library.getString("version.ref") + return versions?.getString(ref) + ?: throw ConfigurationException( + "Version ref '${ref}' not found for library ${libraryName} in catalog file ${file.absolutePath}", + ) } - return library.getString("version") ?: throw RuntimeException("Version not found") + if (library.isString("version")) { + return library.getString("version")!! + } + + throw ConfigurationException( + "Version not found for library ${libraryName} in catalog file ${file.absolutePath}", + ) } private fun parseCatalog(file: File) = Toml.parse(file.toPath()) diff --git a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/GradleDependencyResolver.kt b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/GradleDependencyResolver.kt index 7b5d24c..713b6f9 100644 --- a/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/GradleDependencyResolver.kt +++ b/plugin/src/main/kotlin/dev/aga/gradle/versioncatalogs/service/GradleDependencyResolver.kt @@ -1,5 +1,6 @@ package dev.aga.gradle.versioncatalogs.service +import dev.aga.gradle.versioncatalogs.exception.ResolutionException import java.util.concurrent.atomic.AtomicInteger import java.util.function.Supplier import org.apache.maven.model.Model @@ -38,7 +39,7 @@ class GradleDependencyResolver( val resolver = LocalDependencyResolver(path.parent) return resolver.resolve(path.fileName) } - throw RuntimeException("Unable to resolve ${notation}") + throw ResolutionException("Unable to resolve ${notation}") } private fun createConfiguration(): Configuration { diff --git a/plugin/src/test/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParserTest.kt b/plugin/src/test/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParserTest.kt index eb5ae59..b3dc26f 100644 --- a/plugin/src/test/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParserTest.kt +++ b/plugin/src/test/kotlin/dev/aga/gradle/versioncatalogs/service/FileCatalogParserTest.kt @@ -1,5 +1,6 @@ package dev.aga.gradle.versioncatalogs.service +import dev.aga.gradle.versioncatalogs.exception.ConfigurationException import java.nio.file.Paths import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType @@ -11,7 +12,12 @@ import org.junit.jupiter.params.provider.MethodSource internal class FileCatalogParserTest { @ParameterizedTest @MethodSource("testFindBomProvider") - fun testFindBom(libraryName: String, expected: Array, shouldThrow: Boolean = false) { + fun testFindBom( + libraryName: String, + expected: Array, + shouldThrow: Boolean, + errorContains: String, + ) { val file = buildPath("libs.versions.toml").toFile() val parser = FileCatalogParser(file) if (!shouldThrow) { @@ -20,9 +26,9 @@ internal class FileCatalogParserTest { .extracting("groupId", "artifactId", "version") .containsExactly(*expected) } else { - assertThatExceptionOfType(RuntimeException::class.java).isThrownBy { - parser.findLibrary(libraryName) - } + assertThatExceptionOfType(ConfigurationException::class.java) + .isThrownBy { parser.findLibrary(libraryName) } + .withMessageContaining(errorContains) } } @@ -33,10 +39,26 @@ internal class FileCatalogParserTest { @JvmStatic private fun testFindBomProvider(): List { return listOf( - arguments("groovy-core", arrayOf("org.codehaus.groovy", "groovy", "3.0.5"), false), - arguments("fake-lib", arrayOf("dev.aga.lib", "fake-lib", "1.0.2"), false), - arguments("another-lib", arrayOf("dev.aga.lib", "another-lib", "1.0.0"), false), - arguments("commons-lang3", arrayOf(""), true), + arguments( + "groovy-core", + arrayOf("org.codehaus.groovy", "groovy", "3.0.5"), + false, + "", + ), + arguments("fake-lib", arrayOf("dev.aga.lib", "fake-lib", "1.0.2"), false, ""), + arguments("another-lib", arrayOf("dev.aga.lib", "another-lib", "1.0.0"), false, ""), + arguments( + "commons-lang3", + arrayOf(""), + true, + "Version not found for library commons-lang3 in catalog file", + ), + arguments( + "missing-ref", + arrayOf(""), + true, + "Version ref 'bad-ref' not found for library missing-ref in catalog file", + ), ) } diff --git a/plugin/src/test/resources/libs.versions.toml b/plugin/src/test/resources/libs.versions.toml index ceec759..bd6374a 100644 --- a/plugin/src/test/resources/libs.versions.toml +++ b/plugin/src/test/resources/libs.versions.toml @@ -8,9 +8,11 @@ groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" } groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" } groovy-nio = { module = "org.codehaus.groovy:groovy-nio", version.ref = "groovy" } commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer = "3.9" } } +missing-ref = { group = "org.apache.commons", name = "commons-lang3", version.ref = "bad-ref" } fake-lib = { group = "dev.aga.lib", name = "fake-lib", version = "1.0.2" } another-lib = { group = "dev.aga.lib", name = "another-lib", version.ref = "dev" } + [bundles] groovy = ["groovy-core", "groovy-json", "groovy-nio"]