Inheriting gradle plugin in subprojects - gradle

I want to avoid redundancy and therefore I got one "shared" project that contains looks like this:
plugins {
id "org.flywaydb.flyway" version "4.2.0"
}
repositories {
mavenCentral()
jcenter()
}
apply plugin: "java"
dependencies {
compile "commons-io:commons-io:2.4"
// ...
}
Then I also have my regular projects that inherit the compile dependencies from my shared project like this:
apply plugin: "java"
repositories {
mavenCentral()
jcenter()
}
dependencies {
compile project(":shared")
testCompile project(":shared")
}
Is there any way I can make my regular projects inherit the plugin block or the actual plugin as well?

Not inherit as such. It seems to me that what you're trying to do can be achieved by configuring the subprojects from the root project. Basically in your root build.gradle (which script that will configure your root project) you can write:
subprojects {
// configuration
}
You can probably get rid of your shared project and have this in root project's build.gradle:
plugins {
id "org.flywaydb.flyway" version "4.2.0" apply false
}
subprojects {
repositories {
mavenCentral()
jcenter()
}
apply plugin: "java"
apply plugin: "org.flywaydb.flyway"
dependencies {
compile "commons-io:commons-io:2.4"
// ...
}
}
This way all your subprojects will be configured using the same closure - this is equivalent to copy-pasting everything in subprojects block to your individual subprojects' build.gradle files. The advantage over your initial solution is ability to also apply plugins, configure extensions, everything you normally can do.
As a side note, you don't need both jcenter() and mavenCentral in repositories block - jCenter is a superset of mavenCentral and is the preferred one

Related

Using a gradle plugin before loading other plugins in the buildscript

I have my own gradle plugin that contains a file with versions for other plugins. Currently, whenever I make a new project, I have to copy them over as I can't use the versions from the plugin.
Is there anyway to load my plugin, apply it, and then load other plugins afterwards? Currently, I can only do this for the project myself when I make my plugin model named buildSrc, as it automatically adds it to other modules.
Example of what I want to achieve:
buildscript {
repositories {
google()
jcenter()
maven { url 'https://maven.fabric.io/public' }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "ca.allanwang:kau:$kau_version"
}
// Apply plugin before other dependencies so I can use it
apply plugin: "ca.allanwang.kau"
dependencies {
classpath kauPlugin.android
classpath kauPlugin.kotlin
classpath kauPlugin.androidMaven
classpath kauPlugin.playPublisher
classpath kauPlugin.dexCount
classpath kauPlugin.gitVersion
classpath kauPlugin.spotless
}
wrapper.setDistributionType(Wrapper.DistributionType.ALL)
}
and how it looks like when I have the plugin as a module in my main project:
buildscript {
repositories {
google()
jcenter()
maven { url 'https://maven.fabric.io/public' }
maven { url "https://plugins.gradle.org/m2/" }
}
apply plugin: "ca.allanwang.kau"
dependencies {
classpath kauPlugin.android
classpath kauPlugin.kotlin
classpath kauPlugin.androidMaven
classpath kauPlugin.playPublisher
classpath kauPlugin.dexCount
classpath kauPlugin.gitVersion
classpath kauPlugin.spotless
}
wrapper.setDistributionType(Wrapper.DistributionType.ALL)
}
You should be able to achieve what you want by combining different things:
Define your versions in a Plugin<Settings> that you apply in you settings.gradle(.kts) by leveraging the fact that the Settings object is ExtensionAware
Define your plugin classpath in that same settings file using pluginManagement
Apply plugins in your projects, without specifying a version - see this example for a simpler version that does not define versions through pluginManagement
Example: https://github.com/ljacomet/setttings-plugin-props with the plugin in buildSrc but it could be published and used as a binary plugin without any problem.

Gradle share properties in multi-project

I'm quite new to Gradle, trying to make multi-project. In root project declares all common libs (also their versions as properties) and apply plugins.
For example, root and child common projects.
In root's settings.gradle type:
rootProject.name = 'root'
include 'common'
In root's build.gradle type:
buildscript {
ext.kotlin_version = '1.3.11'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
subprojects {
buildscript {
repositories {
mavenCentral()
}
}
apply plugin: 'kotlin'
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
}
And now I'd like to use another library only in specific child project. Do this in common's build.gradle:
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}
It's work fine when running gradle commands from root's folder, but failed with message Could not get unknown property 'kotlin_version' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler when running from common's folder.
What I'm doing wrong? Or is there any way around? And what are best practices for sharing libs and properties in multi-project?
For me, it looks like common know nothing about it's "parent" project, all relations defined in root's settings.
The reason why Gradle cannot resolve the property is because the project in folder common is named commons. This is caused by a spelling mistake in common's settings.gradle. This is fortunately easy to fix (common/settings.gradle) :
rootProject.name = 'common'
Alternatively, just delete the common/settings.gradle, it's fully optional in this case.
Consider reading the official Gradle documentation for authoring multi-project builds and the guide create multi-project builds for more information and best practices around multi-project builds.

Can I Define The buildscript repositories In The Root Project For All Modules

