Gradle : Something like Maven Parent POM - gradle

In our company, many of the different projects use similar technology stack and will have many common features.
So, we want to maintain the common features, dependencies etc. in one common file and refer it in the other projects.
In maven, it is something like creating a separate maven project with the common dependency information and refer that in the other projects as .
I want to do something similar to the maven parent project in gradle, which can be used by all different projects.
I googled for that, but could not find a concise information on how to do that.
We are not allowed to use external thirdparty plugins.
It would be great if someone could explain it how to do that.

in gradle you can do that, but for it you need to have external plugin, otherwise it is not possible at least for now. I have achieved it in this way:
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.netflix.nebula:nebula-dependency-recommender:4.3.0'
}
}
allprojects {
apply plugin: 'nebula.dependency-recommender'
apply plugin: 'groovy'
apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
jcenter()
maven { url "http://repo1.maven.org/maven2/" }
maven { url "REPOSITORY_OF_YOUR_PARENT_POM.XML" }
}
dependencyRecommendations {
mavenBom module: 'YOUR_PARENT_POM_GROUP:YOUR_PARENT_POM_ID:YOUR_PARENT_POM_VERSION'
}
}
where:
REPOSITORY_OF_YOUR_PARENT_POM.XML - any system like nexus or something else accessible for maven
YOUR_PARENT_POM_GROUP - your parent pom project group (e.g. com.foo.bar.parent)
YOUR_PARENT_POM_ID - your parent pom id (e.g. projects-parent)
YOUR_PARENT_POM_VERSION - your parent pom project version (e.g. 1.0.1)
so, if the external dependency to netflix.nebula is fine , than you can go in this way

Gradle has many extension mechanisms for leveraging build logic located outside of the main script.
A simple thing that can be done is to use an external build script, which can be sourced from the local file system or through an URL, see the documentation on this topic.
If that solution gets too problematic, then you can move to packaging a real plugin that others can apply and potentially configure.
This will allow you to configure much more than dependencies for example.

Related

Gradle: Use a sibling subproject as plugin

I have a project with two subprobjects: gradle-plugin and plugin-consumer. I want to apply the plugin from gradle-plugin to plugin-consumer. I tried to do this:
// plugin-consumer/build.gradle
buildscript {
dependencies {
classpath project(':gradle-plugin')
}
}
apply plugin: 'my.plugin.id'
But I was greeted with the following error:
A problem occurred configuring project ':plugin-consumer'.
> Cannot use project dependencies in a script classpath definition.
I assume this is not supported because it'd require fully building gradle-plugin before plugin-consumer can be configured.
Fortunately I can use a fileTree dependency to accomplish my goal:
// plugin-consumer/build.gradle
buildscript {
dependencies {
classpath fileTree(includes: ['*.jar'], dir: '../gradle-plugin/build/libs')
}
}
apply plugin: 'my.plugin.id'
This works, but it feels like a massive hack and leads to "bootstrapping problems".
For example, I can't clean gradle-plugin because the (deleted) jar file is necessary for configuring plugin-consumer, which must be done to (re)build gradle-plugin.
Fortunately this can be avoided by always running build immediately after clean (in the same 'run' so to speak). This can be done manually (gradle clean build) or automatically (with clean.finalizedBy(build)). Again, this works, but feels like a hack.
At last, my actual question: is there a better way to do this?
Please note that gradle-plugin is an independent plugin that's not only used by plugin-consumer, therefore buildSrc is unfortunately not an appropriate solution here.
You can publish the plugin to your local Maven repository with the Maven Publish plugin. Then simply consume it like any other artifact.
Assuming you have something similar in your plugin project:
plugins {
`maven-publish`
`java-gradle-plugin`
}
Simply publish it locally:
./gradlew :my-plugin-project:publishToMavenLocal
Then in your consuming project, something like:
buildscript {
repositories {
mavenLocal()
}
dependencies {
"classpath"("com.example:my-plugin-gav:1.0.0-SNAPSHOT")
}
}
// apply plugin

how to declare dependency version in one place for many gradle projects

