Configuring Repositories for All Projects in Gradle - gradle

I am trying to configure repositories for all subprojects.
I have the main build.gradle:
buildscript {
repositories {
mavenLocal()
mavenCentral()
google()
jcenter()
...
}
dependencies {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
plugins {
id 'base'
}
allprojects {
apply plugin: 'base'
repositories {
mavenLocal()
mavenCentral()
google()
jcentre()
...
}
wrapper{
gradleVersion = '6.5.1'
distributionType = Wrapper.DistributionType.ALL
}
dependencies {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
In the subprojects build.gradle I just have:
...
dependencies {
implementation ....
}
I am getting:
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
> Cannot resolve external dependency .... because no repositories are defined.
Required by:
project :
I want to define repositories once in the main file as these do not change in subprojects.
In the settings.gradle of the main project I have:
rootProject.name = 'main-project-name'
include 'sub-project-name'
And in the settings.gradle of the sub project I have:
rootProject.name = 'sub-project-name'

A multi-project build in Gradle may have multiple build.gradle files, but only one settings.gradle file (usually in the root project directory). Your second settings.gradle files defines a second setup that only contains a single project. You can check this by running gradle projects. Just delete the second settings.gradle file to solve your problem.
Usually you can simply define the names of your sub-projects by naming the respective directories and then calling include. The name of the rootProject may be defined inside settings.gradle, because the name of the directory is often not stored in version control systems like Git. Developers may check out the repository to different directories causing Gradle to use different names for the root project. If you want a subproject to have a different name than its containing directory, use include with the desired name and then change the project directory via project(':foo').projectDir = file('path/to/foo').

Modern Gradle versions provide a recommended way to declare dependencies in a centralized way.
TLDR: Use the dependencyResolutionManagement DSL in your settings files to configure the repositories in all the subprojects. Both Groovy and Kotlin DSL look the same 👇
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}
Read more in the docs: "Centralizing repositories declaration".

Related

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
}

Gradle buildSrc and buildscript

We have a Gradle build that includes a buildSrc with some custom plugins. Those plugins apply yet other plugins. For example, our plugin applies com.android.tools.build:gradle. For annotation processing that library needs to be on Gradle's classpath during compilation. So, putting this in our main build.gradle works:
buildscript {
repositories {
google()
}
dependencies {
classpath "com.android.tools.build:gradle:$gToolsVersion"
}
}
However, that means that for a user to apply this plugin they must (1) apply our plugin and (2) add that buildscript boilerplate. It seems like that shouldn't be necessary. We can also add a project.buildscript block inside our plugin but that too seems unnecessary and, due to this bug is problematic: https://developer.android.com/studio/build/gradle-plugin-3-0-0.html?utm_source=android-studio#known_issues.
I added the com.android.tools.build:gradle dependency to buildSrc/build.gradle as a runtime dependency. It seems like that should work: I thought that tells Gradle that in order to run my plugin that library (and its dependencies) need to be on the classpath. However, gradle buildEnvironment (and the fact that our build fails) makes it clear that's not the case.
So, questions:
What's the difference between a runtime dependency specified in buildSrc/build.gradle and a classpath dependency specified in a buildscript block in a regular build.gradle?
How can I arrange things so that users can apply the plugin from buildSrc and not have to also add the buildscript block to their build.gradle?
I got a slightly different problem and found an acceptable solution that might help with for your second question: I wanted to apply the same repositories in the buildSrc/build.gradle and twice in the root build.gradle.
repositories.gradle in the project root:
repositories {
if (project.hasProperty('nexus')) {
maven {
url 'http://localhost:8081/repository/JCenter/'
}
maven {
url 'http://localhost:8081/repository/Maven_Google/'
}
} else {
jcenter()
google()
}
}
ext {
androidGradleBuildToolsDependency = 'com.android.tools.build:gradle:3.1.3'
}
buildSrc/build.gradle:
buildscript {
apply from: '../repositories.gradle'
}
allprojects {
apply from: '../repositories.gradle'
}
dependencies {
// androidGradleBuildToolsDependency is defined in repositories.gradle
implementation androidGradleBuildToolsDependency
}
Root build.gradle:
buildscript {
apply from: 'repositories.gradle'
}
allprojects {
// this line will also be executed from the build.gradles in subprojects, so the working
// directory isn't always the same, so we use the absolute path here
apply from: "${rootProject.projectDir}/repositories.gradle"
}
Note that you do not need the classpath dependency inside the buildscript block of the root build.gradle as you normally would. The implementation dependency in the repositories.gradle seems to auto apply it.
My solution probably doesn't work when the build.gradles are supplied via a dependency.
Stumbled upon this while digging into a tangential problem.
I've been successfully using buildSrc/build.gradle as the place to define dependencies that would normally belong in the root-project's buildscript classpath for a few of my projects.
You can see a working example here: https://github.com/episode6/chop/blob/develop/buildSrc/build.gradle
I used to use compile dependencie but just switched to runtimeClasspath which feels more appropriate and also works. I don't think your classpath dependencies were working because they would be on the classpath of the buildSrc project, but not compiled into or run along side it.
If you decide to go this route, you may run into the problem I was just digging into which only came up because of this approach.
When I tried this approach with the dokka plugin, I got the following error
Could not resolve all files for configuration ':detachedConfiguration1'.
> Cannot resolve external dependency org.jetbrains.dokka:dokka-fatjar:0.9.17 because no repositories are defined
I was able to workaround this by adding jcenter() to the root project's buildscript repositories: https://github.com/episode6/chop/blob/develop/build.gradle#L2

Gradle custom plugin dependencies

If a have a custom plugin which handles the building and deploying of a specific component, where do I list the dependencies (other components in my system) which are required for the build?
Dependencies for your Gradle plugins should be listed in the buildscript portion of the build.gradle file. See this chapter of the User Guide, which also has an example:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
}
}
apply plugin: "com.jfrog.bintray"
If your custom plugin depends on jar files on your local machine, I gather that you need to add those files as a "flatDir" repository in the repositories entry, as described here:
repositories {
flatDir {
dirs 'lib1', 'lib2'
}
}

