From 017445ec5d0ababf563795714263701add158379 Mon Sep 17 00:00:00 2001 From: Tony Robalik Date: Thu, 26 Oct 2023 17:17:51 -0700 Subject: [PATCH] Support version catalog references in BundleHandler and DependenciesHandler. (#1006) --- .../jvm/VersionCatalogSpec.groovy | 35 ++++++++ .../jvm/projects/VersionCatalogProject.groovy | 75 ++++++++++++++++ .../DependencyAnalysisExtension.kt | 5 +- .../autonomousapps/extension/BundleHandler.kt | 85 ++++++++++++++++++ .../extension/DependenciesHandler.kt | 88 ++++++------------- .../internal/advice/AdvicePrinter.kt | 23 +++-- .../ProjectHealthConsoleReportBuilder.kt | 2 +- .../reason/DependencyAdviceExplainer.kt | 7 +- .../com/autonomousapps/tasks/ReasonTask.kt | 16 ++-- .../com/autonomousapps/tasks/RewriteTask.kt | 3 +- .../extension/BundleHandlerTest.kt | 5 +- .../autonomousapps/internal/BundlesTest.kt | 5 +- .../ProjectHealthConsoleReportBuilderTest.kt | 9 +- .../autonomousapps/kit/gradle/Dependency.kt | 13 +++ 14 files changed, 276 insertions(+), 95 deletions(-) create mode 100644 src/functionalTest/groovy/com/autonomousapps/jvm/VersionCatalogSpec.groovy create mode 100644 src/functionalTest/groovy/com/autonomousapps/jvm/projects/VersionCatalogProject.groovy create mode 100644 src/main/kotlin/com/autonomousapps/extension/BundleHandler.kt diff --git a/src/functionalTest/groovy/com/autonomousapps/jvm/VersionCatalogSpec.groovy b/src/functionalTest/groovy/com/autonomousapps/jvm/VersionCatalogSpec.groovy new file mode 100644 index 000000000..324f3de2c --- /dev/null +++ b/src/functionalTest/groovy/com/autonomousapps/jvm/VersionCatalogSpec.groovy @@ -0,0 +1,35 @@ +package com.autonomousapps.jvm + +import com.autonomousapps.jvm.projects.VersionCatalogProject +import com.autonomousapps.utils.Colors + +import static com.autonomousapps.utils.Runner.build +import static com.google.common.truth.Truth.assertThat + +final class VersionCatalogSpec extends AbstractJvmSpec { + + def "version catalogs work (#gradleVersion)"() { + given: + def project = new VersionCatalogProject() + gradleProject = project.gradleProject + + when: + build(gradleVersion, gradleProject.rootDir, 'buildHealth', '-Pdependency.analysis.print.build.health=true') + + then: + assertThat(project.actualProjectAdvice()).containsExactlyElementsIn(project.expectedProjectAdvice) + + when: 'We ask about the reason using the version catalog alias' + def result = build(gradleVersion, gradleProject.rootDir, 'lib:reason', '--id', 'libs.commonCollections') + + then: 'It works' + assertThat(Colors.decolorize(result.output)).contains( + '''\ + You asked about the dependency 'org.apache.commons:commons-collections4:4.4 (libs.commonCollections)'. + You have been advised to remove this dependency from 'implementation'.'''.stripIndent() + ) + + where: + gradleVersion << gradleVersions() + } +} diff --git a/src/functionalTest/groovy/com/autonomousapps/jvm/projects/VersionCatalogProject.groovy b/src/functionalTest/groovy/com/autonomousapps/jvm/projects/VersionCatalogProject.groovy new file mode 100644 index 000000000..07d7f59a0 --- /dev/null +++ b/src/functionalTest/groovy/com/autonomousapps/jvm/projects/VersionCatalogProject.groovy @@ -0,0 +1,75 @@ +package com.autonomousapps.jvm.projects + +import com.autonomousapps.AbstractProject +import com.autonomousapps.kit.GradleProject +import com.autonomousapps.kit.Source +import com.autonomousapps.kit.SourceType +import com.autonomousapps.kit.gradle.Plugin +import com.autonomousapps.model.Advice +import com.autonomousapps.model.ProjectAdvice + +import static com.autonomousapps.AdviceHelper.* +import static com.autonomousapps.kit.gradle.Dependency.versionCatalog + +final class VersionCatalogProject extends AbstractProject { + + final GradleProject gradleProject + + VersionCatalogProject() { + this.gradleProject = build() + } + + private GradleProject build() { + def builder = newGradleProjectBuilder() + builder.withRootProject { root -> + root.withFile('gradle/libs.versions.toml', '''\ + [versions] + commonCollections = "4.4" + + [libraries] + commonCollections = { module = "org.apache.commons:commons-collections4", version.ref = "commonCollections"} + '''.stripIndent()) + } + + builder.withSubproject('lib') { c -> + c.sources = sources + c.withBuildScript { bs -> + bs.plugins = [Plugin.javaLibraryPlugin] + bs.dependencies = [ + versionCatalog('implementation', 'libs.commonCollections') + ] + } + } + + def project = builder.build() + project.writer().write() + return project + } + + private sources = [ + new Source( + SourceType.JAVA, 'Library', 'com/example/library', + """\ + package com.example.library; + + public class Library { + } + """.stripIndent() + ) + ] + + Set actualProjectAdvice() { + return actualProjectAdvice(gradleProject) + } + + private Set libAdvice = [ + Advice.ofRemove( + moduleCoordinates('org.apache.commons:commons-collections4', '4.4'), + 'implementation' + ) + ] + + final Set expectedProjectAdvice = [ + projectAdviceForDependencies(':lib', libAdvice), + ] +} diff --git a/src/main/kotlin/com/autonomousapps/DependencyAnalysisExtension.kt b/src/main/kotlin/com/autonomousapps/DependencyAnalysisExtension.kt index 374e95e6d..ad3c84b8e 100644 --- a/src/main/kotlin/com/autonomousapps/DependencyAnalysisExtension.kt +++ b/src/main/kotlin/com/autonomousapps/DependencyAnalysisExtension.kt @@ -35,6 +35,7 @@ import javax.inject.Inject */ @Suppress("MemberVisibilityCanBePrivate") open class DependencyAnalysisExtension @Inject constructor( + project: Project, objects: ObjectFactory, ) : AbstractExtension(objects) { @@ -43,7 +44,7 @@ open class DependencyAnalysisExtension @Inject constructor( override val issueHandler: IssueHandler = objects.newInstance() override val abiHandler: AbiHandler = objects.newInstance() internal val usagesHandler: UsagesHandler = objects.newInstance() - internal val dependenciesHandler: DependenciesHandler = objects.newInstance() + internal val dependenciesHandler: DependenciesHandler = objects.newInstance(project) /** * Customize how dependencies are treated. See [DependenciesHandler] for more information. @@ -83,7 +84,7 @@ open class DependencyAnalysisExtension @Inject constructor( internal fun create(project: Project): DependencyAnalysisExtension = project .extensions - .create(NAME) + .create(NAME, project) } } diff --git a/src/main/kotlin/com/autonomousapps/extension/BundleHandler.kt b/src/main/kotlin/com/autonomousapps/extension/BundleHandler.kt new file mode 100644 index 000000000..2ec6b40eb --- /dev/null +++ b/src/main/kotlin/com/autonomousapps/extension/BundleHandler.kt @@ -0,0 +1,85 @@ +package com.autonomousapps.extension + +import org.gradle.api.Named +import org.gradle.api.artifacts.MinimalExternalModuleDependency +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.provider.SetProperty +import org.gradle.kotlin.dsl.setProperty +import org.intellij.lang.annotations.Language +import javax.inject.Inject + +/** + * ``` + * bundle("kotlin-stdlib") { + * // 0 (Optional): Specify the primary entry point that the user is "supposed" to declare. + * primary("org.something:primary-entry-point") + * + * // 1: include all in group as a single logical dependency + * includeGroup("org.jetbrains.kotlin") + * + * // 2: include all supplied dependencies as a single logical dependency + * includeDependency("org.jetbrains.kotlin:kotlin-stdlib") + * includeDependency("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + * + * // 3: include all dependencies that match the regex as a single logical dependency + * include(".*kotlin-stdlib.*") + * } + * ``` + */ +abstract class BundleHandler @Inject constructor( + private val name: String, + objects: ObjectFactory, +) : Named { + + override fun getName(): String = name + + val primary: Property = objects.property(String::class.java).convention("") + val includes: SetProperty = objects.setProperty().convention(emptySet()) + + fun primary(identifier: String) { + primary.set(identifier) + primary.disallowChanges() + } + + fun primary(module: Provider) { + primary(module.identifier()) + } + + fun includeGroup(group: String) { + include("^$group:.*") + } + + fun includeGroup(module: Provider) { + includeGroup(module.group()) + } + + fun includeDependency(identifier: String) { + include("^$identifier\$") + } + + fun includeDependency(module: Provider) { + includeDependency(module.identifier()) + } + + fun include(@Language("RegExp") regex: String) { + include(regex.toRegex()) + } + + fun include(regex: Regex) { + includes.add(regex) + } + + private fun Provider.identifier(): String { + return map { "${it.group}:${it.name}" }.get() + } + + private fun Provider.group(): String { + return map { + // group is in fact @Nullable + @Suppress("USELESS_ELVIS") + it.group ?: error("No group for $it") + }.get() + } +} diff --git a/src/main/kotlin/com/autonomousapps/extension/DependenciesHandler.kt b/src/main/kotlin/com/autonomousapps/extension/DependenciesHandler.kt index fec6c1334..d3b85f561 100644 --- a/src/main/kotlin/com/autonomousapps/extension/DependenciesHandler.kt +++ b/src/main/kotlin/com/autonomousapps/extension/DependenciesHandler.kt @@ -5,12 +5,9 @@ package com.autonomousapps.extension import com.autonomousapps.internal.coordinatesOrPathMatch import com.autonomousapps.model.Coordinates import org.gradle.api.* +import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.model.ObjectFactory -import org.gradle.api.provider.Property -import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.Input -import org.gradle.kotlin.dsl.setProperty -import org.intellij.lang.annotations.Language import java.io.Serializable import javax.inject.Inject @@ -42,7 +39,10 @@ import javax.inject.Inject * } * ``` */ -abstract class DependenciesHandler @Inject constructor(objects: ObjectFactory) { +abstract class DependenciesHandler @Inject constructor( + private val project: Project, + objects: ObjectFactory, +) { val map = objects.mapProperty(String::class.java, String::class.java).convention(mutableMapOf()) val bundles = objects.domainObjectContainer(BundleHandler::class.java) @@ -59,12 +59,14 @@ abstract class DependenciesHandler @Inject constructor(objects: ObjectFactory) { includeGroup("com.google.firebase") includeGroup("com.google.android.gms") } + + withVersionCatalogs() } - companion object { + internal companion object { /** Transform [map] into lambda function. Returns requested key as value if key isn't present. */ - internal fun Map.toLambda(): (String) -> String = { s -> - getOrDefault(s, s) + fun Map.toLambda(): (String) -> String? = { s -> + get(s) } } @@ -78,6 +80,22 @@ abstract class DependenciesHandler @Inject constructor(objects: ObjectFactory) { } } + private fun withVersionCatalogs() { + val catalogs = project.extensions.findByType(VersionCatalogsExtension::class.java) ?: return + + catalogs.catalogNames.forEach { catalogName -> + val catalog = catalogs.named(catalogName) + val identifierMap = catalog.libraryAliases.associateBy { alias -> + catalog.findLibrary(alias).get().get().module.toString() + } + map.putAll(identifierMap.mapValues { (_, identifier) -> "${catalog.name}.$identifier" }) + } + } + + private fun wrapException(e: GradleException) = if (e is InvalidUserDataException) + GradleException("You must configure this project either at the root or the project level, not both", e) + else e + internal fun serializableBundles(): SerializableBundles = SerializableBundles.of(bundles) class SerializableBundles( @@ -115,58 +133,4 @@ abstract class DependenciesHandler @Inject constructor(objects: ObjectFactory) { } } } - - private fun wrapException(e: GradleException) = if (e is InvalidUserDataException) - GradleException("You must configure this project either at the root or the project level, not both", e) - else e -} - -/** - * ``` - * bundle("kotlin-stdlib") { - * // 0 (Optional): Specify the primary entry point that the user is "supposed" to declare. - * primary("org.something:primary-entry-point") - * - * // 1: include all in group as a single logical dependency - * includeGroup("org.jetbrains.kotlin") - * - * // 2: include all supplied dependencies as a single logical dependency - * includeDependency("org.jetbrains.kotlin:kotlin-stdlib") - * includeDependency("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - * - * // 3: include all dependencies that match the regex as a single logical dependency - * include(".*kotlin-stdlib.*") - * } - * ``` - */ -open class BundleHandler @Inject constructor( - private val name: String, - objects: ObjectFactory, -) : Named { - - override fun getName(): String = name - - val primary: Property = objects.property(String::class.java).convention("") - val includes: SetProperty = objects.setProperty().convention(emptySet()) - - fun primary(identifier: String) { - primary.set(identifier) - primary.disallowChanges() - } - - fun includeGroup(group: String) { - include("^$group:.*") - } - - fun includeDependency(identifier: String) { - include("^$identifier\$") - } - - fun include(@Language("RegExp") regex: String) { - include(regex.toRegex()) - } - - fun include(regex: Regex) { - includes.add(regex) - } } diff --git a/src/main/kotlin/com/autonomousapps/internal/advice/AdvicePrinter.kt b/src/main/kotlin/com/autonomousapps/internal/advice/AdvicePrinter.kt index 01c4c3ee8..f602dcad5 100644 --- a/src/main/kotlin/com/autonomousapps/internal/advice/AdvicePrinter.kt +++ b/src/main/kotlin/com/autonomousapps/internal/advice/AdvicePrinter.kt @@ -7,7 +7,7 @@ import com.autonomousapps.model.ProjectCoordinates internal class AdvicePrinter( private val dslKind: DslKind, /** Customize how dependencies are printed. */ - private val dependencyMap: (String) -> String = { it }, + private val dependencyMap: ((String) -> String?)? = null, ) { fun line(configuration: String, printableIdentifier: String, was: String = ""): String = @@ -37,7 +37,11 @@ internal class AdvicePrinter( DslKind.KOTLIN -> "\"" DslKind.GROOVY -> "'" } - "($id) { capabilities {\n${coordinates.gradleVariantIdentification.capabilities.filter { !it.endsWith(":test-fixtures") }.joinToString("") { it.requireCapability(quote) }} }}" + "($id) { capabilities {\n${ + coordinates.gradleVariantIdentification.capabilities + .filter { !it.endsWith(":test-fixtures") } + .joinToString("") { it.requireCapability(quote) } + } }}" } } } @@ -46,17 +50,18 @@ internal class AdvicePrinter( private fun Coordinates.mapped(): String { val gav = gav() - val mapped = dependencyMap(gav) + // if the map contains full GAV + val mapped = dependencyMap?.invoke(gav) ?: dependencyMap?.invoke(identifier) - return if (gav == mapped) { + return if (!mapped.isNullOrBlank()) { + // If the user is mapping, it's bring-your-own-quotes + mapped + } else { // If there's no map, include quotes when (dslKind) { - DslKind.KOTLIN -> "\"$mapped\"" - DslKind.GROOVY -> "'$mapped'" + DslKind.KOTLIN -> "\"$gav\"" + DslKind.GROOVY -> "'$gav'" } - } else { - // If the user is mapping, it's bring-your-own-quotes - mapped } } } diff --git a/src/main/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilder.kt b/src/main/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilder.kt index bd2077f48..d0b75bf29 100644 --- a/src/main/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilder.kt +++ b/src/main/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilder.kt @@ -8,7 +8,7 @@ internal class ProjectHealthConsoleReportBuilder( private val projectAdvice: ProjectAdvice, dslKind: DslKind, /** Customize how dependencies are printed. */ - dependencyMap: (String) -> String = { it }, + dependencyMap: ((String) -> String?)? = null, ) { val text: String diff --git a/src/main/kotlin/com/autonomousapps/internal/reason/DependencyAdviceExplainer.kt b/src/main/kotlin/com/autonomousapps/internal/reason/DependencyAdviceExplainer.kt index e0692716e..01173c39f 100644 --- a/src/main/kotlin/com/autonomousapps/internal/reason/DependencyAdviceExplainer.kt +++ b/src/main/kotlin/com/autonomousapps/internal/reason/DependencyAdviceExplainer.kt @@ -25,7 +25,7 @@ internal class DependencyAdviceExplainer( private val dependencyGraph: Map, private val bundleTraces: Set, private val wasFiltered: Boolean, - private val dependencyMap: (String) -> String = { it } + private val dependencyMap: ((String) -> String?)? = null ) : ReasonTask.Explainer { override fun computeReason() = buildString { @@ -166,8 +166,9 @@ internal class DependencyAdviceExplainer( private fun printableIdentifier(coordinates: Coordinates): String { val gav = coordinates.gav() - val mapped = dependencyMap(gav) - return if (gav == mapped) gav else "$gav ($mapped)" + val mapped = dependencyMap?.invoke(gav) ?: dependencyMap?.invoke(coordinates.identifier) + + return if (!mapped.isNullOrBlank()) "$gav ($mapped)" else gav } private fun ProjectCoordinates.printableName(): String { diff --git a/src/main/kotlin/com/autonomousapps/tasks/ReasonTask.kt b/src/main/kotlin/com/autonomousapps/tasks/ReasonTask.kt index b3ec36d6d..bd6c08761 100644 --- a/src/main/kotlin/com/autonomousapps/tasks/ReasonTask.kt +++ b/src/main/kotlin/com/autonomousapps/tasks/ReasonTask.kt @@ -24,7 +24,7 @@ import org.gradle.workers.WorkerExecutor import javax.inject.Inject abstract class ReasonTask @Inject constructor( - private val workerExecutor: WorkerExecutor + private val workerExecutor: WorkerExecutor, ) : DefaultTask() { init { @@ -205,10 +205,11 @@ abstract class ReasonTask @Inject constructor( fun findInGraph(): String? = dependencyGraph.values.asSequence() .flatMap { it.nodes } - .map { it.gav() } - .find { gav -> - gav == requestedId || gav.startsWith(requestedId) || dependencyMap(gav) == requestedId - } + .find { coordinates -> + val gav = coordinates.gav() + gav == requestedId || gav.startsWith("$requestedId:") || + dependencyMap(gav) == requestedId || dependencyMap(coordinates.identifier) == requestedId + }?.gav() // Guaranteed to find full GAV or throw val gavKey = dependencyUsages.entries.find(requestedId::equalsKey)?.key @@ -286,7 +287,9 @@ abstract class ReasonTask @Inject constructor( private fun validateModuleOption() { if (module != "android") { - throw InvalidUserDataException("'$module' unexpected. The only valid option for '--module' at this time is 'android'.") + throw InvalidUserDataException( + "'$module' unexpected. The only valid option for '--module' at this time is 'android'." + ) } } } @@ -294,5 +297,4 @@ abstract class ReasonTask @Inject constructor( internal interface Explainer { fun computeReason(): String } - } diff --git a/src/main/kotlin/com/autonomousapps/tasks/RewriteTask.kt b/src/main/kotlin/com/autonomousapps/tasks/RewriteTask.kt index f7b2b5ca3..165527739 100644 --- a/src/main/kotlin/com/autonomousapps/tasks/RewriteTask.kt +++ b/src/main/kotlin/com/autonomousapps/tasks/RewriteTask.kt @@ -58,7 +58,6 @@ abstract class RewriteTask : DefaultTask() { val projectAdvice = projectAdvice.fromJson() val map = dependencyMap.get() - val reversedMap = map.reversed() val rewriter = GradleBuildScriptDependenciesRewriter.newRewriter( file = buildScript.toPath(), @@ -67,7 +66,7 @@ abstract class RewriteTask : DefaultTask() { dslKind = dslKind, dependencyMap = map.toLambda() ), - reversedDependencyMap = reversedMap.toLambda() + reversedDependencyMap = { map.reversed().getOrDefault(it, it) } ) try { diff --git a/src/test/kotlin/com/autonomousapps/extension/BundleHandlerTest.kt b/src/test/kotlin/com/autonomousapps/extension/BundleHandlerTest.kt index 0add6cadf..45bc19f7c 100644 --- a/src/test/kotlin/com/autonomousapps/extension/BundleHandlerTest.kt +++ b/src/test/kotlin/com/autonomousapps/extension/BundleHandlerTest.kt @@ -1,6 +1,7 @@ package com.autonomousapps.extension import com.google.common.truth.Truth.assertThat +import org.gradle.api.model.ObjectFactory import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.Test @@ -8,7 +9,9 @@ class BundleHandlerTest { private val project = ProjectBuilder.builder().build() private val objects = project.objects - private val bundleHandler = BundleHandler("test", objects) + private val bundleHandler = RealBundleHandler("test", objects) + + private class RealBundleHandler(name: String, objects: ObjectFactory) : BundleHandler(name, objects) @Test fun includeGroup() { // I like this better, but the IDE does not comprehend it and I can't stand the red squigglies. diff --git a/src/test/kotlin/com/autonomousapps/internal/BundlesTest.kt b/src/test/kotlin/com/autonomousapps/internal/BundlesTest.kt index c441ae52b..69e4350a0 100644 --- a/src/test/kotlin/com/autonomousapps/internal/BundlesTest.kt +++ b/src/test/kotlin/com/autonomousapps/internal/BundlesTest.kt @@ -8,6 +8,7 @@ import com.autonomousapps.model.declaration.Variant import com.autonomousapps.model.intermediates.Usage import com.autonomousapps.test.usage import com.google.common.truth.Truth.assertThat +import org.gradle.api.Project import org.gradle.api.model.ObjectFactory import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.Nested @@ -18,10 +19,10 @@ class BundlesTest { private val project = ProjectBuilder.builder().build() private val objects = project.objects - private val dependenciesHandler = RealDependenciesHandler(objects) + private val dependenciesHandler = RealDependenciesHandler(project, objects) private val gvi = GradleVariantIdentification.EMPTY - private class RealDependenciesHandler(objects: ObjectFactory) : DependenciesHandler(objects) + private class RealDependenciesHandler(project: Project, objects: ObjectFactory) : DependenciesHandler(project, objects) @Nested inner class DefaultBundles { @Test fun `kotlin stdlib is a default bundle`() { diff --git a/src/test/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilderTest.kt b/src/test/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilderTest.kt index 3f25bdf9d..d0719f1b8 100644 --- a/src/test/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilderTest.kt +++ b/src/test/kotlin/com/autonomousapps/internal/advice/ProjectHealthConsoleReportBuilderTest.kt @@ -11,8 +11,7 @@ internal class ProjectHealthConsoleReportBuilderTest { private val gvi = GradleVariantIdentification.EMPTY - @Test - fun adviceOfRemoveShouldBeSorted() { + @Test fun `remove advice should be sorted`() { val dependencyAdvice = setOf( Advice.ofRemove(ModuleCoordinates("com.project.a", "1.0", gvi), "implementation"), Advice.ofRemove(ModuleCoordinates("com.project.c", "1.0", gvi), "api"), @@ -31,8 +30,7 @@ internal class ProjectHealthConsoleReportBuilderTest { ) } - @Test - fun adviceOfChangeShouldBeSorted() { + @Test fun `change advice should be sorted`() { val dependencyAdvice = setOf( Advice.ofChange(ModuleCoordinates("com.project.a", "1.0", gvi), "implementation", "api"), Advice.ofChange(ModuleCoordinates("com.project.c", "1.0", gvi), "api", "implementation"), @@ -51,8 +49,7 @@ internal class ProjectHealthConsoleReportBuilderTest { ) } - @Test - fun adviceOfAddShouldBeSorted() { + @Test fun `add advice should be sorted`() { val dependencyAdvice = setOf( Advice.ofAdd(ModuleCoordinates("com.project.a", "1.0", gvi), "implementation"), Advice.ofAdd(ModuleCoordinates("com.project.c", "1.0", gvi), "api"), diff --git a/testkit/src/main/kotlin/com/autonomousapps/kit/gradle/Dependency.kt b/testkit/src/main/kotlin/com/autonomousapps/kit/gradle/Dependency.kt index b556ee473..2ec760de3 100644 --- a/testkit/src/main/kotlin/com/autonomousapps/kit/gradle/Dependency.kt +++ b/testkit/src/main/kotlin/com/autonomousapps/kit/gradle/Dependency.kt @@ -9,6 +9,7 @@ public class Dependency @JvmOverloads constructor( private val dependency: String, private val ext: String? = null, private val capability: String? = null, + private val isVersionCatalog: Boolean = false, ) : Element.Line { private val isProject = dependency.startsWith(":") @@ -24,6 +25,9 @@ public class Dependency @JvmOverloads constructor( dependency.endsWith("()") -> "$configuration $dependency" // Some kind of custom notation !dependency.contains(":") -> "$configuration $dependency" + // version catalog reference + isVersionCatalog -> "$configuration $dependency" + // normal dependency else -> { // normal external dependencies @@ -73,6 +77,15 @@ public class Dependency @JvmOverloads constructor( * Libraries */ + @JvmStatic + public fun versionCatalog(configuration: String, ref: String): Dependency { + return Dependency( + configuration = configuration, + dependency = ref, + isVersionCatalog = true + ) + } + @JvmStatic public fun dagp(configuration: String): Dependency { val version = System.getProperty("com.autonomousapps.pluginversion")