I work on a project with multiple grails services, plugins and libraries, all built with gradle with their dependencies declared in build.gradle files, one per project, this makes sense, I hope.
In maven I used to be able to declare versions of all dependencies in one parent project pom, or a pom template, and only include the dependencies in the projects that required them without the versions. This made upgrading dependencies easy in one place. Is there a simple way to do this in gradle?
Pseudocode example:
master_template/build.gradle
dependencies {
joda-time:joda-time:2.9.1
cglib:cglib:3.2.9
javax.servlet:javax.servlet-api:3.1.0
}
service_a/build.gradle
parent: master_template
dependencies {
joda-time:joda-time
javax.servlet:javax.servlet-api
}
service_b/build.gradle
parent: master_template
dependencies {
cglib:cglib
javax.servlet:javax.servlet-api
}
You can create a multi module project like you would do in maven with a parent pom.
In order to manage the dependency in the parent, I use the spring dependency management plugin.
You parent build.gradle would look like:
subprojects {
apply plugin: "io.spring.dependency-management"
sourceCompatibility = 1.8
targetCompatibility = 1.8
check.dependsOn dependencyCheckAggregate
repositories {
mavenLocal()
jcenter()
// other repos
}
dependencyManagement {
def jacksonVersion = "2.+"
dependencies {
dependency "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
dependency "com.fasterxml.jackson.core:jackson-core:$jacksonVersion"
dependency "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
dependency "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$jacksonVersion"
dependency "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion"
}
}
}
Now, you can add dependencies to your submodules without specifying version.
You can easily achieve what you want by using Gradle's default apply from: 'other.gradle', so no additional plugins are needed.
In my micro-service project I'm using something like that:
common-gradle/env.gradle
apply plugin:'groovy'
ext.compile = [ 'joda-time:joda-time:2.9.1', 'cglib:cglib:3.2.9` ]
ext.testCompile = [ 'org.spockframework:spock-core:1.3-groovy-2.5' ]
common-gradle/dependencies.gradle
dependencies {
compile ext.compile
testCompile ext.testCompile
}
And the usage
service_a/build.gradle
apply from:'../common-gradle/env.gradle'
ext.compile << 'ch.qos.logback:logback-classic:1.2.3'
apply from:'../common-gradle/dependencies.gradle'
Thus each of my build.gradle files contain only 3-5 lines of critical information like project name and version.
You don't need to import the common-gradle as a project in your IDE, you can simply use symlinks to avoid using external references. Also during build on a Jenkins-like pipeline, the only thing you have to do is to check out the common-gradle repo into your working dir.

Gradle: How do you include your own library as part of build?

I have a commons gradle project which is a shared library for all my other projects.
In the build.gradle of dependent project, I included the commons jar as following:
dependencies {
...
runtime files('../commons/build/libs/commons-1.0.jar')
}
And this builds fine with the relative path. But this feels like hard-coding a specific library. What is the standard way to achieve the builds in this case?
You can publish the common jar to Your local maven repository. But If You are developing with in a team, You should publish to a repository manager where other parties have also access to.
And in the dependent projects You simply add this common jar, like You are adding a third party library. With this way You don't have to store dependent jar files on Your version control system. When projects are developed by different parties, this way would be more convenient.
Example of using mavenlocal
// Common project build.gradle
apply plugin: 'maven-publish'
version = '2.0'
...
publishing {
publications {
maven(MavenPublication) {
groupId = 'com.gradle.sample'
artifactId = 'project1-sample'
from components.java
}
}
}
You can use gradle publishToMavenLocal to publish common project to mavenlocal. (Dependent projects can not use the new versions of common jar, unless You publish it to mavenlocal in this case)
// Dependent project build.gradle
repositories {
mavenLocal()
}
dependencies {
implementation 'com.gradle.sample:project1-sample:2.0'
....
}
Check the following link for details.
https://docs.gradle.org/current/userguide/publishing_maven.html

Artifact id resolved wrong

I am new to gradle and I am facing a weird problem while I’m trying to add a plugin in gradle. I know that we have to specify an if and version in plugin body for a gradle build, but I tried to add a plugin with some id and version. My question is..how does a gradle build know which artifact id to choose if there are multiple artifacts under same group id? I know that this might be a lame question...but I’m pretty new to gradle and I’d like to know your input.
Are you trying to apply the spring-boot-plugin?
If so, does the project you're trying to apply the plugin to have a buildscript block like this:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.4.RELEASE"
}
}
apply plugin: "org.springframework.boot"
or a plugin closure:
plugins {
id "org.springframework.boot" version "2.0.4.RELEASE"
}
With a buildscript block, Gradle knows where to find the plugin because I've specified a repository for it to go look for it. After resolving the dependency path it finds and downloads the plugin, then puts it on the classpath for use in build.gradle files. It then only needs to get applied, i.e. apply plugin: ....
With the plugins closure, things are a bit trickier. Plugins are published under a unique id, which is looked up and gradle resolves the specified version. I'm not too terribly knowledgeable about how this is done, but here, new plugin mechanism , describes some differences between buildscript {} apply plugin: ... and plugins {}.

Spring Boot Gradle Plugin "Blessed" Dependencies in a multi-project environment

In a multi-project Gradle environment, I have the usual buildscript block in my parent build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.7.RELEASE")
}
}
However, the dependencies which are supposed to be "blessed" (See 54.2 Declaring dependencies without versions) does not seem to be, since Gradle does not search for the correct version (because there is not version at all). I wonder if I am missing some additional configuration or it's just not possible at this moment to have "blessed" dependencies for a multi-project Gradle environment.
Applying spring-boot plugin to all projects (not just parent project) should help.
Try:
allprojects {
apply plugin: 'spring-boot'
}
EDIT: Andy and I posted the answers almost at the same time. But yes, either allprojects or subprojects should work fine, depending whether you parent project needs the plugin, or not.
You need to apply the Spring Boot plugin to every project that you want to use the Boot-provided dependency versions. As it's a multi-project build (and assuming you want to apply the plugin to every subproject), add the following to your build.gradle:
subprojects {
apply plugin: 'spring-boot'
}

Resources