Skip to content
Advertisement

Is it possible to define the gradle publish task to public?

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.

Advertisement