diff options
author | Marcin Aman <marcin.aman@gmail.com> | 2021-06-21 11:44:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-21 11:44:36 +0200 |
commit | a0b77276242ec227f98bf69ed878b9d71c1c5888 (patch) | |
tree | 796cc4638808ae26a060d3f1b17f20aa117d5af0 | |
parent | 1b918994dbfe8f4d345c11c054c8b5ffc9b65cd4 (diff) | |
download | dokka-a0b77276242ec227f98bf69ed878b9d71c1c5888.tar.gz dokka-a0b77276242ec227f98bf69ed878b9d71c1c5888.tar.bz2 dokka-a0b77276242ec227f98bf69ed878b9d71c1c5888.zip |
Cachable task (#1905)
* Add tests for Gradle caching scenarios and adjust
tasks to honor caching such that tests pass
* Make dokka tasks cachable
* Make dokka tasks cachable
* Make dokka tasks cachable
* Fix gradle assertion
Co-authored-by: Volker Leck <volker.leck@gmail.com>
12 files changed, 274 insertions, 13 deletions
diff --git a/integration-tests/gradle/projects/it-basic/build.gradle.kts b/integration-tests/gradle/projects/it-basic/build.gradle.kts index 414037fe..e5abd7e1 100644 --- a/integration-tests/gradle/projects/it-basic/build.gradle.kts +++ b/integration-tests/gradle/projects/it-basic/build.gradle.kts @@ -50,5 +50,5 @@ tasks.withType<DokkaTask> { } suppressObviousFunctions.set(false) - pluginsMapConfiguration.set(mapOf(DokkaBase::class.qualifiedName to """{ "customStyleSheets": ["${file("customResources/logo-styles.css")}", "${file("customResources/custom-style-to-add.css")}"], "customAssets" : ["${file("customResources/custom-resource.svg")}"] }""")) + pluginsMapConfiguration.set(mapOf(DokkaBase::class.qualifiedName to """{ "customStyleSheets": ["${file("../customResources/logo-styles.css")}", "${file("../customResources/custom-style-to-add.css")}"], "customAssets" : ["${file("../customResources/custom-resource.svg")}"] }""")) } diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleCachingIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleCachingIntegrationTest.kt new file mode 100644 index 00000000..2bce02aa --- /dev/null +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleCachingIntegrationTest.kt @@ -0,0 +1,136 @@ +package org.jetbrains.dokka.it.gradle + +import org.gradle.util.GradleVersion +import java.io.File +import kotlin.test.* + +abstract class AbstractGradleCachingIntegrationTest(override val versions: BuildVersions): AbstractGradleIntegrationTest() { + fun setupProject(project: File) { + val templateProjectDir = File("projects", "it-basic") + project.mkdirs() + templateProjectDir.listFiles().orEmpty() + .filter { it.isFile } + .forEach { topLevelFile -> topLevelFile.copyTo(File(project, topLevelFile.name)) } + + File(templateProjectDir, "src").copyRecursively(File(project, "src")) + val customResourcesDir = File(templateProjectDir, "customResources") + if(customResourcesDir.exists() && customResourcesDir.isDirectory) { + val destination = File(project.parentFile, "customResources") + destination.mkdirs() + destination.deleteRecursively() + customResourcesDir.copyRecursively(destination) + } + + // clean local cache for each test + if (versions.gradleVersion >= GradleVersion.version("7.0")) { + //Gradle 7.0 removed the old syntax + project.toPath().resolve("settings.gradle.kts").toFile().appendText( + """ + buildCache { + local { + // Set local build cache directory. + directory = File("${projectDir.absolutePath}", "build-cache") + } + } + """.trimIndent() + ) + } else { + project.toPath().resolve("settings.gradle.kts").toFile().appendText( + """ + buildCache { + local<DirectoryBuildCache> { + // Set local build cache directory. + directory = File("${projectDir.absolutePath}", "build-cache") + } + } + """.trimIndent() + ) + } + } + + fun File.assertHtmlOutputDir() { + 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 reactFile = File(this, "scripts/main.js") + assertTrue(reactFile.isFile, "Missing main.js") + + val stylesDir = File(this, "styles") + assertTrue(stylesDir.isDirectory, "Missing styles directory") + val reactStyles = File(this, "styles/main.css") + assertTrue(reactStyles.isFile, "Missing main.css") + + 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(this, "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) + assertNoSuppressedMarker(file) + assertNoEmptyLinks(file) + assertNoEmptySpans(file) + } + + assertTrue( + allHtmlFiles().any { file -> "Basic Project" in file.readText() }, + "Expected configured moduleName to be present in html" + ) + + assertTrue( + allHtmlFiles().any { file -> + "https://github.com/Kotlin/dokka/tree/master/" + + "integration-tests/gradle/projects/it-basic/" + + "src/main/kotlin/it/basic/PublicClass.kt" in file.readText() + }, + "Expected `PublicClass` source link to GitHub" + ) + + assertTrue( + allHtmlFiles().any { file -> + "https://github.com/Kotlin/dokka/tree/master/" + + "integration-tests/gradle/projects/it-basic/" + + "src/main/java/it/basic/java/SampleJavaClass.java" in file.readText() + }, + "Expected `SampleJavaClass` source link to GitHub" + ) + + val anchorsShouldNotHaveHashes = "<a data-name=\".*#.*\"\\sanchor-label=\"*.*\">".toRegex() + assertTrue( + allHtmlFiles().all { file -> + !anchorsShouldNotHaveHashes.containsMatchIn(file.readText()) + }, + "Anchors should not have hashes inside" + ) + + assertEquals( + """#logo{background-image:url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');}""", + stylesDir.resolve("logo-styles.css").readText().replace("\\s".toRegex(), ""), + ) + assertTrue(stylesDir.resolve("custom-style-to-add.css").isFile) + assertEquals("""/* custom stylesheet */""", stylesDir.resolve("custom-style-to-add.css").readText()) + allHtmlFiles().forEach { file -> + if(file.name != "navigation.html") assertTrue("custom-style-to-add.css" in file.readText(), "custom styles not added to html file ${file.name}") + } + assertTrue(imagesDir.resolve("custom-resource.svg").isFile) + } +}
\ No newline at end of file diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicCachingIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicCachingIntegrationTest.kt new file mode 100644 index 00000000..2207a13f --- /dev/null +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicCachingIntegrationTest.kt @@ -0,0 +1,47 @@ +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 BasicCachingIntegrationTest(override val versions: BuildVersions) : AbstractGradleCachingIntegrationTest(versions) { + + companion object { + @get:JvmStatic + @get:Parameters(name = "{0}") + val versions = BuildVersions.permutations( + gradleVersions = listOf("7.0", *ifExhaustive("6.6", "6.1.1")), + kotlinVersions = listOf("1.3.30", *ifExhaustive("1.3.72", "1.4.32"), "1.5.0") + ) + BuildVersions.permutations( + gradleVersions = listOf("5.6.4", "6.0"), + kotlinVersions = listOf("1.3.30", *ifExhaustive("1.4.32")) + ) + } + + @BeforeTest + fun setupProjectFiles(){ + setupProject(projectDir) + } + + @Test + fun execute() { + runAndAssertOutcome(TaskOutcome.SUCCESS) + runAndAssertOutcome(TaskOutcome.FROM_CACHE) + } + + private fun runAndAssertOutcome(expectedOutcome: TaskOutcome) { + val result = createGradleRunner( + "clean", + "dokkaHtml", + "-i", + "-s", + "-Dorg.gradle.caching.debug=true", + "--build-cache" + ).buildRelaxed() + + assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaHtml")).outcome) + + File(projectDir, "build/dokka/html").assertHtmlOutputDir() + } +} 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 index 11f20ae8..1322356f 100644 --- 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 @@ -29,18 +29,35 @@ class BasicGradleIntegrationTest(override val versions: BuildVersions) : Abstrac File(templateProjectDir, "src").copyRecursively(File(projectDir, "src")) val customResourcesDir = File(templateProjectDir, "customResources") - if(customResourcesDir.exists() && customResourcesDir.isDirectory) customResourcesDir.copyRecursively(File(projectDir, "customResources")) + + if (customResourcesDir.exists() && customResourcesDir.isDirectory) { + val destination = File(projectDir.parentFile, "customResources") + destination.mkdirs() + destination.deleteRecursively() + customResourcesDir.copyRecursively(destination) + } } @Test fun execute() { - val result = createGradleRunner("dokkaHtml", "dokkaJavadoc", "dokkaGfm", "dokkaJekyll", "-i", "-s") - .buildRelaxed() + runAndAssertOutcome(TaskOutcome.SUCCESS) + runAndAssertOutcome(TaskOutcome.UP_TO_DATE) + } - 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) + private fun runAndAssertOutcome(expectedOutcome: TaskOutcome) { + val result = createGradleRunner( + "dokkaHtml", + "dokkaJavadoc", + "dokkaGfm", + "dokkaJekyll", + "-i", + "-s" + ).buildRelaxed() + + assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaHtml")).outcome) + assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaJavadoc")).outcome) + assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaGfm")).outcome) + assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaJekyll")).outcome) File(projectDir, "build/dokka/html").assertHtmlOutputDir() File(projectDir, "build/dokka/javadoc").assertJavadocOutputDir() @@ -129,7 +146,10 @@ class BasicGradleIntegrationTest(override val versions: BuildVersions) : Abstrac assertTrue(stylesDir.resolve("custom-style-to-add.css").isFile) assertEquals("""/* custom stylesheet */""", stylesDir.resolve("custom-style-to-add.css").readText()) allHtmlFiles().forEach { file -> - if(file.name != "navigation.html") assertTrue("custom-style-to-add.css" in file.readText(), "custom styles not added to html file ${file.name}") + if (file.name != "navigation.html") assertTrue( + "custom-style-to-add.css" in file.readText(), + "custom styles not added to html file ${file.name}" + ) } assertTrue(imagesDir.resolve("custom-resource.svg").isFile) } diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/GradleRelocatedCachingIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/GradleRelocatedCachingIntegrationTest.kt new file mode 100644 index 00000000..d82c3827 --- /dev/null +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/GradleRelocatedCachingIntegrationTest.kt @@ -0,0 +1,45 @@ +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 GradleRelocatedCachingIntegrationTest(override val versions: BuildVersions) : AbstractGradleCachingIntegrationTest(versions) { + + companion object { + @get:JvmStatic + @get:Parameters(name = "{0}") + val versions = BuildVersions.permutations( + gradleVersions = listOf("7.0", *ifExhaustive("6.6", "6.1.1")), + kotlinVersions = listOf("1.3.30", *ifExhaustive("1.3.72", "1.4.32"), "1.5.0") + ) + BuildVersions.permutations( + gradleVersions = listOf("5.6.4", "6.0"), + kotlinVersions = listOf("1.3.30", *ifExhaustive("1.4.32")) + ) + } + + @BeforeTest + fun prepareProjectFiles() { + setupProject(projectFolder(1)) + setupProject(projectFolder(2)) + } + + @Test + fun execute() { + runAndAssertOutcome(projectFolder(1), TaskOutcome.SUCCESS) + runAndAssertOutcome(projectFolder(2), TaskOutcome.FROM_CACHE) + } + + private fun runAndAssertOutcome(project: File, expectedOutcome: TaskOutcome) { + val result = createGradleRunner("clean", "dokkaHtml", "-i", "-s", "-Dorg.gradle.caching.debug=true", "--build-cache") + .withProjectDir(project) + .buildRelaxed() + + assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaHtml")).outcome) + + File(project, "build/dokka/html").assertHtmlOutputDir() + } + + private fun projectFolder(index: Int) = File(projectDir.absolutePath + index) +} diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt index c3217722..f9f48404 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt @@ -37,6 +37,7 @@ abstract class AbstractDokkaTask : DefaultTask() { @Optional @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) val cacheRoot: Property<File?> = project.objects.safeProperty() @Input diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt index cfe56d52..68c4181c 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt @@ -1,7 +1,9 @@ package org.jetbrains.dokka.gradle +import org.gradle.api.tasks.CacheableTask import org.jetbrains.dokka.DokkaConfigurationImpl +@CacheableTask abstract class DokkaCollectorTask : AbstractDokkaParentTask() { override fun generateDocumentation() { diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt index b0683204..de503476 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt @@ -14,9 +14,11 @@ typealias DokkaMultimoduleTask = DokkaMultiModuleTask private typealias TaskPath = String +@CacheableTask abstract class DokkaMultiModuleTask : AbstractDokkaParentTask() { @InputFiles @Optional + @PathSensitive(PathSensitivity.RELATIVE) val includes: ConfigurableFileCollection = project.files() @Internal @@ -24,6 +26,7 @@ abstract class DokkaMultiModuleTask : AbstractDokkaParentTask() { .safeConvention(DokkaMultiModuleFileLayout.CompactInParent) @get:InputFiles + @get:PathSensitive(PathSensitivity.RELATIVE) internal val sourceChildOutputDirectories: Iterable<File> get() = childDokkaTasks.map { task -> task.outputDirectory.getSafe() } diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt index 682b2591..6bb946c3 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt @@ -2,7 +2,9 @@ package org.jetbrains.dokka.gradle import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.build +import org.gradle.api.tasks.* +@CacheableTask abstract class DokkaTask : AbstractDokkaLeafTask() { override fun buildDokkaConfiguration(): DokkaConfigurationImpl = DokkaConfigurationImpl( diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTaskPartial.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTaskPartial.kt index ce779c99..eaee68a2 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTaskPartial.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTaskPartial.kt @@ -2,7 +2,9 @@ package org.jetbrains.dokka.gradle import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.build +import org.gradle.api.tasks.* +@CacheableTask abstract class DokkaTaskPartial : AbstractDokkaLeafTask() { override fun buildDokkaConfiguration(): DokkaConfigurationImpl { diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt index 70d84dc4..de8eed77 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt @@ -38,6 +38,7 @@ open class GradleDokkaSourceSetBuilder( val displayName: Property<String?> = project.objects.safeProperty() @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) val sourceRoots: ConfigurableFileCollection = project.objects.fileCollection() @Input @@ -46,10 +47,12 @@ open class GradleDokkaSourceSetBuilder( @InputFiles @Optional + @PathSensitive(PathSensitivity.RELATIVE) val samples: ConfigurableFileCollection = project.files() @InputFiles @Optional + @PathSensitive(PathSensitivity.RELATIVE) val includes: ConfigurableFileCollection = project.files() @Input @@ -111,6 +114,7 @@ open class GradleDokkaSourceSetBuilder( .safeConvention(false) @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) val suppressedFiles: ConfigurableFileCollection = project.files() @Input diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt index e84bfd2c..6dec5f89 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt @@ -2,9 +2,7 @@ package org.jetbrains.dokka.gradle import org.gradle.api.Project import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.* import org.jetbrains.dokka.DokkaConfigurationBuilder import org.jetbrains.dokka.SourceLinkDefinitionImpl import java.io.File @@ -14,7 +12,8 @@ class GradleSourceLinkBuilder( @Transient @get:Internal internal val project: Project ) : DokkaConfigurationBuilder<SourceLinkDefinitionImpl> { - @Input + @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) val localDirectory: Property<File?> = project.objects.safeProperty() @Input |