diff --git a/core/src/main/kotlin/com/mitteloupe/cag/core/generation/versioncatalog/VersionCatalogUpdater.kt b/core/src/main/kotlin/com/mitteloupe/cag/core/generation/versioncatalog/VersionCatalogUpdater.kt index c2c5e5d..f22055c 100644 --- a/core/src/main/kotlin/com/mitteloupe/cag/core/generation/versioncatalog/VersionCatalogUpdater.kt +++ b/core/src/main/kotlin/com/mitteloupe/cag/core/generation/versioncatalog/VersionCatalogUpdater.kt @@ -91,8 +91,9 @@ class VersionCatalogUpdater( val resolvedPluginIdToAliasMutable = existingPluginIdToAlias.toMutableMap() val pluginRequirements = mutableListOf() val pluginAliasToIdMutable = existingPluginAliasToId.toMutableMap() + val uniqueDesiredPlugins = dependencyConfiguration.plugins.distinctBy { it.id } - for (desired in dependencyConfiguration.plugins) { + for (desired in uniqueDesiredPlugins) { val existingAlias = existingPluginIdToAlias[desired.id] if (existingAlias != null) { resolvedPluginIdToAliasMutable[desired.id] = existingAlias @@ -131,8 +132,9 @@ class VersionCatalogUpdater( val resolvedLibraryModuleToAliasMutable = existingLibraryModuleToAlias.toMutableMap() val libraryRequirements = mutableListOf() val libraryAliasToModuleMutable = existingLibraryAliasToModule.toMutableMap() + val uniqueDesiredLibraries = dependencyConfiguration.libraries.distinctBy { it.module } - for (desired in dependencyConfiguration.libraries) { + for (desired in uniqueDesiredLibraries) { val existingAlias = existingLibraryModuleToAlias[desired.module] if (existingAlias != null) { resolvedLibraryModuleToAliasMutable[desired.module] = existingAlias @@ -201,7 +203,7 @@ class VersionCatalogUpdater( fileCreator.createFileIfNotExists(catalogFile) { "" } val pluginRequirements = - dependencyConfiguration.plugins.map { desired -> + dependencyConfiguration.plugins.distinctBy { it.id }.map { desired -> PluginRequirement( key = desired.key, id = desired.id, @@ -210,7 +212,7 @@ class VersionCatalogUpdater( } val libraryRequirements = - dependencyConfiguration.libraries.map { desired -> + dependencyConfiguration.libraries.distinctBy { it.module }.map { desired -> LibraryRequirement( key = desired.key, module = desired.module, diff --git a/core/src/test/kotlin/com/mitteloupe/cag/core/generation/VersionCatalogUpdaterTest.kt b/core/src/test/kotlin/com/mitteloupe/cag/core/generation/VersionCatalogUpdaterTest.kt index 85b9c38..93d6d6d 100644 --- a/core/src/test/kotlin/com/mitteloupe/cag/core/generation/VersionCatalogUpdaterTest.kt +++ b/core/src/test/kotlin/com/mitteloupe/cag/core/generation/VersionCatalogUpdaterTest.kt @@ -4,6 +4,7 @@ import com.mitteloupe.cag.core.fake.FakeFileSystemBridge import com.mitteloupe.cag.core.generation.filesystem.FileCreator import com.mitteloupe.cag.core.generation.versioncatalog.DependencyConfiguration import com.mitteloupe.cag.core.generation.versioncatalog.LibraryConstants +import com.mitteloupe.cag.core.generation.versioncatalog.LibraryConstants.TEST_MOCKITO_ANDROID import com.mitteloupe.cag.core.generation.versioncatalog.PluginConstants import com.mitteloupe.cag.core.generation.versioncatalog.SectionEntryRequirement.LibraryRequirement import com.mitteloupe.cag.core.generation.versioncatalog.SectionEntryRequirement.PluginRequirement @@ -24,6 +25,145 @@ class VersionCatalogUpdaterTest { classUnderTest = VersionCatalogUpdater(FileCreator(FakeFileSystemBridge())) } + @Test + fun `Given libraries include library twice when createOrUpdateVersionCatalog then deduplicates`() { + // Given + val (projectRoot, catalogFile) = + createProjectWithCatalog( + initialContent = + """ + [versions] + kotlin = "2.2.10" + compileSdk = "36" + minSdk = "24" + """.trimIndent() + ) + + val dependencyConfiguration = + DependencyConfiguration( + versions = emptyList(), + libraries = listOf(TEST_MOCKITO_ANDROID, TEST_MOCKITO_ANDROID), + plugins = emptyList() + ) + val expectedCatalog = + """ + [versions] + kotlin = "2.2.10" + compileSdk = "36" + minSdk = "24" + mockitoAndroid = "2.28.6" + + [libraries] + test-mockito-android = { module = "com.linkedin.dexmaker:dexmaker-mockito-inline", version.ref = "mockitoAndroid" } + + """.trimIndent() + + // When + classUnderTest.createOrUpdateVersionCatalog(projectRootDir = projectRoot, dependencyConfiguration = dependencyConfiguration) + val actualCatalog = catalogFile.readText() + + // Then + assertEquals(expectedCatalog, actualCatalog) + } + + @Test + fun `Given plugins include plugin twice when createOrUpdateVersionCatalog then deduplicates`() { + // Given + val (projectRoot, catalogFile) = + createProjectWithCatalog( + initialContent = + """ + [versions] + kotlin = "2.2.10" + compileSdk = "36" + minSdk = "24" + """.trimIndent() + ) + + val dependencyConfiguration = + DependencyConfiguration( + versions = emptyList(), + libraries = emptyList(), + plugins = listOf(PluginConstants.KOTLIN_JVM, PluginConstants.KOTLIN_JVM) + ) + val expectedCatalog = + """ + [versions] + kotlin = "2.2.10" + compileSdk = "36" + minSdk = "24" + + [plugins] + kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } + + """.trimIndent() + + // When + classUnderTest.createOrUpdateVersionCatalog(projectRootDir = projectRoot, dependencyConfiguration = dependencyConfiguration) + val actualCatalog = catalogFile.readText() + + // Then + assertEquals(expectedCatalog, actualCatalog) + } + + @Test + fun `Given libraries include library twice when createOrReplaceVersionCatalog then deduplicates`() { + // Given + val projectRoot = createTempDirectory(prefix = "newCatalogDedupLib").toFile() + + val dependencyConfiguration = + DependencyConfiguration( + versions = emptyList(), + libraries = listOf(TEST_MOCKITO_ANDROID, TEST_MOCKITO_ANDROID), + plugins = emptyList() + ) + val expectedCatalog = + """ + [versions] + mockitoAndroid = "2.28.6" + + [libraries] + test-mockito-android = { module = "com.linkedin.dexmaker:dexmaker-mockito-inline", version.ref = "mockitoAndroid" } + + """.trimIndent() + + // When + classUnderTest.createOrReplaceVersionCatalog(projectRootDir = projectRoot, dependencyConfiguration = dependencyConfiguration) + val actualCatalog = File(projectRoot, "gradle/libs.versions.toml").readText() + + // Then + assertEquals(expectedCatalog, actualCatalog) + } + + @Test + fun `Given plugins include plugin twice when createOrReplaceVersionCatalog then deduplicates`() { + // Given + val projectRoot = createTempDirectory(prefix = "newCatalogDedupPlugin").toFile() + + val dependencyConfiguration = + DependencyConfiguration( + versions = emptyList(), + libraries = emptyList(), + plugins = listOf(PluginConstants.KOTLIN_JVM, PluginConstants.KOTLIN_JVM) + ) + val expectedCatalog = + """ + [versions] + kotlin = "2.2.10" + + [plugins] + kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } + + """.trimIndent() + + // When + classUnderTest.createOrReplaceVersionCatalog(projectRootDir = projectRoot, dependencyConfiguration = dependencyConfiguration) + val actualCatalog = File(projectRoot, "gradle/libs.versions.toml").readText() + + // Then + assertEquals(expectedCatalog, actualCatalog) + } + @Test fun `Given no catalog file when createOrUpdateVersionCatalog then does nothing`() { // Given