aboutsummaryrefslogtreecommitdiff
path: root/integration-tests/gradle/src
diff options
context:
space:
mode:
Diffstat (limited to 'integration-tests/gradle/src')
-rw-r--r--integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt77
-rw-r--r--integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt99
-rw-r--r--integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt98
-rw-r--r--integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multimodule0IntegrationTest.kt61
-rw-r--r--integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt43
-rw-r--r--integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt74
-rw-r--r--integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt48
7 files changed, 500 insertions, 0 deletions
diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt
new file mode 100644
index 00000000..2a9d7a70
--- /dev/null
+++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt
@@ -0,0 +1,77 @@
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.jetbrains.dokka.it.isAndroidSdkInstalled
+import org.jetbrains.dokka.it.isCI
+import org.junit.Assume
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+import kotlin.test.*
+
+class Android0GradleIntegrationTest(override val versions: BuildVersions) : AbstractGradleIntegrationTest() {
+
+ companion object {
+ @get:JvmStatic
+ @get:Parameters(name = "{0}")
+ val versions = BuildVersions.permutations(
+ gradleVersions = listOf("6.5.1", "5.6.4"),
+ kotlinVersions = listOf("1.3.72", "1.4-M3"),
+ androidGradlePluginVersions = listOf("3.5.3", "3.6.3")
+ ) + BuildVersions.permutations(
+ gradleVersions = listOf("6.5.1", "6.1.1"),
+ kotlinVersions = listOf("1.3.72", "1.4-M3"),
+ androidGradlePluginVersions = listOf("4.0.0")
+ ) + BuildVersions.permutations(
+ gradleVersions = listOf("6.5.1"),
+ kotlinVersions = listOf("1.3.72", "1.4-M3"),
+ androidGradlePluginVersions = listOf("4.1.0-beta02")
+ )
+ }
+
+ @BeforeTest
+ fun assumeAndroidInstallation() {
+ if (isCI) {
+ return
+ }
+ Assume.assumeTrue("Missing ANDROID_SDK_ROOT", isAndroidSdkInstalled)
+ }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-android-0")
+
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .filterNot { it.name == "local.properties" }
+ .filterNot { it.name.startsWith("gradlew") }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ }
+
+ @Test
+ fun execute() {
+ val result = createGradleRunner("dokkaHtml", "-i", "-s").buildRelaxed()
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtml")).outcome)
+
+ val htmlOutputDir = File(projectDir, "build/dokka/html")
+ assertTrue(htmlOutputDir.isDirectory, "Missing html output directory")
+
+ assertTrue(
+ htmlOutputDir.allHtmlFiles().count() > 0,
+ "Expected html files in html output directory"
+ )
+
+ htmlOutputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLInks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ }
+
+ assertTrue(
+ htmlOutputDir.allHtmlFiles().any { file ->
+ "https://developer.android.com/reference/android/content/Context.html" in file.readText()
+ }, "Expected link to developer.android.com"
+ )
+ }
+}
diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt
new file mode 100644
index 00000000..30b560e7
--- /dev/null
+++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt
@@ -0,0 +1,99 @@
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+import kotlin.test.*
+
+class BasicGradleIntegrationTest(override val versions: BuildVersions) : AbstractGradleIntegrationTest() {
+
+ companion object {
+ @get:JvmStatic
+ @get:Parameters(name = "{0}")
+ val versions = BuildVersions.permutations(
+ gradleVersions = listOf("6.5.1", "6.4.1", "6.3", "6.2.2", "6.1.1", "6.0", "5.6.4"),
+ kotlinVersions = listOf("1.3.30", "1.3.72", "1.4-M3")
+ )
+ }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-basic")
+
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ }
+
+ @Test
+ fun execute() {
+ val result = createGradleRunner("dokkaHtml", "dokkaJavadoc", "dokkaGfm", "dokkaJekyll", "-i", "-s")
+ .buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtml")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaJavadoc")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaGfm")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaJekyll")).outcome)
+
+ File(projectDir, "build/dokka/html").assertKdocOutputDir()
+ File(projectDir, "build/dokka/javadoc").assertJavadocOutputDir()
+ File(projectDir, "build/dokka/gfm").assertGfmOutputDir()
+ File(projectDir, "build/dokka/jekyll").assertJekyllOutputDir()
+ }
+
+ private fun File.assertKdocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka html output directory")
+
+ val imagesDir = File(this, "images")
+ assertTrue(imagesDir.isDirectory, "Missing images directory")
+
+ val scriptsDir = File(this, "scripts")
+ assertTrue(scriptsDir.isDirectory, "Missing scripts directory")
+
+ val stylesDir = File(this, "styles")
+ assertTrue(stylesDir.isDirectory, "Missing styles directory")
+
+ val navigationHtml = File(this, "navigation.html")
+ assertTrue(navigationHtml.isFile, "Missing navigation.html")
+
+ val moduleOutputDir = File(this, "-basic -project")
+ assertTrue(moduleOutputDir.isDirectory, "Missing module directory")
+
+ val moduleIndexHtml = File(moduleOutputDir, "index.html")
+ assertTrue(moduleIndexHtml.isFile, "Missing module index.html")
+
+ val modulePackageDir = File(moduleOutputDir, "it.basic")
+ assertTrue(modulePackageDir.isDirectory, "Missing it.basic package directory")
+
+ val modulePackageIndexHtml = File(modulePackageDir, "index.html")
+ assertTrue(modulePackageIndexHtml.isFile, "Missing module package index.html")
+
+ val moduleJavaPackageDir = File(moduleOutputDir, "it.basic.java")
+ assertTrue(moduleJavaPackageDir.isDirectory, "Missing it.basic.java package directory")
+
+ allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLInks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ }
+
+ assertTrue(
+ allHtmlFiles().any { file -> "Basic Project" in file.readText() },
+ "Expected configured moduleDisplayName to be present in html"
+ )
+ }
+
+ private fun File.assertJavadocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka javadoc output directory")
+ }
+
+ private fun File.assertGfmOutputDir() {
+ assertTrue(isDirectory, "Missing dokka gfm output directory")
+ }
+
+ private fun File.assertJekyllOutputDir() {
+ assertTrue(isDirectory, "Missing dokka jekyll output directory")
+ }
+}
diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt
new file mode 100644
index 00000000..92b7ec40
--- /dev/null
+++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt
@@ -0,0 +1,98 @@
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.runners.Parameterized
+import java.io.File
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+import kotlin.test.BeforeTest
+import kotlin.test.Test
+
+class BasicGroovyIntegrationTest(override val versions: BuildVersions) : AbstractGradleIntegrationTest() {
+
+ companion object {
+ @get:JvmStatic
+ @get:Parameterized.Parameters(name = "{0}")
+ val versions = BuildVersions.permutations(
+ gradleVersions = listOf("6.5.1", "5.6.4"),
+ kotlinVersions = listOf("1.4-M3")
+ )
+ }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-basic-groovy")
+
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ }
+
+ @Test
+ fun execute() {
+ val result = createGradleRunner("dokkaHtml", "dokkaJavadoc", "dokkaGfm", "dokkaJekyll", "-i", "-s")
+ .buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtml")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaJavadoc")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaGfm")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaJekyll")).outcome)
+
+ File(projectDir, "build/dokka/customHtml").assertKdocOutputDir()
+ File(projectDir, "build/dokka/customJavadoc").assertJavadocOutputDir()
+ File(projectDir, "build/dokka/customGfm").assertGfmOutputDir()
+ File(projectDir, "build/dokka/customJekyll").assertJekyllOutputDir()
+ }
+
+ private fun File.assertKdocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka html output directory")
+
+ val imagesDir = File(this, "images")
+ assertTrue(imagesDir.isDirectory, "Missing images directory")
+
+ val scriptsDir = File(this, "scripts")
+ assertTrue(scriptsDir.isDirectory, "Missing scripts directory")
+
+ val stylesDir = File(this, "styles")
+ assertTrue(stylesDir.isDirectory, "Missing styles directory")
+
+ val navigationHtml = File(this, "navigation.html")
+ assertTrue(navigationHtml.isFile, "Missing navigation.html")
+
+ val moduleOutputDir = File(this, "it-basic-groovy")
+ assertTrue(moduleOutputDir.isDirectory, "Missing module directory")
+
+ val moduleIndexHtml = File(moduleOutputDir, "index.html")
+ assertTrue(moduleIndexHtml.isFile, "Missing module index.html")
+
+ val modulePackageDir = File(moduleOutputDir, "it.basic")
+ assertTrue(modulePackageDir.isDirectory, "Missing it.basic package directory")
+
+ val modulePackageIndexHtml = File(modulePackageDir, "index.html")
+ assertTrue(modulePackageIndexHtml.isFile, "Missing module package index.html")
+
+ val moduleJavaPackageDir = File(moduleOutputDir, "it.basic.java")
+ assertTrue(moduleJavaPackageDir.isDirectory, "Missing it.basic.java package directory")
+
+ allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLInks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ }
+ }
+
+ private fun File.assertJavadocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka javadoc output directory")
+ }
+
+ private fun File.assertGfmOutputDir() {
+ assertTrue(isDirectory, "Missing dokka gfm output directory")
+ }
+
+ private fun File.assertJekyllOutputDir() {
+ assertTrue(isDirectory, "Missing dokka jekyll output directory")
+ }
+}
diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multimodule0IntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multimodule0IntegrationTest.kt
new file mode 100644
index 00000000..390db3a0
--- /dev/null
+++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multimodule0IntegrationTest.kt
@@ -0,0 +1,61 @@
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.runners.Parameterized
+import java.io.File
+import kotlin.test.*
+
+class Multimodule0IntegrationTest(override val versions: BuildVersions) : AbstractGradleIntegrationTest() {
+ companion object {
+ @get:JvmStatic
+ @get:Parameterized.Parameters(name = "{0}")
+ val versions = BuildVersions.permutations(
+ gradleVersions = listOf("6.5.1", "6.1.1"),
+ kotlinVersions = listOf("1.4-M3")
+ )
+ }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-multimodule-0")
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+ File(templateProjectDir, "moduleA").copyRecursively(File(projectDir, "moduleA"))
+ }
+
+ @Test
+ fun execute() {
+ val result = createGradleRunner(":moduleA:dokkaHtmlMultimodule", "-i","-s").buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaHtmlMultimodule")).outcome)
+
+ val outputDir = File(projectDir, "moduleA/build/dokka/htmlMultimodule")
+ assertTrue(outputDir.isDirectory, "Missing dokka output directory")
+
+ assertTrue(
+ outputDir.allHtmlFiles().any(),
+ "Expected at least one html file being generated"
+ )
+
+ outputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLInks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ }
+
+ val modulesFile = File(outputDir, "-modules.html")
+ assertTrue(modulesFile.isFile, "Missing -modules.html file")
+
+ val modulesFileText = modulesFile.readText()
+ assertTrue(
+ "moduleB" in modulesFileText,
+ "Expected moduleB being mentioned in -modules.html"
+ )
+ assertTrue(
+ "moduleC" in modulesFileText,
+ "Expected moduleC being mentioned in -modules.html"
+ )
+
+ }
+}
diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt
new file mode 100644
index 00000000..6a3b9c83
--- /dev/null
+++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt
@@ -0,0 +1,43 @@
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.runners.Parameterized
+import java.io.File
+import kotlin.test.*
+
+class Multiplatform0GradleIntegrationTest(override val versions: BuildVersions) : AbstractGradleIntegrationTest() {
+
+ companion object {
+ @get:JvmStatic
+ @get:Parameterized.Parameters(name = "{0}")
+ val versions = BuildVersions.permutations(
+ gradleVersions = listOf("6.5.1", "6.1.1"),
+ kotlinVersions = listOf("1.3.30", "1.3.72", "1.4-M3")
+ )
+ }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-multiplatform-0")
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ }
+
+ @Test
+ fun execute() {
+ val result = createGradleRunner("dokkaHtml", "-i", "-s").buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtml")).outcome)
+
+ val dokkaOutputDir = File(projectDir, "build/dokka/html")
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+
+ dokkaOutputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLInks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ }
+ }
+}
diff --git a/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt b/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt
new file mode 100644
index 00000000..f852dc8b
--- /dev/null
+++ b/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt
@@ -0,0 +1,74 @@
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.internal.DefaultGradleRunner
+import org.gradle.tooling.GradleConnectionException
+import org.jetbrains.dokka.it.AbstractIntegrationTest
+import org.junit.Assume
+import org.junit.Assume.assumeFalse
+import org.junit.AssumptionViolatedException
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.io.File
+import kotlin.test.BeforeTest
+
+@RunWith(Parameterized::class)
+abstract class AbstractGradleIntegrationTest : AbstractIntegrationTest() {
+
+ abstract val versions: BuildVersions
+
+ @BeforeTest
+ fun copyTemplates() {
+ File("projects").listFiles().orEmpty()
+ .filter { it.isFile }
+ .filter { it.name.startsWith("template.") }
+ .forEach { file -> file.copyTo(File(temporaryTestFolder.root, file.name)) }
+ }
+
+ fun createGradleRunner(
+ vararg arguments: String
+ ): GradleRunner {
+ return GradleRunner.create()
+ .withProjectDir(projectDir)
+ .withGradleVersion(versions.gradleVersion.version)
+ .forwardOutput()
+ .withTestKitDir(File("build", "gradle-test-kit").absoluteFile)
+ .withArguments(
+ listOfNotNull(
+ "-Pkotlin_version=${versions.kotlinVersion}",
+ "-Pdokka_it_kotlin_version=${versions.kotlinVersion}",
+ versions.androidGradlePluginVersion?.let { androidVersion ->
+ "-Pdokka_it_android_gradle_plugin_version=$androidVersion"
+ },
+ * arguments
+ )
+ ).run { this as DefaultGradleRunner }
+ .withJvmArguments("-Xmx4G", "-XX:MaxMetaspaceSize=2G")
+ }
+
+ fun GradleRunner.buildRelaxed(): BuildResult {
+ return try {
+ build()
+ } catch (e: Throwable) {
+ val gradleConnectionException = e.withAllCauses().find { it is GradleConnectionException }
+ if (gradleConnectionException != null) {
+ gradleConnectionException.printStackTrace()
+ throw AssumptionViolatedException("Assumed Gradle connection", gradleConnectionException)
+
+ }
+ throw e
+ }
+ }
+}
+
+private fun Throwable.withAllCauses(): Sequence<Throwable> {
+ val root = this
+ return sequence {
+ yield(root)
+ val cause = root.cause
+ if (cause != null && cause != root) {
+ yieldAll(cause.withAllCauses())
+ }
+ }
+}
diff --git a/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt b/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt
new file mode 100644
index 00000000..84a7f1e8
--- /dev/null
+++ b/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt
@@ -0,0 +1,48 @@
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.util.GradleVersion
+
+data class BuildVersions(
+ val gradleVersion: GradleVersion,
+ val kotlinVersion: String,
+ val androidGradlePluginVersion: String? = null,
+) {
+ constructor(
+ gradleVersion: String,
+ kotlinVersion: String,
+ androidGradlePluginVersion: String? = null
+ ) : this(
+ gradleVersion = GradleVersion.version(gradleVersion),
+ kotlinVersion = kotlinVersion,
+ androidGradlePluginVersion = androidGradlePluginVersion
+ )
+
+ override fun toString(): String {
+ return buildString {
+ append("Gradle ${gradleVersion.version}, Kotlin $kotlinVersion")
+ if (androidGradlePluginVersion != null) {
+ append(", Android $androidGradlePluginVersion")
+ }
+ }
+ }
+
+ companion object {
+ fun permutations(
+ gradleVersions: List<String>,
+ kotlinVersions: List<String>,
+ androidGradlePluginVersions: List<String?> = listOf(null)
+ ): List<BuildVersions> {
+ return gradleVersions.distinct().flatMap { gradleVersion ->
+ kotlinVersions.distinct().flatMap { kotlinVersion ->
+ androidGradlePluginVersions.distinct().map { androidVersion ->
+ BuildVersions(
+ gradleVersion = gradleVersion,
+ kotlinVersion = kotlinVersion,
+ androidGradlePluginVersion = androidVersion
+ )
+ }
+ }
+ }
+ }
+ }
+}