I have a Gradle 7.0
publish task defined in my Java Spring boot project sub module build.gradle
file like this:
publishing { publications { maven(MavenPublication) { groupId 'com.sportswin.soa' artifactId 'soa-auth-api' version('1.0.0-SNAPSHOT') from components.java artifact sourceJar { classifier "sources" } } } repositories { maven { url = version.endsWith('SNAPSHOT') ? "${dabaiSnapshotRepo}" : "${dabaiReleaseRepo}" url = "$url" credentials { username "$mavenLoginName" password "$mavenPassword" } } } }
It works fine in each of my sub module. The only problem is that this code snippet must be copied to each of my sub module. Now the sub module increased more than 50+. I have to copy and paste it in each location.
Is it possible to define the publish task as a public task and I only need to pass some parameters like the groupId
, artifactId
, version
? What should I do to make it work like this so I do not have to copy and paste the duplicate code snippet?
My project structure is like this:
rootProject -- build.gradle -- setting.gradle module1 -- build.gradle module2 -- build.gradle
BTW, this is the full sub module build.gradle:
project(":soa-auth") { dependencies { } } project(":soa-auth:soa-auth-api") { jar { enabled = true } bootJar { enabled = false } dependencies { api project(":soa-misc-biz") } publishing { publications { maven(MavenPublication) { groupId 'com.sportswin.soa' artifactId 'soa-auth-api' version('1.0.0-SNAPSHOT') from components.java artifact sourceJar { classifier "sources" } } } repositories { maven { url = "${dabaiSnapshotRepo}" url = "$url" credentials { username "$mavenLoginName" password "$mavenPassword" } } } } } project(":soa-auth:soa-auth-service") { archivesBaseName = "soa-auth-service" version = "1.0.0-SNAPSHOT" bootJar { manifest { attributes 'Start-Class': 'com.sportswin.soa.auth.AppStarter' } } dependencies { implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client") implementation project(":soa-auth:soa-auth-api") } }
I am glad to supply any extra information to solve this problem.
Advertisement
Answer
Solution 1: buildSrc
buildSrc
is a special folder implicitly treated as an included build by Gradle. You can put some common build logic here.
Structure
├── buildSrc │ ├── src/main/groovy/com.example.my-publishing.gradle │ └── build.gradle ├── module1 │ └── build.gradle ├── module2 │ └── build.gradle ├── build.gradle └── settings.gradle
./buildSrc/build.gradle
plugins { id 'groovy-gradle-plugin' } repositories { gradlePluginPortal() }
./buildSrc/src/main/com.example.my-publishing.gradle
plugins { id 'java' id 'maven-publish' } java { withSourcesJar() } publishing { publications { maven(MavenPublication) { from components.java } } repositories { ... } }
./module1/build.gradle
plugins { ... id 'com.example.my-publishing' }
Solution 2: Explicit buildSrc
This solution is nearly identical to the first one. I prefer this because I believe explicit is better than implicit.
Structure
├── build-conventions <-- Use any name other than 'buildSrc' │ ├── src/main/groovy/com.example.my-publishing.gradle │ ├── build.gradle │ └── settings.gradle <-- Leave it empty ├── module1 │ └── build.gradle ├── module2 │ └── build.gradle ├── build.gradle └── settings.gradle
./settings.gradle
... include('module1') include('module2') includeBuild('build-conventions')
Solution 3: Standalone Plugin
If your publishing logic becomes much complicated someday, you probably need this. I choose implementing in Kotlin for static typing. You can write it in Groovy too.
Structure
├── plugins │ ├── src/main/kotlin/com/example/MyPublishingPlugin.kt │ ├── build.gradle.kts │ └── settings.gradle.kts <-- Leave it empty ├── module1 │ └── build.gradle ├── module2 │ └── build.gradle ├── build.gradle └── settings.gradle
./settings.gradle
... include('module1') include('module2') includeBuild('plugins')
./plugins/build.gradle.kts
plugins { `java-gradle-plugin` id("org.jetbrains.kotlin.jvm") version "1.5.0" } repositories { mavenCentral() } dependencies { implementation(platform("org.jetbrains.kotlin:kotlin-bom")) implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit") } gradlePlugin { val myPublishing by plugins.creating { id = "com.example.my-publishing" implementationClass = "com.example.MyPublishingPlugin" } }
./plugins/src/main/kotlin/com/example/MyPublishingPlugin.kt
package com.example import org.gradle.api.Project import org.gradle.api.Plugin import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.plugins.MavenPublishPlugin class MyPublishingPlugin: Plugin<Project> { override fun apply(project: Project) { project.plugins.apply(MavenPublishPlugin::class.java) project.afterEvaluate { project.configureJavaExtension() project.configurePublishingExtension() } } private fun Project.configureJavaExtension() { val extension = this.extensions.getByType(JavaPluginExtension::class.java) extension.withSourcesJar() } private fun Project.configurePublishingExtension() { val extension = this.extensions.getByType(PublishingExtension::class.java) extension.publications { container -> container.create("maven", MavenPublication::class.java) { it.from(this.components.getByName("java")) } } extension.repositories { it.maven { repo -> repo.url = this.uri(this.layout.buildDirectory.dir("repo")) // ------------ YOUR IMPLEMENTATION ------------ } } } }
./module1/build.gradle
plugins { ... id 'com.example.my-publishing' }
You can generate a full Gradle plugin project via the command gradle init
. If you need pass extra arguments to a plugin, you can attach a custom extension to it.