Skip to content

Commit

Permalink
Update CLI Integration Tests to use JVM Test Suites (#3580)
Browse files Browse the repository at this point in the history
* Part of KT-64200

- Migrate the CLI integration tests away from the custom integration test convention (which are not build-cache compatible) to use JVM Test Suites.
- Remove shadowing, replace with passing in the JARs via system properties. (a custom CommandLineArgumentProvider is confusing and overly complicated, but it's required to satisfy Gradle input normalization, so that the build-cache can be re-used.)
- Simplify `processUtils.kt` - the coroutines logic isn't necessary since the entrypoint just used `runBlocking {}`.
- move `jsonBuilder.kt` test-util into `src/main`, since it's not a test
- Rename `CliIntegrationTest` to `CliTest` (it wasn't an integration test, and the name was confusing compared to the actual `CliIntegrationTest`)

* fix dokkaCli dependency resolution

* exclude transitives from dokkaPluginsClasspath

* create a dokka-config.json for each test in the temp directory, don't re-write a shared file in resources

* add ticket to TODO

* rm check fix

* revert build.gradle.kts

* re-add `required dependencies of plugin-base` comment

* incrementally print stdout from Process

* rm unnecessary coroutines dependency
  • Loading branch information
adam-enko committed May 7, 2024
1 parent 7b18f65 commit bf056d6
Show file tree
Hide file tree
Showing 13 changed files with 233 additions and 204 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import dokkabuild.utils.declarable
import dokkabuild.utils.resolvable
import org.gradle.api.attributes.Bundling.BUNDLING_ATTRIBUTE
import org.gradle.api.attributes.Bundling.SHADOWED
import org.gradle.api.attributes.Usage.JAVA_RUNTIME
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE


val dokkaCli: Configuration by configurations.creating {
description = "Dependency on Dokka CLI JAR. Must only contain a single dependency."
declarable()
}

val dokkaCliResolver: Configuration by configurations.creating {
description = "Resolve the Dokka CLI JAR. Intransitive - must only contain a single JAR."
resolvable()
extendsFrom(dokkaCli)
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
attribute(BUNDLING_ATTRIBUTE, objects.named(SHADOWED))
}
// we should have single artifact here
isTransitive = false
}


val dokkaPluginsClasspath: Configuration by configurations.creating {
description = "Dokka CLI runtime dependencies required to run Dokka CLI, and its plugins."
declarable()
}

val dokkaPluginsClasspathResolver: Configuration by configurations.creating {
description = "Resolve Dokka CLI runtime dependencies required to run Dokka CLI, and its plugins. " +
"Transitive dependencies are excluded, and so must be defined explicitly."
resolvable()
extendsFrom(dokkaPluginsClasspath)
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
}
// we don't fetch transitive dependencies here to be able to control external dependencies explicitly
isTransitive = false
}
118 changes: 64 additions & 54 deletions dokka-integration-tests/cli/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,79 +1,89 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("UnstableApiUsage")

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.attributes.Bundling.BUNDLING_ATTRIBUTE
import org.gradle.api.attributes.Bundling.SHADOWED

plugins {
id("dokkabuild.test-integration")
id("com.github.johnrengelman.shadow")
id("dokkabuild.kotlin-jvm")
id("dokkabuild.test-cli-dependencies")
`jvm-test-suite`
}

dependencies {
implementation(kotlin("test-junit5"))
implementation(libs.junit.jupiterApi)
implementation(projects.utilities)
}
api(kotlin("test-junit5"))
api(libs.junit.jupiterApi)
api(projects.utilities)

val cliPluginsClasspath: Configuration by configurations.creating {
description = "plugins/dependencies required to run CLI with base plugin"
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
}
dokkaCli("org.jetbrains.dokka:runner-cli")

// we don't fetch transitive dependencies here to be able to control external dependencies explicitly
isTransitive = false
}
//region required dependencies of plugin-base
dokkaPluginsClasspath("org.jetbrains.dokka:plugin-base")
dokkaPluginsClasspath(libs.kotlinx.html)
dokkaPluginsClasspath(libs.freemarker)

val cliClasspath: Configuration by configurations.creating {
description = "dependency on CLI JAR"
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
val analysisDependency = dokkaBuild.integrationTestUseK2.map { useK2 ->
if (useK2) {
"org.jetbrains.dokka:analysis-kotlin-symbols"
} else {
"org.jetbrains.dokka:analysis-kotlin-descriptors"
}
}
dokkaPluginsClasspath(analysisDependency) {
attributes {
attribute(BUNDLING_ATTRIBUTE, project.objects.named(SHADOWED))
}
}
// we should have single artifact here
isTransitive = false
//endregion
}

dependencies {
cliClasspath("org.jetbrains.dokka:runner-cli")

cliPluginsClasspath("org.jetbrains.dokka:plugin-base")
// required dependencies of `plugin-base`
cliPluginsClasspath(libs.freemarker)
cliPluginsClasspath(libs.kotlinx.html)

val tryK2 = project.providers
.gradleProperty("org.jetbrains.dokka.experimental.tryK2")
.map(String::toBoolean)
.orNull ?: false
/**
* Provide files required for running Dokka CLI in a build cache friendly way.
*/
abstract class DokkaCliClasspathProvider : CommandLineArgumentProvider {
@get:Classpath
abstract val dokkaCli: ConfigurableFileCollection

val analysisDependency = when {
tryK2 -> "org.jetbrains.dokka:analysis-kotlin-symbols"
else -> "org.jetbrains.dokka:analysis-kotlin-descriptors"
}
@get:Classpath
abstract val dokkaPluginsClasspath: ConfigurableFileCollection

cliPluginsClasspath(analysisDependency) {
attributes {
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
override fun asArguments(): Iterable<String> = buildList {
require(dokkaCli.count() == 1) {
"Expected a single Dokka CLI JAR, but got ${dokkaCli.count()}"
}
add("-D" + "dokkaCliJarPath=" + dokkaCli.singleFile.absolutePath)
add("-D" + "dokkaPluginsClasspath=" + dokkaPluginsClasspath.joinToString(";") { it.absolutePath })
}
}

val cliPluginsShadowJar by tasks.registering(ShadowJar::class) {
archiveFileName.set("cli-plugins-${project.version}.jar")
configurations = listOf(cliPluginsClasspath)

// service files are merged to make sure all Dokka plugins
// from the dependencies are loaded, and not just a single one.
mergeServiceFiles()
}
testing {
suites {
withType<JvmTestSuite>().configureEach {
useJUnitJupiter()
}

tasks.integrationTest {
dependsOn(cliClasspath)
dependsOn(cliPluginsShadowJar)
register<JvmTestSuite>("integrationTest") {
dependencies {
implementation(project())
}

targets.configureEach {
testTask.configure {
jvmArgumentProviders.add(
objects.newInstance<DokkaCliClasspathProvider>().apply {
dokkaCli.from(configurations.dokkaCliResolver)
dokkaPluginsClasspath.from(configurations.dokkaPluginsClasspathResolver)
}
)
}
}
}
}
}

inputs.dir(file("projects"))
environment("CLI_JAR_PATH", cliClasspath.singleFile)
environment("BASE_PLUGIN_JAR_PATH", cliPluginsShadowJar.get().archiveFile.get())
tasks.check {
dependsOn(testing.suites)
}

0 comments on commit bf056d6

Please sign in to comment.