How to set a dependency for a project with all subprojects? - gradle

I don't like that I repeat every repository dependency (let us say, junit), for the main project and for subprojects. Is there a possibility to make the subproject to use the dependencies of the main project. Or is there another way to escape that repetition?

Unlike the accepted answer it's better to use the following:
allprojects {
plugins.withType(JavaPlugin) {
dependencies {
testCompile 'junit:junit:4.12'
}
}
}
The changes will be applied immediately if java plugin already exists or will watch for it to be added and apply later.
Updated
At the moment I use better way to control configuration for plugin - pluginManager. The effect is the same as for plugins.withType, but you don't have to know plugin's class name:
Example for org.springframework.boot plugin:
apply plugin: 'org.springframework.boot'
allprojects {
pluginManager.withPlugin('org.springframework.boot') {
springBoot {
buildInfo()
layout 'DIR'
}
}
}

root/build.gradle
allprojects {
if (plugins.hasPlugin('java')) {
dependencies {
testCompile 'junit:junit:4.12'
}
}
}

Related

Remove transitive classpath dependency - plugins block

I want to remove the log4j transitive dependency from the shadow gradle plugin.
plugins {
id 'com.github.johnrengelman.shadow' version '7.1.2'
}
I search for a solution but did not get any. I know I can remove this using the following code -
buildscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.1.2', {
exclude module: 'log4j'
}
}
}
But is there any way to do this with plugins block?
No, the plugins { } is itself a DSL which is limited by design. This is documented in the documentation:
https://docs.gradle.org/current/userguide/plugins.html#sec:constrained_syntax
The plugins {} block does not support arbitrary code. It is constrained, in order to be idempotent (produce the same result every time) and side effect free (safe for Gradle to execute at any time).
It is designed to do one thing and one thing only: apply plugins.
I used following code to exclude the dependency -
buildscript {
repositories {
..
}
dependencies {
..
}
configurations.classpath {
exclude module: 'log4j'
}
}
plugins {
id 'com.github.johnrengelman.shadow' version '7.1.2'
}

new gradle format confusion and migrating causes Could not find method testCompile()

