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.
CodePudding user response:
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.