From 12e2a3c6b8bf1533148ddf29c77e73f5045754a6 Mon Sep 17 00:00:00 2001 From: aSemy <897017+aSemy@users.noreply.github.com> Date: Thu, 16 Mar 2023 02:15:49 +0100 Subject: Refactor Maven Runner build config (#2911) --- .../conventions/maven-cli-setup.gradle.kts | 103 ++++++++++++++++++ gradle.properties | 3 + integration-tests/maven/build.gradle.kts | 13 +-- runners/maven-plugin/build.gradle.kts | 117 ++++++++++++--------- runners/maven-plugin/pom.template.xml | 26 +++++ runners/maven-plugin/pom.tpl.xml | 26 ----- 6 files changed, 205 insertions(+), 83 deletions(-) create mode 100644 build-logic/src/main/kotlin/org/jetbrains/conventions/maven-cli-setup.gradle.kts create mode 100644 runners/maven-plugin/pom.template.xml delete mode 100644 runners/maven-plugin/pom.tpl.xml diff --git a/build-logic/src/main/kotlin/org/jetbrains/conventions/maven-cli-setup.gradle.kts b/build-logic/src/main/kotlin/org/jetbrains/conventions/maven-cli-setup.gradle.kts new file mode 100644 index 00000000..ec59da7b --- /dev/null +++ b/build-logic/src/main/kotlin/org/jetbrains/conventions/maven-cli-setup.gradle.kts @@ -0,0 +1,103 @@ +package org.jetbrains.conventions + +import org.gradle.kotlin.dsl.support.serviceOf + +/** + * Utility for downloading and installing a Maven binary. + * + * Provides the `setupMavenProperties` extension that contains the default versions and locations + * of the Maven binary. + * + * The task [installMavenBinary] will download and unzip the Maven bianry. + */ + +plugins { + base +} + +abstract class SetupMavenProperties { + abstract val mavenVersion: Property + abstract val mavenPluginToolsVersion: Property + abstract val mavenBuildDir: DirectoryProperty + + /** Directory that will contain the unpacked Apache Maven dependency */ + abstract val mavenInstallDir: DirectoryProperty + + /** + * Path to the Maven executable. + * + * This should be different per OS: + * + * * Windows: `$mavenInstallDir/bin/mvn.cmd` + * * Unix: `$mavenInstallDir/bin/mvn` + */ + abstract val mvn: RegularFileProperty +} + +val setupMavenProperties = + extensions.create("setupMavenProperties", SetupMavenProperties::class).apply { + mavenVersion.convention(providers.gradleProperty("mavenVersion")) + mavenPluginToolsVersion.convention(providers.gradleProperty("mavenPluginToolsVersion")) + + mavenBuildDir.convention(layout.buildDirectory.dir("maven")) + mavenInstallDir.convention(layout.buildDirectory.dir("apache-maven")) + + val isWindowsProvider = + providers.systemProperty("os.name").map { "win" in it.toLowerCase() } + + mvn.convention( + providers.zip(mavenInstallDir, isWindowsProvider) { mavenInstallDir, isWindows -> + mavenInstallDir.file( + when { + isWindows -> "bin/mvn.cmd" + else -> "bin/mvn" + } + ) + } + ) + } + +val mavenBinary by configurations.registering { + description = "used to download the Maven binary" + isCanBeResolved = true + isCanBeConsumed = false + isVisible = false + + defaultDependencies { + addLater(setupMavenProperties.mavenVersion.map { mavenVersion -> + project.dependencies.create( + group = "org.apache.maven", + name = "apache-maven", + version = mavenVersion, + classifier = "bin", + ext = "zip" + ) + }) + } +} + +tasks.clean { + delete(setupMavenProperties.mavenBuildDir) + delete(setupMavenProperties.mavenInstallDir) +} + +val installMavenBinary by tasks.registering(Sync::class) { + val archives = serviceOf() + from( + mavenBinary.flatMap { conf -> + @Suppress("UnstableApiUsage") + val resolvedArtifacts = conf.incoming.artifacts.resolvedArtifacts + + resolvedArtifacts.map { artifacts -> + artifacts.map { archives.zipTree(it.file) } + } + } + ) { + eachFile { + // drop the first directory inside the zipped Maven bin (apache-maven-$version) + relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray()) + } + includeEmptyDirs = false + } + into(setupMavenProperties.mavenInstallDir) +} diff --git a/gradle.properties b/gradle.properties index a8eb1eff..d68155d7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,6 +14,9 @@ jackson_version=2.12.7 # fixes CVE-2022-42003 jackson_databind_version=2.12.7.1 freemarker_version=2.3.31 +# Dokka Maven Plugin versions +mavenVersion=3.5.0 +mavenPluginToolsVersion=3.5.2 # Code style kotlin.code.style=official # Gradle settings diff --git a/integration-tests/maven/build.gradle.kts b/integration-tests/maven/build.gradle.kts index 4b8b6011..a2e7c440 100644 --- a/integration-tests/maven/build.gradle.kts +++ b/integration-tests/maven/build.gradle.kts @@ -1,12 +1,10 @@ -import org.jetbrains.SetupMaven import org.jetbrains.dependsOnMavenLocalPublication plugins { id("org.jetbrains.conventions.dokka-integration-test") + id("org.jetbrains.conventions.maven-cli-setup") } -evaluationDependsOn(":runners:maven-plugin") - dependencies { implementation(project(":integration-tests")) implementation(kotlin("stdlib")) @@ -16,10 +14,13 @@ dependencies { tasks.integrationTest { dependsOnMavenLocalPublication() - val setupMavenTask = project(":runners:maven-plugin").tasks.withType().single() - dependsOn(setupMavenTask) + dependsOn(tasks.installMavenBinary) + val mvn = setupMavenProperties.mvn + inputs.file(mvn) val dokka_version: String by project environment("DOKKA_VERSION", dokka_version) - environment("MVN_BINARY_PATH", setupMavenTask.mvn.absolutePath) + doFirst("workaround for https://github.com/gradle/gradle/issues/24267") { + environment("MVN_BINARY_PATH", mvn.get().asFile.invariantSeparatorsPath) + } } diff --git a/runners/maven-plugin/build.gradle.kts b/runners/maven-plugin/build.gradle.kts index f8badf8e..90f2ffef 100644 --- a/runners/maven-plugin/build.gradle.kts +++ b/runners/maven-plugin/build.gradle.kts @@ -1,82 +1,97 @@ -import org.jetbrains.CrossPlatformExec -import org.jetbrains.SetupMaven +import org.gradle.kotlin.dsl.support.appendReproducibleNewLine import org.jetbrains.registerDokkaArtifactPublication plugins { id("org.jetbrains.conventions.kotlin-jvm") id("org.jetbrains.conventions.maven-publish") + id("org.jetbrains.conventions.maven-cli-setup") } -val setupMaven by tasks.register("setupMaven") - dependencies { implementation(project(":core")) - implementation("org.apache.maven:maven-core:${setupMaven.mavenVersion}") - implementation("org.apache.maven:maven-plugin-api:${setupMaven.mavenVersion}") - implementation("org.apache.maven.plugin-tools:maven-plugin-annotations:${setupMaven.mavenPluginToolsVersion}") + implementation("org.apache.maven:maven-core:${setupMavenProperties.mavenVersion.get()}") + implementation("org.apache.maven:maven-plugin-api:${setupMavenProperties.mavenVersion.get()}") + implementation("org.apache.maven.plugin-tools:maven-plugin-annotations:${setupMavenProperties.mavenPluginToolsVersion.get()}") implementation("org.apache.maven:maven-archiver:2.5") implementation(kotlin("stdlib-jdk8")) } -val mavenBuildDir = setupMaven.mavenBuildDir -val mavenBinDir = setupMaven.mavenBinDir - -tasks.clean { - delete(mavenBuildDir) - delete(mavenBinDir) -} +val mavenPluginTaskGroup = "maven plugin" -val generatePom by tasks.registering(Copy::class) { +val generatePom by tasks.registering(Sync::class) { description = "Generate pom.xml for Maven Plugin Plugin" + group = mavenPluginTaskGroup val dokka_version: String by project inputs.property("dokka_version", dokka_version) - from("$projectDir/pom.tpl.xml") { - rename("(.*).tpl.xml", "$1.xml") - } - into(setupMaven.mavenBuildDir) - - eachFile { - filter { line -> - line.replace("", "${setupMaven.mavenVersion}") - } - filter { line -> - line.replace("dokka_version", "$dokka_version") - } - filter { line -> - line.replace( - "maven-plugin-plugin", - "${setupMaven.mavenPluginToolsVersion}" - ) - } + val pomTemplateFile = layout.projectDirectory.file("pom.template.xml") + + val mavenVersion = setupMavenProperties.mavenVersion.get() + val mavenPluginToolsVersion = setupMavenProperties.mavenPluginToolsVersion.get() + + from(pomTemplateFile) { + rename { it.replace(".template.xml", ".xml") } + + expand( + "mavenVersion" to mavenVersion, + "dokka_version" to dokka_version, + "mavenPluginToolsVersion" to mavenPluginToolsVersion, + ) } + + into(temporaryDir) } -val syncClasses by tasks.registering(Sync::class) { - description = "Copy compiled classes to the Maven build dir, for Maven Plugin task execution" +val prepareMavenPluginBuildDir by tasks.registering(Sync::class) { + description = "Prepares all files for Maven Plugin task execution" + group = mavenPluginTaskGroup + + from(tasks.compileKotlin.flatMap { it.destinationDirectory }) { into("classes/java/main") } + from(tasks.compileJava.flatMap { it.destinationDirectory }) { into("classes/java/main") } - dependsOn(tasks.compileKotlin, tasks.compileJava) - from("$buildDir/classes/kotlin", "$buildDir/classes/java") - into("${setupMaven.mavenBuildDir}/classes/java") + from(generatePom) - preserve { - include("**/*.class") + into(setupMavenProperties.mavenBuildDir) +} + +val helpMojo by tasks.registering(Exec::class) { + group = mavenPluginTaskGroup + + dependsOn(tasks.installMavenBinary, prepareMavenPluginBuildDir) + + workingDir(setupMavenProperties.mavenBuildDir) + executable(setupMavenProperties.mvn.get()) + args("-e", "-B", "org.apache.maven.plugins:maven-plugin-plugin:helpmojo") + + outputs.dir(setupMavenProperties.mavenBuildDir) + + doLast("normalize maven-plugin-help.properties") { + // The maven-plugin-help.properties file contains a timestamp by default. + // It should be removed as it is not reproducible and impacts Gradle caching + val pluginHelpProperties = workingDir.resolve("maven-plugin-help.properties") + pluginHelpProperties.writeText( + buildString { + val lines = pluginHelpProperties.readText().lines().iterator() + // the first line is a descriptive comment + appendReproducibleNewLine(lines.next()) + // the second line is the timestamp, which should be ignored + lines.next() + // the remaining lines are properties + lines.forEach { appendReproducibleNewLine(it) } + } + ) } } -val helpMojo by tasks.registering(CrossPlatformExec::class) { - dependsOn(setupMaven, generatePom, syncClasses) - workingDir(setupMaven.mavenBuildDir) - commandLine(setupMaven.mvn, "-e", "-B", "org.apache.maven.plugins:maven-plugin-plugin:helpmojo") +val pluginDescriptor by tasks.registering(Exec::class) { + group = mavenPluginTaskGroup - outputs.dir(layout.buildDirectory.dir("maven")) -} + dependsOn(tasks.installMavenBinary, prepareMavenPluginBuildDir) -val pluginDescriptor by tasks.registering(CrossPlatformExec::class) { - dependsOn(setupMaven, generatePom, syncClasses) - workingDir(setupMaven.mavenBuildDir) - commandLine(setupMaven.mvn, "-e", "-B", "org.apache.maven.plugins:maven-plugin-plugin:descriptor") + workingDir(setupMavenProperties.mavenBuildDir) + executable(setupMavenProperties.mvn.get()) + args("-e", "-B", "org.apache.maven.plugins:maven-plugin-plugin:descriptor") outputs.dir(layout.buildDirectory.dir("maven/classes/java/main/META-INF/maven")) } @@ -84,7 +99,7 @@ val pluginDescriptor by tasks.registering(CrossPlatformExec::class) { tasks.jar { dependsOn(pluginDescriptor, helpMojo) metaInf { - from("${setupMaven.mavenBuildDir}/classes/java/main/META-INF") + from(setupMavenProperties.mavenBuildDir.map { it.dir("classes/java/main/META-INF") }) } manifest { attributes("Class-Path" to configurations.runtimeClasspath.map { configuration -> diff --git a/runners/maven-plugin/pom.template.xml b/runners/maven-plugin/pom.template.xml new file mode 100644 index 00000000..97db90ee --- /dev/null +++ b/runners/maven-plugin/pom.template.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + org.jetbrains.dokka + dokka-maven-plugin + ${dokka_version} + maven-plugin + + ${mavenVersion} + + + + + org.apache.maven.plugins + maven-plugin-plugin + ${mavenPluginToolsVersion} + + org.jetbrains.dokka.maven + + + + ./ + ./classes/java/main + + diff --git a/runners/maven-plugin/pom.tpl.xml b/runners/maven-plugin/pom.tpl.xml deleted file mode 100644 index c5883c6a..00000000 --- a/runners/maven-plugin/pom.tpl.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - 4.0.0 - org.jetbrains.dokka - dokka-maven-plugin - dokka_version - maven-plugin - - - - - - - org.apache.maven.plugins - maven-plugin-plugin - maven-plugin-plugin - - org.jetbrains.dokka.maven - - - - ./ - ./classes/java/main - - -- cgit