Defining cross project versions for gradle build - gradle

I have a several projects in a flat structure with dependencies between them.
Currently in each one a have a definition similar to this defining the versions used within the build script:
ext {
versions = [
scala: '2.11.1',
scalatra: '2.3.0',
jetty: '9.1.5.v20140505',
scalaTest: '2.3.0',
junit: '4.8.1',
]
}
and later usage:
compile group:'org.scala-lang' , name:'scala-library',version: versions.scala
As I have this defined in each build.gradle what I would rather want is to define the versions in one place and read in all files in the current build.
Writing to a global value will not be sufficient here as the combination of build files involved in a build may change (e.g. when testing a specific component only none of the components depending on it will be defined)

Put this map into its own .gradle file and include into your projects with apply from: '../dependencies.gradle'. Similar to what Gradle has in its own codebase

Related

Gradle equivalent for maven properties

How can I add properties in Gradle which are similar to Maven's properties?
The use case is this: I want to have a file which declares all versions for repo dependencies so they are unified in a single place for a multi module project
compile group: 'javax.servlet.jsp.jstl', name: 'jstl', version: '1.2'
In Maven you can have properties like this:
<properties>
<jstlVersion>1.2</jstlVersion>
</properties>
Is it ok to use Gradle's external properties? Or just add them to the gradle.properties file?
Project properties defined in the root build file are available to subprojects. So if you have this in your root build.gradle file:
ext.commonsLangVersion = "2.4"
then you can use that in the dependencies {} block of a subproject like so:
dependencies {
implementation "commons-lang:commons-lang:${commonsLangVersion}"
}
You can also define such properties in the root gradle.properties file instead of the root build file. You use them in the same way.
If you really feel the need to put the versions in a separate file, you can do so. Simply add the following line to the root build file:
apply from: "dependencies.gradle"
Within the dependencies.gradle file, you can define the extra project properties as if they were in the root build file directly:
ext.commonsLangVersion = "2.4"
Note Normally, the values set in the build script take precedence over the values in gradle.properties. But if you set a value in the root build script as above, then any matching value in gradle.properties will override it in subprojects.
This behaviour is somewhat confusing and unique. For behaviour that is consistent with Gradle single-project builds you would need to use the following in the root build script:
allprojects {
apply from: "dependencies.gradle"
}
As a general rule of thumb, any given property should be declared/defined in either the build script or gradle.properties. If users want to override a particular property value, they can do so in $USER_HOME/.gradle/gradle.properties.
[EDIT I have updated the above note to clarify the actual behaviour]
One final thing: Gradle also allows you to control the versions of transitive dependencies via dependency constraints. You can also import Maven BOMs if you're using Gradle 4.6 or newer.
Found this as a possible solution, though I don't really like that uses relative path to the properties file.
Point 7 from here:
https://proandroiddev.com/make-your-build-gradle-great-again-c84cc172a654#8029

Gradle: Project dependencies from file

I'm fairly new to Gradle, and am enamored by its task-driven approach and customizability. So I have a question that hopefully helps me understand how to do something beyond the basics.
Suppose I have a simple text file that contains information about a project's dependencies. For example, something like
- dependency1
from: 'foobar'
version: '1'
- dependency2
from: 'foobaz'
version: '1'
Note that these are not I have some code that would, from this file, generate a file along the lines as follows:
compile 'commons-lang:commons-lang 2.6'
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
Is there a way to configure my project so that my project's dependencies are taken from this file (not exclusively)?
Do note that the text file is also used to generate other artifacts that are used by other tasks (for example, a file to be added to a Docker container), so while it may be possible to, say, declare the dependencies normally and generate the text file instead, it is not a trivial process to do so at this time.
Yes, you can write your own groovy function that parses the file and creates a List. Then you can pass this map to the dependencies closures:
List<String> compileLibraries() {
// ... parse yaml and return list
}
dependencies {
compile compileLibraries()
}
Also, to use a yaml-parsing library, consider setting up a custom gradle subproject in the special buildSrc subfolder and writing your helper function there.
See this old post for more details: https://discuss.gradle.org/t/programmatically-adding-dependencies/7575/12
And here for buildSrc projects:
https://docs.gradle.org/current/userguide/organizing_build_logic.html#sec:build_sources