How to generate a war file based on two subprojects

I have a project which is splitted into two subprojects.
/project
/sub-project-a (backend with JAVA source which is compiled into JAR file)
/sub-project-b (frontend sources which are compiled with grunt via gradle call)
build.gradle
settings.gradle (contains include 'sub-project-a', 'sub-project-b')
My Question is how can I create a War file with sub-projects and external lib dependencies? The following code snipped is my current build.gradle:
apply plugin: 'war'
version '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compile project(':sub-project-a')
compile project(':sub-project-b')
compile 'com.google.code.gson:gson:2.2.4'
}
task copy(type: Copy) {
from 'sub-project-a/build', 'sub-project-b/build'
into 'build'
}
build.dependsOn clean, copy
war {
archiveName 'project.war'
}
One detail is important. The java context listener (deep inside project code) work with compiled backend as jar file from WEB-INF/lib folder. This means that all class files can't be easily used from WEB-INF/classes folder.
As you can see I played with dependencies and a custom copy task. I'm not sure what is right gradle way. How should I do this?
SOLUTION
Define with war.from methode, where you get your static sources.
gradle docu
from(sourcePaths) -
Specifies source files or directories for a copy. The given paths are
evaluated as per Project.files().
My changed build.gradle
apply plugin: 'war'
version '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.code.gson:gson:2.2.4'
}
war {
archiveName 'project.war'
from 'sub-project-a/build/dist', 'sub-project-b/build/dist'
}
SOLUTION (for cleanly closing this question) shamefully taken from the question's originator ;-)
Define subproject dependencies with the "war.from" method, where you get your static sources.
gradle documentation excerpt: from(sourcePaths) - Specifies source files or directories
for a copy. The given paths are evaluated as per Project.files().
Ronny's changed build.gradle
apply plugin: 'war'
version '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.code.gson:gson:2.2.4'
}
war {
archiveName 'project.war'
from 'sub-project-a/build/dist', 'sub-project-b/build/dist'
}

Resources