I have a build.gradle with
plugins {
id {some plugin for all projects}
id "com.diffplug.spotless" version "5.1.1"
}
AND THEN I have an allprojects {} section that defines ONE apply plugin: 'jacoco' and a subprojects {} section that declares apply plugin: 'java' with a few others
Immediately adding spotless messed with stuff and errors out that it cannot find the java plugin so then I modify ALL plugins to be in the plugins section like so
plugins {
id "java"
id "checkstyle"
id "eclipse"
id "idea"
id "jacoco"
id "com.diffplug.spotless" version "5.1.1"
id "com.dorongold.task-tree" version "1.5" //This prints out a task tree (pretty print)
}
This then results in this error
Could not find method testCompile() for arguments [junit:junit:4.11] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
So for some reason the java plugin is lost. I can't figure out the right combination here to migrate everything to this new plugins section format.
How do I do that? I randomly tried putting a plugins section in allprojects and subprojects but that results in this new error
Could not find method plugins() for arguments [build_d8c2jgy4ua1m0vkv9kmvgefmc$_run_closure2$_closure5#62337fda] on root project 'providersvc-all' of type org.gradle.api.Project
How does this new plugins section work? I can't seem to migrate without it breaking everything. I just want java plugin, testCompile, and spotless to play nicely together right now
EDIT(forgot to attach the full trimmed down file that does not work):
plugins {
id "java"
id "com.diffplug.spotless" version "5.1.1"
}
ext {
//dependency versions every project usees so we version in one location all jars(less jar hell this way)
deps = [
'junit': 'junit:junit:4.11'
]
}
allprojects {
repositories {
jcenter()
mavenCentral()
maven {
//webpieces VERSIONED snapshots so you can lock on a snapshot
url "https://dl.bintray.com/deanhiller/maven"
}
//For testing locally
maven {
url uri('/tmp/myRepo/')
}
}
}
subprojects {
dependencies {
testCompile deps['junit']
}
}
thanks,
Dean
You are only applying the plugins to the root project - not the sub-projects. However, if you like to configure plugins through the subprojects configuration, you have to use the apply plugin syntax. But you don't have to use the old buildscript block for configuring the classpath and repositories if you a combination of the two.
Here is an example. I am assuming the root project is not a Java project. I have also removed your comments and inserted mine instead for the sole reason to make them easier to spot.
plugins {
id "com.diffplug.spotless" version "5.1.1" apply false // <-- Set "apply false" here
// This makes it configure which version to use on the classpath for the entire build, but without applying it.
// Notice that the Java plugin is not specified here anymore.
// This is because it is a core plugin so you can't set the version (and I am assuming you don't want it on in the root project).
}
ext {
deps = [
'junit': 'junit:junit:4.11'
]
}
allprojects {
repositories {
jcenter()
mavenCentral() // <-- You can remove this if you want as it is already present as a proxy in jcenter().
maven {
url "https://dl.bintray.com/deanhiller/maven"
}
maven {
url uri('/tmp/myRepo/')
}
}
}
subprojects {
// Here are the two plugins
apply plugin: "java"
apply plugin: "com.diffplug.spotless"
dependencies {
testImplementation deps['junit'] // <-- testCompile renamed to testImplementation as the former has been deprecated for a long time
}
}

Control the gradle task execute order

I have a strange problem about gradle task recently.
Assume I have a simple gradle config as follows
apply plugin: "java"
apply plugin: "maven"
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "com.diffplug.gradle.spotless:spotless:2.0.0"
}
}
apply plugin: "com.diffplug.gradle.spotless"
spotless {
java {
eclipseFormatFile 'format.xml' // XML file dumped out by the Eclipse formatter
}
}
spotlessJavaCheck.dependsOn(processResources)
version = '1.0-SNAPSHOT'
I just want to set the depends on relationship for the spotless check. After I run a build, the error looks like this
> Could not find property 'spotlessJavaCheck' on root project 'gradle-helloworld'.
I have done something similar with other plugins, it works well, but not for this spotless plugin.
Br,
Tim
Spotless Gradle plugin does magic at configuration time.
You need to set the dependency after evaluation time, once the magic is done:
afterEvaluate {
tasks['spotlessJavaCheck'].dependsOn processResources
}

Gradle Custom buildScriptRepository methods