Gradle dependency on module of another project failing

I realize there are a lot of posts online regarding Gradle setup. That being said, I have researched heavily and not found exactly what I'm looking for, or I'm using incorrect terms to do so. I'm using Gradle version 3.3.
So I've got multiple Gradle projects, each of which is maintained separately. There is no master Gradle project. Each projects has its own modules, build, and settings file. The structure of this is as so:
Projects
A
a1
build.gradle
a2
build.gradle
build.gradle
settings.gradle
B
b1
build.gradle
b2
build.gradle
build.gradle
settings.gradle
What I'm attempting to do is make B dependent on A's modules. Let's assume one of the modules in B is dependent on a1. In B's settings, I've done the following:
rootProject.name = 'B'
rootProject.setProjectDir(new File(".")
include 'a1'
project(':a1').setProjectDir(new File(settingsDir.getParentFile(), "/A/a1"))
The way I'm storing version numbers is through each project's build.gradle file in the ext closure. I then access them through the project. Here's how B's build file looks:
ext {
freemarkerVersion = '2.3.19'
}
dependencies {
compile project(':a1')
compile group: 'org.freemarker', name: 'freemarker', version: rootProject.properties.get('freemarkerVersion')
}
What I'm seeing is B is able to resolve its dependencies and is attempting to compile project a1, but it is using B's version numbers instead of A's. I verified this by putting a common dependency in both projects with different version numbers. The dependency showed up using B's version. I also changed the version number in B and further confirmed this. So if I could get any help for using project-appropriate versions in each of their own build.gradle files, that would be great!
EDIT: Updated post, figured out previous problem was from relative path not resolving.
Not to toot my own horn or anything, but I'm posting the solution I came up with, as I had no other answers knocking down my door.
The first thing I did was moved all of my version properties to an external gradle.properties file, instead of in an ext closure in the project's build.gradle file. Doing this, the project will load the properties file by default when compiled from its own context. It will of course be overridden from the user.home gradle.properties file, so keep this in mind. Example gradle.properties:
a_freemarkerVersion = 2.3.19
When using one project's modules from another project, you'll need a way to separately link the two so Gradle can resolve the dependency's properties. I achieved this by defining a method to load in the desired project's properties file. This method looks like so:
def addConfig(String parent, String filename) {
Properties props = new Properties()
props.load(new FileInputStream(new File(project.projectDir.getParent(), "/${parent}/${filename}")))
props.each { prop ->
project.ext.set(prop.key, prop.value)
}
}
addConfig("A", "gradle.properties")
All this method does is goes up one directory, goes into the project specified, and retrieves its gradle.properties file and loads these variables into the current project's properties. With that being said, there's one thing to note here: if you define the same variable in both, one of them will be overridden. To avoid this, I just prefixed all variables with the project name and then an underscore. This will guarantee they'll never conflict with one another.
I accessed the variables in all projects with this syntax:
dependencies {
compile group: 'org.freemarker', name: 'freemarker', version: "${a_freemarkerVersion}"
}
The rest of the setup is the same as I defined in my initial post. Just make sure to include the dependent module, specify its project directory, and compile that project from within the project's dependencies.

How to use Afterburner.fx with Gradle instaed of Maven 3, while leaving the original project structure of afterburner.fx

afterburner.fx for JavaFX 8 is a minimalistic (3 classes) JavaFX MVP framework based on Convention over Configuration and Dependency Injection created by Adam Bien.
afterburner.fx use Maven 3.
I would like to use it with Gradle.
How to use Afterburner.fx with Gradle instaed of Maven 3, while leaving the original project structure of afterburner.fx ?
In the build.gradle File add dependencies
dependencies {
compile group: 'com.airhacks', name:'afterburner.fx', version: afterburnerfxVersion
}
In the build.gradle File add the additional Resources (.fxml , .css , .properties)
sourceSets.main.resources.srcDirs("src/main/java").includes.addAll(["**/*.fxml", "**/*.css", "**/*.properties"])
and (re-)add all the standard Resources (in the resources folder)
sourceSets.main.resources.srcDirs("src/main/resources").includes.addAll(["**/*.*"])
Update for Gradle Version 6.8.1 : if you run gradlew with --warning-mode all there is a deprecated Message:
Copying or archiving duplicate paths with the default duplicates strategy has been deprecated. This is scheduled to be removed in Gradle 7.0.
Solution
add this line:
// from https://docs.gradle.org/6.8.1/userguide/upgrading_version_5.html#implicit_duplicate_strategy_for_copy_or_archive_tasks_has_been_deprecated
// and https://docs.gradle.org/current/userguide/java_plugin.html
// Java Plugin Task processResources(type: Copy)
processResources.duplicatesStrategy = DuplicatesStrategy.INCLUDE // allow duplicates
Thanks, this helped me a lot. I added the short form of it to dependencies:
compile 'com.airhacks:afterburner.fx:1.6.0'
Additionally I added a second line to include the files from the resources folder and not only from /java. I also added **/*.png to include png files because new Image("filename.png") wasn't working anymore.
sourceSets.main.resources.srcDirs("src/main/java").includes.addAll(["**/*.fxml", "**/*.css", "**/*.properties", "**/*.png"])
sourceSets.main.resources.srcDirs("src/main/resources").includes.addAll(["**/*.fxml", "**/*.css", "**/*.properties", "**/*.png"])
I don't know why the above two lines broke the default behavior - seems like I have to add every new file type to the above lines. :/ If anyone has a better solution please tell me.

Gradle - Recursively include external project and its subprojects

I have a gradle project with many submodules named shared-library.
I have a project named service that depends on one of the modules of shared-library. e.g., it depends on :shared-library:module1. Normally, I get this dependency from maven.
Now I want to modify shared-library and test my changes using the dependent project. Instead of making a change to shared-library, building, deploying to maven, then rebuilding my service, I'd like to instead have service depend on the shared-library gradle project directly.
So I found out that you can point gradle to arbitrary project directories on the filesystem:
service/settings.gradle
include "shared-library"
project(":shared-library").projectDir = new File("/projects/shared-library")
But when I do this, the project is not aware of shared-library's submodules. I cannot do this:
service/build.gradle
compile(
project(":shared-library:module1"),
)
So I tried includeing them directly. :shared-library:module1 depends on :shared-library:module2 so I include that one as well:
service/settings.gradle
include "shared-library"
project(":shared-library").projectDir = new File("/projects/shared-library")
include "shared-library:module2"
include "shared-library:module1"
But now when I try to run this, it complains that :shared-library:module1 cannot locate a project named :module2. This is because its dependency is configured as such:
shared-library/module1/build.gradle
compile(
project(":module2")
)
But if I change that to an absolute project path, now shared-library cannot compile on its own:
shared-library/module1/build.gradle
compile(
project(":shared-library:module2")
)
tl;dr, it seems like there is a mismatch between the way service resolves the shared-library submodule names and how shared-library does it.
You're right. You can import an external project, or even external subprojects, and reference them in your main project, but as soon as you compile the external entities they fail to resolve with the expected names.
I found that you can rename the external projects in your main project so that they match the names of the external projects. That way your main project and the external projects use the same name.
Change your service/settings.gradle to:
include "shared-library"
project(":shared-library").projectDir = new File("/projects/shared-library")
include "shared-library:module2"
project('shared-library:module2').name = ':module2'
include "shared-library:module1"
project('shared-library:module1').name = ':module1'
Now in your project and external project refer to your modules always as :module1 and :module2. In service/build.gradle use:
compile(project(":module1"))

Resources