aboutsummaryrefslogtreecommitdiff
path: root/build-logic/src
diff options
context:
space:
mode:
authorGoooler <wangzongler@gmail.com>2023-03-13 21:51:31 +0800
committerGitHub <noreply@github.com>2023-03-13 14:51:31 +0100
commit3ea414251d32108dab8b14d41a672e9834824690 (patch)
tree5f7a62f60e3d90ee97989cff8e5d748b180d091b /build-logic/src
parent7a46cd329ac6ccbdb10195310197289947ee4104 (diff)
downloaddokka-3ea414251d32108dab8b14d41a672e9834824690.tar.gz
dokka-3ea414251d32108dab8b14d41a672e9834824690.tar.bz2
dokka-3ea414251d32108dab8b14d41a672e9834824690.zip
Migrate buildSrc to composite build (#2912)
Diffstat (limited to 'build-logic/src')
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/CrossPlatformExec.kt63
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/DokkaPublicationChannel.kt62
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/DokkaVersion.kt19
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/DokkaVersionType.kt8
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/SetupMaven.kt45
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/ValidatePublications.kt79
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/conventions/base-java.gradle.kts22
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/conventions/base.gradle.kts12
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/conventions/dokka-integration-test.gradle.kts75
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/conventions/dokka.gradle.kts13
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/conventions/kotlin-jvm.gradle.kts32
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/conventions/maven-publish.gradle.kts30
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/projectUtils.kt16
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/publication.kt152
-rw-r--r--build-logic/src/main/kotlin/org/jetbrains/taskUtils.kt22
15 files changed, 650 insertions, 0 deletions
diff --git a/build-logic/src/main/kotlin/org/jetbrains/CrossPlatformExec.kt b/build-logic/src/main/kotlin/org/jetbrains/CrossPlatformExec.kt
new file mode 100644
index 00000000..715dde2f
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/CrossPlatformExec.kt
@@ -0,0 +1,63 @@
+package org.jetbrains
+
+import org.gradle.api.tasks.AbstractExecTask
+import org.gradle.internal.os.OperatingSystem
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.Paths
+
+open class CrossPlatformExec : AbstractExecTask<CrossPlatformExec>(CrossPlatformExec::class.java) {
+ private val windowsExtensions = listOf(".bat", ".cmd", ".exe")
+ private val unixExtensions = listOf("", ".sh")
+
+ private val isWindows = OperatingSystem.current().isWindows
+
+ override fun exec() {
+ val commandLine: MutableList<String> = this.commandLine
+
+ if (commandLine.isNotEmpty()) {
+ commandLine[0] = findCommand(commandLine[0])
+ }
+
+ if (isWindows && commandLine.isNotEmpty() && commandLine[0].isNotBlank()) {
+ this.commandLine = listOf("cmd", "/c") + commandLine
+ } else {
+ this.commandLine = commandLine
+ }
+
+ super.exec()
+ }
+
+ private fun findCommand(command: String): String {
+ val normalizedCommand = normalizeCommandPaths(command)
+ val extensions = if (isWindows) windowsExtensions else unixExtensions
+
+ return extensions.map { extension ->
+ resolveCommandFromFile(Paths.get("$normalizedCommand$extension"))
+ }.firstOrNull { it.isNotBlank() } ?: normalizedCommand
+ }
+
+ private fun resolveCommandFromFile(commandFile: Path) =
+ if (!Files.isExecutable(commandFile)) {
+ ""
+ } else {
+ commandFile.toAbsolutePath().normalize().toString()
+ }
+
+
+ private fun normalizeCommandPaths(command: String): String {
+ // need to escape backslash so it works with regex
+ val backslashSeparator = "\\"
+ val forwardSlashSeparator = "/"
+
+ // get the actual separator
+ val separator = if (File.separatorChar == '\\') backslashSeparator else File.separator
+
+ return command
+ // first replace all of the backslashes with forward slashes
+ .replace(backslashSeparator, forwardSlashSeparator)
+ // then replace all forward slashes with whatever the separator actually is
+ .replace(forwardSlashSeparator, separator)
+ }
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/DokkaPublicationChannel.kt b/build-logic/src/main/kotlin/org/jetbrains/DokkaPublicationChannel.kt
new file mode 100644
index 00000000..03f607e8
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/DokkaPublicationChannel.kt
@@ -0,0 +1,62 @@
+@file:Suppress("LocalVariableName")
+
+package org.jetbrains
+
+import org.gradle.api.Project
+
+enum class DokkaPublicationChannel {
+ SPACE_DOKKA_DEV,
+ MAVEN_CENTRAL,
+ MAVEN_CENTRAL_SNAPSHOT,
+ GRADLE_PLUGIN_PORTAL;
+
+ val acceptedDokkaVersionTypes: List<DokkaVersionType>
+ get() = when(this) {
+ MAVEN_CENTRAL -> listOf(DokkaVersionType.RELEASE, DokkaVersionType.RC)
+ MAVEN_CENTRAL_SNAPSHOT -> listOf(DokkaVersionType.SNAPSHOT)
+ SPACE_DOKKA_DEV -> listOf(DokkaVersionType.RELEASE, DokkaVersionType.RC, DokkaVersionType.DEV, DokkaVersionType.SNAPSHOT)
+ GRADLE_PLUGIN_PORTAL -> listOf(DokkaVersionType.RELEASE, DokkaVersionType.RC)
+ }
+
+ fun isSpaceRepository() = this == SPACE_DOKKA_DEV
+
+ fun isMavenRepository() = this == MAVEN_CENTRAL || this == MAVEN_CENTRAL_SNAPSHOT
+
+ fun isGradlePluginPortal() = this == GRADLE_PLUGIN_PORTAL
+
+ companion object {
+ fun fromPropertyString(value: String): DokkaPublicationChannel = when (value) {
+ "space-dokka-dev" -> SPACE_DOKKA_DEV
+ "maven-central-release" -> MAVEN_CENTRAL
+ "maven-central-snapshot" -> MAVEN_CENTRAL_SNAPSHOT
+ "gradle-plugin-portal" -> GRADLE_PLUGIN_PORTAL
+ else -> throw IllegalArgumentException("Unknown dokka_publication_channel=$value")
+ }
+ }
+}
+
+val Project.publicationChannels: Set<DokkaPublicationChannel>
+ get() {
+ val publicationChannel = this.properties["dokka_publication_channel"]?.toString()
+ val publicationChannels = this.properties["dokka_publication_channels"]?.toString()
+ if (publicationChannel != null && publicationChannels != null) {
+ throw IllegalArgumentException(
+ "Only one of dokka_publication_channel and dokka_publication_channel*s* can be set. Found: \n" +
+ "dokka_publication_channel=$publicationChannel\n" +
+ "dokka_publication_channels=$publicationChannels"
+ )
+ }
+
+ if (publicationChannel != null) {
+ return setOf(DokkaPublicationChannel.fromPropertyString(publicationChannel))
+ }
+
+ if (publicationChannels != null) {
+ return publicationChannels.split("&").map { channel ->
+ DokkaPublicationChannel.fromPropertyString(channel)
+ }.toSet()
+ }
+
+ return emptySet()
+ }
+
diff --git a/build-logic/src/main/kotlin/org/jetbrains/DokkaVersion.kt b/build-logic/src/main/kotlin/org/jetbrains/DokkaVersion.kt
new file mode 100644
index 00000000..517c7731
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/DokkaVersion.kt
@@ -0,0 +1,19 @@
+package org.jetbrains
+
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.extra
+import org.gradle.kotlin.dsl.provideDelegate
+
+@Suppress("LocalVariableName") // property name with underscore as taken from gradle.properties
+fun Project.configureDokkaVersion(): String {
+ val dokka_version: String? by this.extra
+ return checkNotNull(dokka_version)
+}
+
+val Project.dokkaVersion: String
+ get() = configureDokkaVersion()
+
+val Project.dokkaVersionType: DokkaVersionType?
+ get() = DokkaVersionType.values().find {
+ it.suffix.matches(dokkaVersion.substringAfter("-", ""))
+ }
diff --git a/build-logic/src/main/kotlin/org/jetbrains/DokkaVersionType.kt b/build-logic/src/main/kotlin/org/jetbrains/DokkaVersionType.kt
new file mode 100644
index 00000000..077cd854
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/DokkaVersionType.kt
@@ -0,0 +1,8 @@
+package org.jetbrains
+
+enum class DokkaVersionType(val suffix: Regex) {
+ RELEASE("^$".toRegex()),
+ RC("RC\\d?".toRegex()),
+ SNAPSHOT("SNAPSHOT".toRegex()),
+ DEV("dev-\\d+".toRegex());
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/SetupMaven.kt b/build-logic/src/main/kotlin/org/jetbrains/SetupMaven.kt
new file mode 100644
index 00000000..a1b59a50
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/SetupMaven.kt
@@ -0,0 +1,45 @@
+package org.jetbrains
+
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.Sync
+import org.gradle.kotlin.dsl.creating
+import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.getValue
+import java.io.File
+
+@Suppress("LeakingThis")
+open class SetupMaven : Sync() {
+ @get:Input
+ var mavenVersion = "3.5.0"
+
+ @get:Input
+ var mavenPluginToolsVersion = "3.5.2"
+
+ @get:Internal
+ val mavenBuildDir = "${project.buildDir}/maven"
+
+ @get:Internal
+ val mavenBinDir = "${project.buildDir}/maven-bin"
+
+ @get:Internal
+ val mvn = File(mavenBinDir, "apache-maven-$mavenVersion/bin/mvn")
+
+ private val mavenBinaryConfiguration: Configuration by project.configurations.creating {
+ project.dependencies {
+ this@creating.invoke(
+ group = "org.apache.maven",
+ name = "apache-maven",
+ version = mavenVersion,
+ classifier = "bin", ext = "zip"
+ )
+ }
+ }
+
+ init {
+ from(mavenBinaryConfiguration.map { file -> project.zipTree(file) })
+ into(mavenBinDir)
+ }
+
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/ValidatePublications.kt b/build-logic/src/main/kotlin/org/jetbrains/ValidatePublications.kt
new file mode 100644
index 00000000..af35a847
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/ValidatePublications.kt
@@ -0,0 +1,79 @@
+package org.jetbrains
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.api.publish.PublishingExtension
+import org.gradle.api.publish.maven.MavenPublication
+import org.gradle.api.tasks.TaskAction
+import org.gradle.kotlin.dsl.findByType
+
+open class ValidatePublications : DefaultTask() {
+
+ init {
+ group = "verification"
+ project.tasks.named("check") {
+ dependsOn(this@ValidatePublications)
+ }
+ }
+
+ @TaskAction
+ fun validatePublicationConfiguration() {
+ project.subprojects.forEach { subProject ->
+ val publishing = subProject.extensions.findByType<PublishingExtension>() ?: return@forEach
+ publishing.publications
+ .filterIsInstance<MavenPublication>()
+ .filter { it.version == project.dokkaVersion }
+ .forEach { _ ->
+ checkProjectDependenciesArePublished(subProject)
+ subProject.assertPublicationVersion()
+ }
+ }
+ }
+
+ private fun checkProjectDependenciesArePublished(project: Project) {
+ val implementationDependencies = project.findDependenciesByName("implementation")
+ val apiDependencies = project.findDependenciesByName("api")
+
+ val allDependencies = implementationDependencies + apiDependencies
+
+ allDependencies
+ .filterIsInstance<ProjectDependency>()
+ .forEach { projectDependency ->
+ val publishing = projectDependency.dependencyProject.extensions.findByType<PublishingExtension>()
+ ?: throw UnpublishedProjectDependencyException(
+ project = project, dependencyProject = projectDependency.dependencyProject
+ )
+
+ val isPublished = publishing.publications.filterIsInstance<MavenPublication>()
+ .any { it.version == project.dokkaVersion }
+
+ if (!isPublished) {
+ throw UnpublishedProjectDependencyException(project, projectDependency.dependencyProject)
+ }
+ }
+ }
+
+ private fun Project.findDependenciesByName(name: String): Set<Dependency> {
+ return configurations.findByName(name)?.allDependencies.orEmpty()
+ }
+
+ private fun Project.assertPublicationVersion() {
+ val versionTypeMatchesPublicationChannels = publicationChannels.all { publicationChannel ->
+ publicationChannel.acceptedDokkaVersionTypes.any { acceptedVersionType ->
+ acceptedVersionType == dokkaVersionType
+ }
+ }
+ if (!versionTypeMatchesPublicationChannels) {
+ throw AssertionError("Wrong version $dokkaVersion for configured publication channels $publicationChannels")
+ }
+ }
+
+ private class UnpublishedProjectDependencyException(
+ project: Project, dependencyProject: Project
+ ): GradleException(
+ "Published project ${project.path} cannot depend on unpublished project ${dependencyProject.path}"
+ )
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/conventions/base-java.gradle.kts b/build-logic/src/main/kotlin/org/jetbrains/conventions/base-java.gradle.kts
new file mode 100644
index 00000000..2073f9a2
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/conventions/base-java.gradle.kts
@@ -0,0 +1,22 @@
+package org.jetbrains.conventions
+
+/**
+ * Base configuration for Java projects.
+ *
+ * This convention plugin contains shared Java config for both the [KotlinJvmPlugin] convention plugin and
+ * the Gradle Plugin subproject (which cannot have the `kotlin("jvm")` plugin applied).
+ */
+
+plugins {
+ java
+}
+
+java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(8))
+ }
+}
+
+java {
+ withSourcesJar()
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/conventions/base.gradle.kts b/build-logic/src/main/kotlin/org/jetbrains/conventions/base.gradle.kts
new file mode 100644
index 00000000..c4352d16
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/conventions/base.gradle.kts
@@ -0,0 +1,12 @@
+package org.jetbrains.conventions
+
+plugins {
+ base
+}
+
+// common Gradle configuration that should be applied to all projects
+
+if (project != rootProject) {
+ project.group = rootProject.group
+ project.version = rootProject.version
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/conventions/dokka-integration-test.gradle.kts b/build-logic/src/main/kotlin/org/jetbrains/conventions/dokka-integration-test.gradle.kts
new file mode 100644
index 00000000..f9edb68e
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/conventions/dokka-integration-test.gradle.kts
@@ -0,0 +1,75 @@
+package org.jetbrains.conventions
+
+import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+import org.gradle.api.tasks.testing.logging.TestLogEvent
+
+plugins {
+ id("org.jetbrains.conventions.kotlin-jvm")
+}
+
+val integrationTestSourceSet: SourceSet = sourceSets.create("integrationTest") {
+ compileClasspath += sourceSets.main.get().output
+ runtimeClasspath += sourceSets.main.get().output
+}
+
+val integrationTestImplementation: Configuration by configurations.getting {
+ extendsFrom(configurations.implementation.get())
+}
+
+val integrationTestRuntimeOnly: Configuration by configurations.getting {
+ extendsFrom(configurations.runtimeOnly.get())
+}
+
+/**
+ * Dokka's integration test task is not cacheable because the HTML outputs
+ * it produces when running the tests are used for showcasing resulting documentation,
+ * which does not work well with caching.
+ *
+ * At the moment there are two problems that do not allow to make it cacheable:
+ *
+ * 1. The task's inputs are such that changes in Dokka's code do not invalidate the cache,
+ * because it is run with the same version of Dokka (`"DOKKA_VERSION"`) on the same
+ * test project inputs.
+ * 2. The tests generate HTML output which is then used to showcase documentation.
+ * The outputs are usually copied to a location from which it will be served.
+ * However, if the test is cacheable, it produces no outputs, so no documentation
+ * to showcase. It needs to be broken into two separate tasks: one cacheable for running
+ * the tests and producing HTML output, and another non-cacheable for copying the output.
+ *
+ * @see [org.jetbrains.dokka.it.TestOutputCopier] for more details on showcasing documentation
+ */
+@DisableCachingByDefault(because = "Contains incorrect inputs/outputs configuration, see the KDoc for details")
+abstract class NonCacheableIntegrationTest : Test()
+
+val integrationTest by tasks.registering(NonCacheableIntegrationTest::class) {
+ maxHeapSize = "2G"
+ description = "Runs integration tests."
+ group = "verification"
+ useJUnit()
+
+ testClassesDirs = integrationTestSourceSet.output.classesDirs
+ classpath = integrationTestSourceSet.runtimeClasspath
+
+ setForkEvery(1)
+ project.properties["dokka_integration_test_parallelism"]?.toString()?.toIntOrNull()?.let { parallelism ->
+ maxParallelForks = parallelism
+ }
+ environment(
+ "isExhaustive",
+ project.properties["dokka_integration_test_is_exhaustive"]?.toString()?.toBoolean()
+ ?: System.getenv("DOKKA_INTEGRATION_TEST_IS_EXHAUSTIVE")?.toBoolean()
+ ?: false.toString()
+ )
+
+ testLogging {
+ exceptionFormat = TestExceptionFormat.FULL
+ events(TestLogEvent.SKIPPED, TestLogEvent.FAILED)
+ showExceptions = true
+ showCauses = true
+ showStackTraces = true
+ }
+}
+
+tasks.check {
+ dependsOn(integrationTest)
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/conventions/dokka.gradle.kts b/build-logic/src/main/kotlin/org/jetbrains/conventions/dokka.gradle.kts
new file mode 100644
index 00000000..9a193cbb
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/conventions/dokka.gradle.kts
@@ -0,0 +1,13 @@
+package org.jetbrains.conventions
+
+import org.gradle.kotlin.dsl.invoke
+import org.jetbrains.isLocalPublication
+
+plugins {
+ id("org.jetbrains.dokka")
+}
+
+tasks.dokkaHtml {
+ onlyIf { !isLocalPublication }
+ outputDirectory.set(layout.buildDirectory.dir("dokka").map { it.asFile })
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/conventions/kotlin-jvm.gradle.kts b/build-logic/src/main/kotlin/org/jetbrains/conventions/kotlin-jvm.gradle.kts
new file mode 100644
index 00000000..c40ce57c
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/conventions/kotlin-jvm.gradle.kts
@@ -0,0 +1,32 @@
+package org.jetbrains.conventions
+
+import org.jetbrains.configureDokkaVersion
+import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ id("org.jetbrains.conventions.base")
+ id("org.jetbrains.conventions.base-java")
+ kotlin("jvm")
+}
+
+configureDokkaVersion()
+
+val language_version: String by project
+
+tasks.withType<KotlinCompile>().configureEach {
+ compilerOptions {
+ freeCompilerArgs.addAll(
+ listOf(
+ "-opt-in=kotlin.RequiresOptIn",
+ "-Xjsr305=strict",
+ "-Xskip-metadata-version-check",
+ // need 1.4 support, otherwise there might be problems with Gradle 6.x (it's bundling Kotlin 1.4)
+ "-Xsuppress-version-warnings"
+ )
+ )
+ allWarningsAsErrors.set(true)
+ languageVersion.set(KotlinVersion.fromVersion(language_version))
+ apiVersion.set(KotlinVersion.fromVersion(language_version))
+ }
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/conventions/maven-publish.gradle.kts b/build-logic/src/main/kotlin/org/jetbrains/conventions/maven-publish.gradle.kts
new file mode 100644
index 00000000..7007fd9e
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/conventions/maven-publish.gradle.kts
@@ -0,0 +1,30 @@
+package org.jetbrains.conventions
+
+plugins {
+ id("org.jetbrains.conventions.base")
+ `maven-publish`
+ signing
+ id("org.jetbrains.conventions.dokka")
+}
+
+val javadocJar by tasks.registering(Jar::class) {
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+ description = "Assembles a Javadoc JAR using Dokka HTML"
+ archiveClassifier.set("javadoc")
+ from(tasks.dokkaHtml)
+}
+
+publishing {
+ repositories {
+ // Publish to a project-local Maven directory, for verification. To test, run:
+ // ./gradlew publishAllPublicationsToMavenProjectLocalRepository
+ // and check $rootDir/build/maven-project-local
+ maven(rootProject.layout.buildDirectory.dir("maven-project-local")) {
+ name = "MavenProjectLocal"
+ }
+ }
+
+ publications.withType<MavenPublication>().configureEach {
+ artifact(javadocJar)
+ }
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/projectUtils.kt b/build-logic/src/main/kotlin/org/jetbrains/projectUtils.kt
new file mode 100644
index 00000000..46d803a5
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/projectUtils.kt
@@ -0,0 +1,16 @@
+package org.jetbrains
+
+import org.gradle.api.Project
+
+fun Project.whenEvaluated(action: Project.() -> Unit) {
+ if (state.executed) {
+ action()
+ } else {
+ afterEvaluate { action() }
+ }
+}
+
+fun Project.invokeWhenEvaluated(action: (project: Project) -> Unit) {
+ whenEvaluated { action(this) }
+}
+
diff --git a/build-logic/src/main/kotlin/org/jetbrains/publication.kt b/build-logic/src/main/kotlin/org/jetbrains/publication.kt
new file mode 100644
index 00000000..60d91c33
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/publication.kt
@@ -0,0 +1,152 @@
+package org.jetbrains
+
+import com.github.jengelman.gradle.plugins.shadow.ShadowExtension
+import org.gradle.api.Project
+import org.gradle.api.plugins.JavaBasePlugin
+import org.gradle.api.publish.PublishingExtension
+import org.gradle.api.publish.maven.MavenPublication
+import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
+import org.gradle.api.tasks.TaskContainer
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.api.tasks.bundling.Jar
+import org.gradle.kotlin.dsl.*
+import org.gradle.plugins.signing.SigningExtension
+import org.jetbrains.DokkaPublicationChannel.*
+import java.net.URI
+
+class DokkaPublicationBuilder {
+ enum class Component {
+ Java, Shadow
+ }
+
+ var artifactId: String? = null
+ var component: Component = Component.Java
+}
+
+
+fun Project.registerDokkaArtifactPublication(publicationName: String, configure: DokkaPublicationBuilder.() -> Unit) {
+ configure<PublishingExtension> {
+ publications {
+ register<MavenPublication>(publicationName) {
+ val builder = DokkaPublicationBuilder().apply(configure)
+ artifactId = builder.artifactId
+ when (builder.component) {
+ DokkaPublicationBuilder.Component.Java -> from(components["java"])
+ DokkaPublicationBuilder.Component.Shadow -> run {
+ extensions.getByType(ShadowExtension::class.java).component(this)
+ artifact(tasks["sourcesJar"])
+ }
+ }
+ configurePom("Dokka ${project.name}")
+ }
+ }
+ }
+
+ configureSpacePublicationIfNecessary(publicationName)
+ configureSonatypePublicationIfNecessary(publicationName)
+ createDokkaPublishTaskIfNecessary()
+}
+
+fun Project.configureSpacePublicationIfNecessary(vararg publications: String) {
+ if (SPACE_DOKKA_DEV in this.publicationChannels) {
+ configure<PublishingExtension> {
+ repositories {
+ /* already registered */
+ findByName(SPACE_DOKKA_DEV.name)?.let { return@repositories }
+ maven {
+ name = SPACE_DOKKA_DEV.name
+ url = URI.create("https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev")
+ credentials {
+ username = System.getenv("SPACE_PACKAGES_USER")
+ password = System.getenv("SPACE_PACKAGES_SECRET")
+ }
+ }
+ }
+ }
+ }
+
+ whenEvaluated {
+ tasks.withType<PublishToMavenRepository> {
+ if (this.repository.name == SPACE_DOKKA_DEV.name) {
+ this.isEnabled = this.isEnabled && publication.name in publications
+ if (!this.isEnabled) {
+ this.group = "disabled"
+ }
+ }
+ }
+ }
+}
+
+fun Project.createDokkaPublishTaskIfNecessary() {
+ tasks.maybeCreate("dokkaPublish").run {
+ if (publicationChannels.any { it.isSpaceRepository() }) {
+ dependsOn(tasks.named("publish"))
+ }
+
+ if (publicationChannels.any { it.isMavenRepository() }) {
+ dependsOn(tasks.named("publishToSonatype"))
+ }
+
+ if (publicationChannels.any { it.isGradlePluginPortal() }) {
+ dependsOn(tasks.named("publishPlugins"))
+ }
+ }
+}
+
+fun Project.configureSonatypePublicationIfNecessary(vararg publications: String) {
+ if (publicationChannels.any { it.isMavenRepository() }) {
+ signPublicationsIfKeyPresent(*publications)
+ }
+}
+
+fun MavenPublication.configurePom(projectName: String) {
+ pom {
+ name.set(projectName)
+ description.set("Dokka is an API documentation engine for Kotlin and Java, performing the same function as Javadoc for Java")
+ url.set("https://github.com/Kotlin/dokka")
+
+ licenses {
+ license {
+ name.set("The Apache Software License, Version 2.0")
+ url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
+ distribution.set("repo")
+ }
+ }
+
+ developers {
+ developer {
+ id.set("JetBrains")
+ name.set("JetBrains Team")
+ organization.set("JetBrains")
+ organizationUrl.set("http://www.jetbrains.com")
+ }
+ }
+
+ scm {
+ connection.set("scm:git:git://github.com/Kotlin/dokka.git")
+ url.set("https://github.com/Kotlin/dokka/tree/master")
+ }
+ }
+}
+
+@Suppress("UnstableApiUsage")
+private fun Project.signPublicationsIfKeyPresent(vararg publications: String) {
+ val signingKeyId: String? = System.getenv("SIGN_KEY_ID")
+ val signingKey: String? = System.getenv("SIGN_KEY")
+ val signingKeyPassphrase: String? = System.getenv("SIGN_KEY_PASSPHRASE")
+
+ if (!signingKey.isNullOrBlank()) {
+ extensions.configure<SigningExtension>("signing") {
+ if (signingKeyId?.isNotBlank() == true) {
+ useInMemoryPgpKeys(signingKeyId, signingKey, signingKeyPassphrase)
+ } else {
+ useInMemoryPgpKeys(signingKey, signingKeyPassphrase)
+ }
+ publications.forEach { publicationName ->
+ extensions.findByType(PublishingExtension::class)!!.publications.findByName(publicationName)?.let {
+ sign(it)
+ }
+ }
+ }
+ }
+}
diff --git a/build-logic/src/main/kotlin/org/jetbrains/taskUtils.kt b/build-logic/src/main/kotlin/org/jetbrains/taskUtils.kt
new file mode 100644
index 00000000..261d1663
--- /dev/null
+++ b/build-logic/src/main/kotlin/org/jetbrains/taskUtils.kt
@@ -0,0 +1,22 @@
+package org.jetbrains
+
+import org.gradle.api.Project
+import org.gradle.api.Task
+
+fun Task.dependsOnMavenLocalPublication() {
+ project.rootProject.allprojects.forEach { otherProject ->
+ otherProject.invokeWhenEvaluated { evaluatedProject ->
+ evaluatedProject.tasks.findByName("publishToMavenLocal")?.let { publishingTask ->
+ this.dependsOn(publishingTask)
+ }
+ }
+ }
+}
+
+val Project.isLocalPublication: Boolean
+ get() = gradle.startParameter.taskNames.any {
+ it.endsWith("publishToMavenLocal", ignoreCase = true) ||
+ it.endsWith("integrationTest", ignoreCase = true) ||
+ it.endsWith("check", ignoreCase = true) ||
+ it.endsWith("test", ignoreCase = true)
+ }