I have code similar to the following in each of my sub-modules but with different plugins
buildscript {
ext {
springBootVersion = '2.0.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
Can the repositories be set in the root project so I don't repeat it?
I already have the main repositories section set in the root like this but this question is for the plugins and the buildscript section.
allprojects {
repositories {
jcenter()
maven { url 'https://jitpack.io' }
}
}
The  buildscript block can't be put into a separate file and then imported, it's a special one.
What you can do on the other hand is to put your buildscript block into the build.gradle file of the root project and then all other build files from subprojects will inherit this block.
You can copy the repositories from the buildscript of the root project, like this:
buildscript {
repositories.addAll rootProject.buildscript.repositories
// plugin dependencies, etc, go here
}
You still have to copy that one line to the buildscript block of your subsidiary Gradle file, but at least it is just one line. This works both for subprojects, and also for additional .gradle files you include using apply from:
You can even put that one-liner into a method in build.gradle:
rootProject.ext.setupPluginRepos = {
it.repositories.addAll rootProject.buildscript.repositories
}
So then your subproject (or Gradle file) just has to do this:
buildscript {
rootProject.ext.setupPluginRepos(it)
// plugin dependencies, etc, go here
}
I wrote a custom Gradle plugin, used for certain internal projects at my employer. It adds an extension to every project, let us just call it xyzzy (not its actual name). So I added the above setupPluginRepos to my plugin, and now I just have to do:
buildscript {
xyzzy.setupPluginRepos(it)
// plugin dependencies, etc, go here
}

How to configure Gradle to find local SNAPSHOT resource?

I'm trying to do some work with the springfox project which has been broken up into two separate projects: the springfox runtime, and a suite of demos.
In order to investigate the behavior of certain configurations, I need to change the module in springfox/springfox-petstore, and compile that into springfox-demos/springfox-java-swagger.
In springfox, I built and published a new version of springfox-petstore, and validated that it exists correctly in ~/.m2/repository/io/springfox/springfox-petstore/2.2.2-SNAPSHOT.
Next, in springfox-demos I added mavenLocal() as a repository, and added the springfox-petstore-2.2.2-SNAPSHOT as a changing=true dependency.
When I attempt to build the springfox-demos runtime, I get the following error:
* What went wrong:
A problem occurred configuring project ':spring-java-swagger'.
> Could not resolve all dependencies for configuration ':spring-java-swagger:runtimeCopy'.
> Could not find io.springfox:springfox-petstore:2.2.2-SNAPSHOT.
Searched in the following locations:
https://jcenter.bintray.com/io/springfox/springfox-petstore/2.2.2-SNAPSHOT/maven-metadata.xml
https://jcenter.bintray.com/io/springfox/springfox-petstore/2.2.2-SNAPSHOT/springfox-petstore-2.2.2-SNAPSHOT.pom
https://jcenter.bintray.com/io/springfox/springfox-petstore/2.2.2-SNAPSHOT/springfox-petstore-2.2.2-SNAPSHOT.jar
http://oss.jfrog.org/artifactory/oss-snapshot-local/io/springfox/springfox-petstore/2.2.2-SNAPSHOT/maven-metadata.xml
http://oss.jfrog.org/artifactory/oss-snapshot-local/io/springfox/springfox-petstore/2.2.2-SNAPSHOT/springfox-petstore-2.2.2-SNAPSHOT.pom
http://oss.jfrog.org/artifactory/oss-snapshot-local/io/springfox/springfox-petstore/2.2.2-SNAPSHOT/springfox-petstore-2.2.2-SNAPSHOT.jar
Required by:
springfox-demos:spring-java-swagger:unspecified
I've tried a variety of combinations of build tasks but I can't seem to get Gradle to honor my request for using the local maven repo with a -SNAPSHOT artifact.
Here is the top-level build.gradle:
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath "com.github.adrianbk:gradle-jvmsrc-plugin:0.6.1"
classpath 'com.ofg:uptodate-gradle-plugin:1.6.0'
}
}
apply from: "$rootDir/gradle/dependencies.gradle"
subprojects {
apply plugin: 'com.github.adrianbk.jvmsrc'
jvmsrc {
packageName "springfoxdemo"
}
apply plugin: 'java'
apply plugin: 'com.ofg.uptodate'
repositories {
jcenter()
maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
configurations.all {
//Dont cache snapshots
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
}
wrapper {
gradleVersion = "2.4"
}
So it appears that the top-level build.gradle can have more than one repositories{} block. I had correctly added the mavenLocal() to one, but missed the other. Once adding the mavenLocal() to the second block, all worked well.

How to apply plugin to allprojects with new Gradle plugins mechanism?

Before Gradle 2.1 I could apply plugin to all projects by using allProjects closure (by prevoisly resolving the jar, of course):
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.0.1"
}
}
allprojects {
apply plugin: "com.jfrog.artifactory"
}
With new publishing mechanism it looks like the plugins closure can't be used inside allprojects:
allprojects {
plugins {
id "com.jfrog.artifactory" version "3.0.1"
}
}
fails with:
"Could not find method plugins() for arguments [build_xxxx_run_closure1_closure4#yyyyy] on root project"
What are the rules of using plugins closure? Is the plugin applied to current project only? If so, how can I apply it to all projects without repeating the plugins closure inside each build?
The new plugins {...} syntax cannot be used within a allprojects {...} or subprojects {...} closure. Additionally, it can only be used within build scripts (no script plugins, init scripts, etc). If you want to avoid having to apply the plugin to each project individually I'd suggest using the old notation. This is an issue the Gradle team is aware of and a solution will be introduced in future versions.
Update: Starting with Gradle 3.0 you can do this in a slightly modified way. You still have to explicitly use apply() but you no longer have to deal with all the buildscript { } nonsense to get the plugin on your classpath. This also allows you to conditionally apply plugins. Check out the Gradle 3.0 release notes for more information.
plugins {
id 'my.special.plugin' version '1.0' apply false
}
allprojects {
apply plugin: 'java'
apply plugin: 'my.special.plugin'
}

Resources