I would like to make a custom buildScript repository method so I can easily reference our internal maven repo. Right now I'm required to declare a maven block everywhere we use our plugin.
Here is the current setup
buildscript {
repositories {
jcenter()
maven { url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
What I would like to do is something like this
buildscript {
repositories {
jcenter()
myReleaseRepo()
}
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
How can I make a method available to create a repository anywhere we may use the plugin in the future?
Another solution is to add custom methods on RepositoryHandler using some Groovy goodness. Just chuck this in ~/.gradle/init.gradle
RepositoryHandler.metaClass.myReleaseRepo = {
delegate.maven {
name 'myReleaseRepo'
url 'http://myNexus:8081/nexus/content/repositories/My-Release'
}
}
After that, you can use it just as you described:
buildscript {
repositories {
myReleaseRepo()
}
}
Metaclasses in Groovy are just great. The delegate in this case is pretty much like the javascript this. This code is essentially using the RepositoryHandler instance (delegate keyword) and just calling repositoryHandlerInstance.maven(name, url).
It is possible to add a repo to an init script which would then apply to all gradle invocations that use the init script - without having to individually declare your maven repo in each build.gradle.
Solution 1:
Partial solution, does not do exactly what you're asking for. In init.gradle:
allprojects{
buildscript{
repositories{
maven{ url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
}
}
Then your build.gradle can skip buildscript repo declaration entirely:
buildscript {
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
Solution 2:
In fact, you can even move your buildscript classpath declaration to init and have the plugin apply to all projects that use the init script:
beefier init.gradle
allprojects{
buildscript{
repositories{
maven{ url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
}
gives you a lighter build.gradle
apply plugin: 'my-plugin'
I tried to, but apparently you cannot move the apply line to init.gradle as well. see this defect.
Solution 3:
I retract what I said in the comment above, I figured out how to do exactly what you're asking for. Apparently you can create extensions for the buildscript block using the initscript. However I still prefer solution2, because it gives you a cleaner build.gradle.
To create a buildscript extension, in your init.gradle:
class customRepos {
def buildscript
customRepos(buildscript) {
this.buildscript = buildscript
}
void addMyRepo() {
buildscript.repositories {
maven{ url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
}
}
allprojects {
extensions.create('myRepo', customRepos, buildscript)
}
which then allows you to do this in your build.gradle
buildscript{
myRepo.addMyRepo()
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
apply plugin: 'my-plugin'

Building a fully executable Spring Boot 1.3 war from a Gradle multi project build

I'm trying to build a fully executable WAR using Spring Boot 1.3 as per https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html. If I build a single Gradle project, it all works fine, but I havea multi project build, where I have a "root" project and then several projects underneath it, and I cannot get it to build anything but a standard, "fat" WAR file, without the providedRuntime of Jetty and without the scripts to make it run.
Does anyone know how to do this?
In my root project, I have the following (abridged):
buildscript {
repositories {
mavenCentral()
}
ext {
springBootVersion = '1.3.0.RELEASE'
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
}
allprojects {
//Put instructions for all projects
repositories {
mavenCentral() // jcenter is missing spring-orm.4.1.6.RELEASE jar file so try mavenCentral first
jcenter {
url "http://jcenter.bintray.com/"
}
maven { url 'http://repo.opensourceagility.com/release' }
}
}
subprojects {
apply plugin: 'java'
apply plugin: 'spring-boot'
}
and then in the subproject which is a web project, and which I'm trying to build, I have:
apply plugin: 'war'
dependencies {
// Include related projects
compile project(':project-model')
compile project(':project-dynamoDB')
// Core Spring Boot - note version is set in main build.gradle file
compile 'org.springframework.boot:spring-boot-starter-web'
// Remove Tomcat (included in -web) and include Jetty instead
providedRuntime 'org.springframework.boot:spring-boot-starter-jetty'
// Other Spring modules
compile 'org.springframework.boot:spring-boot-starter-social-facebook'
compile 'org.springframework.boot:spring-boot-starter-social-linkedin'
compile 'org.springframework.social:spring-social-google:1.0.0.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
compile 'org.springframework.boot:spring-boot-starter-security'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.springframework.boot:spring-boot-devtools'
compile 'org.springframework:spring-context'
compile 'org.springframework:spring-context-support'
}
configurations {
providedRuntime.exclude group: 'org.springframework.boot', module:'spring-boot-starter-tomcat'
all*.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' // exclude when using log4j
}
springBoot {
mainClass = 'rs.web.Weblication'
executable = true
}
bootRun {
addResources = true
}
processResources {
// exclude resources if they look like they're profile dependent but don't match the current env/profile
eachFile { d ->
if(d.name.endsWith('.xml') || d.name.endsWith('.yaml') || d.name.endsWith('.properties')) {
//def fname = d.name.replaceFirst(~/\.[^\.]+$/, '')
//if(fname.indexOf("-") > -1 && ! fname.endsWith("-" + environment)) {
// d.exclude()
//} else {
// replace #variables# listed below in properties/config files
filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: [
activeProfiles: environment
])
//}
}
}
}
war {
baseName = 'project-web'
version = '1.0.0'
manifest {
attributes 'Implementation-Title': baseName,
'Implementation-Version': version
}
webXml = file('src/main/resources/web.xml')
// rename the war task which has profiles appended from warName-profile,profile2.war
// to warName-profile.profile2.war
classifier = environment.replaceAll(',','-')
}
but when I build it (./gradlew build, or ./gradlew subprojectname:build), all is well and a working WAR is created, but not an executable one.
With a single project, I have it working fine.
Ah ha, right well I build a test multi-project build and it worked OK, so it was clearly the configuration above.
I worked through a process of elimination and it turns out that the problematic area was the line
classifier = environment.replaceAll(',','-')
which is intended to rename files with environment variables as part of the name. This process seems to get in the way of the script addition; perhaps it could be applied afterwards if it's really necessary.

Resources