gradle, idea plugin and multi-project setup - intellij-idea

I'm trying to setup a multi-module gradle project with idea support. It works until I'm adding project-wide gradle.properties to the mix. Here's an example:
gradle.properties:
javaVersion = 1.8
gradle.settings:
include 'module_a'
build.gradle:
allprojects {
apply plugin: 'idea'
idea {
project {
jdkName = javaVersion
}
}
}
module_a is an empty sub-folder.
gradle idea fails with this:
Build file 'project/build.gradle' line: 7
* What went wrong:
A problem occurred evaluating root project 'project'.
> Cannot set property 'jdkName' on null object
What could be the reason?
Question 2: can a sub-project make modifications to the global idea task, for instance
idea.module.generatedSourceDirs += file('srm/main/java.generated')
Will it only affect module_a if placed in module_a/build.gradle ?
Thanks

You can't set "jdkName" on every subproject, it only should set on the root project like this:
idea {
project {
jdkName = "1.8"
languageLevel = "1.8"
}
module {
name = "My root project name"
}
}
On the sub projects you can config other things like
idea.module.testSourceDirs = idea.module.testSourceDirs+idea.module.sourceDirs
idea.module.sourceDirs = [] as Set

Related

How to reuse dependency versions in subprojects for Kotlin DSL?

I have a multi module Gradle project with Kotlin DSL as build file. Inside of the root build.gradle.kts there is dependencies section for root and subprojects with its own dependencies. I would like to create a variable that can keep version of some dependency and be used in all modules in build.gradle.kts.
Root build.gradle.kts looks like:
buildscript {
// ...
}
plugins {
// ...
}
subprojects {
// repositories, plugins, tasks, etc.
dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.10.4")
}
Submodule common-module/build.gradle.kts
dependencies {
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.10.4")
}
I would like to declare a variable and assign the version for these dependencies as a value and only reuse it on modules. Some thing like implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv:${jacksonVersion}").
How can I do that?
The most modern, type-safe solution of this problem is using version catalogs.
Update Gradle to 7.2.
Add this to your settings.gradle or settings.gradle.kts:
enableFeaturePreview("VERSION_CATALOGS")
gradle/libs.versions.toml:
[versions]
jackson = "2.12.5"
[libraries]
jackson-databind = { module = "com.fasterxml.jackson:jackson-databind", version.ref = "jackson" }
jackson-dataformat-csv = { module = "com.fasterxml.jackson.dataformat:jackson-dataformat-csv", version.ref = "jackson" }
Add dependencies like implementation(libs.jackson.dataformat.csv) in all the subprojects.

GRADLE - You must specify at least one directory for a flat directory repository

I'm trying to build a gradle 2.11 project in Intellij and I keep getting this error kicked back to me. I'm setting a flatDir in the build.gradle file but this error is still coming up when I run gradle idea.
buildscript {
repositories {
flatDir {
dirs "$rootProject.rootDir/lib/gradle-plugins"
}
}
dependencies {
classpath "gradle.plugins:prompt-version-plugin:1.0.0"
classpath "gradle.plugins:properties-plugin:1.0.0"
}
}
idea {
module {
/*
* If you omit [ ] around, it fails with: Cannot change configuration ':provided' after it has been resolved
* This is due Gradle 2.x using Groovy 2.3 that does not allow += for single elements addition.
* More: https://discuss.gradle.org/t/custom-provided-configuration-not-working-with-gradle-2-0-rc2-in-multi-project-mode/2459
*/
scopes.PROVIDED.plus += [configurations.provided]
downloadJavadoc = true
downloadSources = true
}
}
Error
* What went wrong:
Execution failed for task ':ideaModule'.
> You must specify at least one directory for a flat directory repository.
Is there another place to set the flat directory?

Custom source set in Gradle imported to IntelliJ 14

I'm trying to get Gradle (2.1) and IntelliJ (14.0.2) to play nicely. Specifically, I have imported a sample Gradle project containing a separate source set for integration tests into IntelliJ.
The project builds fine using Gradle on the command line, and I'm able to run the integration tests successfully. When running inside IntelliJ on the other hand, I have two problems:
1) Compiling inside IntelliJ fails, due to a dependency in the integration test to a third-party library (commons-collections) which fails to resolve.
2) If I remove the dependency above and compile, I'm not able to run the integration test inside IntelliJ. I get the following error message:
No tests found for given includes: [org.gradle.PersonIntegrationTest.canConstructAPersonWithAName]
The file structure looks like this:
src
integration-test
java
resources
main
java
resources
test
java
resources
build.gradle
And build.gradle:
apply plugin: 'java'
repositories {
mavenCentral()
}
sourceSets {
integrationTest {
java.srcDir file('src/integration-test/java')
resources.srcDir file('src/integration-test/resources')
}
}
dependencies {
testCompile 'junit:junit:4.11'
integrationTestCompile 'commons-collections:commons-collections:3.2'
integrationTestCompile sourceSets.main.output
integrationTestCompile configurations.testCompile
integrationTestCompile sourceSets.test.output
integrationTestRuntime configurations.testRuntime
}
task integrationTest(type: Test, dependsOn: jar) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
systemProperties['jar.path'] = jar.archivePath
}
check.dependsOn integrationTest
Any ideas on how to make this work would be much appreciated.
The full Gradle sample project is available in the Gradle distribution, under samples/java/withIntegrationTests
You need to tell IDEA to map entries from your integrationTest configuration into your project as TEST dependencies. I am not sure whether you need to add source root directories too. The important part is:
idea {
module {
//and some extra test source dirs
testSourceDirs += file('some-extra-test-dir')
generatedSourceDirs += file('some-extra-source-folder')
scopes.TEST.plus += [ configurations.integrationTest ]
}
}
More is described in http://www.gradle.org/docs/current/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html
Edits to reflect Daniel's comments: generatedSourceDirs is is Gradle 2.2+.
To set up the test task you will use task like
task integTest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDir = sourceSets.integTest.output.classesDir
classpath = sourceSets.integTest.runtimeClasspath
reports.junitXml.destination = file("${project.testResultsDir}/$name")
reports.html.destination = file("${project.reporting.baseDir}/$name")
shouldRunAfter test
}
check.dependsOn integTest

Android Studio : Config Gradle file for library project

I have an Android Project, and I want to create a sub-library (just another Android Project) as library for this one.
Here is my Structure:
Project/
settings.gradle
build.gradle
/ProjectA
/ProjectA/build.gradle
/ProjectA/libs
/ProjectA/libs/ProjectB
/ProjectA/libs/ProjectB/build.gradle
ProjectA is my main project. I do as following. In setting.gradle. I add:
include ':ProjectA'
include ':ProjectA:libs:ProjectB'
after that. I copy all information of ProjectA/build.gradle into ProjectB/build.gradle content of file is:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.1"
defaultConfig {
minSdkVersion 9
targetSdkVersion 18
}
buildTypes {
debug {
packageNameSuffix ".debug"
}
}
}
After that, I change ProjectA/build.gradle. Add this line: compile projects(:libs:projectB) to dependencies. After that I receive error :
Project with path ':libs:ProjectB' could not be found in project ':ProjectA'
Please help me how to configure for multiply project in Android Studio.
Thanks :)
Either of these will work:
compile project(':ProjectA:libs:ProjectB')
or
compile project('libs:ProjectB')
The leading colon is like a leading slash on a filesystem path: it makes it an absolute path, starting with the project root. Without a leading colon, it's relative to the module's root.
Having said all that, your project structure is complex. Does ProjectB really need to be contained in ProjectA? Would this work better instead?
Project/
settings.gradle
build.gradle
/ProjectA
/ProjectA/build.gradle
/ProjectB
/ProjectB/build.gradle
I have solution for my problem. Sadly, I see no full tutorial for my problem. And by many mistakes, I can try it by hand.I have try a way : here is my short tutorial. Hope help someone here.
Short Description : I will add a SlidingMenu library to my project. This library is special because :
it's an Eclipse-type project (means : has a slide difference compare to android project create by Android Studio or Intellij IDEA),
so you must have a step config by hand. If this's a normal library
create by Android Studio, you can remove mapping by hand step in below
Gradle file.
It uses v4 support library. Often, your app uses this library too. So, if you compile both same two libries in same project. You will
meet error. So, there is a way : using Android Repository to synchronized. You will not meet exception that two same libraries in one project.
You create a libs folder inside your app. After that, copy whole project library to this folder. For example, I'm using SlidingMenu. After that, you create gradle.build with following content. ( I have added some comments, for easier to follow)
// SlidingMenu is an Eclipse project. so its structure is different. and must config by hand.
// script to decide which gradle version will use for maven
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
// because this is a android library. we change : apply plugin: 'android' to
apply plugin: 'android-library'
// Base Project includes "Support Library v4 jar to its project
// 1. If Not Compile it : this library project cannot compile because missing libraries
// 2. Cannot delete jar file in libs folder. Because its code depend on this libs. Delete jar file turn out that cannot see class file
// 3. My Solution : Use Gradle Repository. By use Gradle Repository, this library will be synchronized between two projects.
// So, just one instance could be used for both project.
dependencies {
compile 'com.android.support:support-v4:19.0.0'
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.1"
// Mapping phrase : use if this library is Eclipse-base project
// modify link because this project is from Eclipse Project
// not from normal gradle Project. So project structure is different. Cannot make default
// Config by hand, get Gradle knows which part for each type of directory
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
Here is main gradle file :
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
// this is main project : so we use apply plugin : 'android'
apply plugin: 'android'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.1"
defaultConfig {
minSdkVersion 9
targetSdkVersion 18
}
}
dependencies {
compile 'com.android.support:appcompat-v7:19.0.0'
compile 'com.android.support:support-v4:18.0.0'
// compile project SlidingMenu
compile project(':Hop Am Chuan:libs:SlidingMenu')
// add this line just for demonstration. you can use or remove it.
// compile files('libs/google-gson-2.2.4/gson-2.2.4.jar')
}
Hope this help :)

Managing project dependencies with Gradle and IntelliJ

I am looking to use Gradle to build my Groovy / Grails based project for which we are using IntelliJ Idea as the IDE.
I am using IntelliJ version 11.1.4, Gradle version 1.2.
My project is a configured as a multi project build with various Groovy & Grails subprojects.
I was hoping that this would give me the same kind of IDE support that I would get if managing the build through Maven, such as:
Automatic dependency management (import new dependencies to IntelliJ when added to various build.gradle)
Build DSL support
Execution of build tasks
Use of the underlying build system (gradle) by the IDE when performing builds\
I have imported my project into IntelliJ by opening the root build.gradle file.
So far I am coming up against a few annoying problems:
IntelliJ is not recognising (or recognising randomly) changes to dependencies in the build.gradle files and therefore dependencies are not being updated.
The gradle "idea" plugin doesn't seem to work with multi module projects.
How are people working with Gradle inside IntelliJ? Are you managing dependencies manually within IntelliJ??
I have been using Gradle "idea" plugin for some time now and it works very well. Since "idea" plugin simply generates IntelliJ project configuration files it is somewhat limited in what you can do with it, but nevertheless, I have had more success with it compared to the IntelliJ gradle support (JetGradle thing).
Gradle "idea" plugin does work with multi-module projects, never had a problem with that. I always put parent project configuration in master folder (see Initialization chapter), which seems to work. Never tried the nested structure though.
In order to do additional IntelliJ configuration you can do some .ipr and .iml tinkering from gradle, or alternatively try using one of my plugins (see Utilities plugin) which will do most of the tinkering for you.
In the end I went with rodion's suggestion above and used the idea plugin. It turns out I had not configured it properly first time I tried it (only applied the plugin to the master project, not subprojects).
I only found this out after writing my own task to update the dependencies for an IntelliJ project (based on the .idea directory layout project structure). I am going to use the plugin as there will be less maintenance, but here is my solution for posterity and in case it is useful to anyone:
ext {
intelliJLibraryDir = "$gradle.rootProject.rootDir/.idea/libraries"
userHomeDir = gradle.gradleUserHomeDir.parent
}
task cleanIntelliJLibraries << {
ant.delete (includeEmptyDirs: 'true') {
fileset(dir: intelliJLibraryDir, includes: '*.xml')
}
}
task createIntelliJLibraries(dependsOn: cleanIntelliJLibraries) << {
// The unique set of dependency artifacts across all subprojects
def uniqueProjectArtifacts = subprojects.collectMany {
if (it.configurations.compile) {
it.configurations.compile.resolvedConfiguration.resolvedArtifacts.findAll {
it.moduleVersion.id.group != "my.project"
}
}
else { [] }
}.unique()
// Output a library xml file for each of the dependency artifacts
uniqueProjectArtifacts.each { artifact ->
def artifactPath = artifact.file.path
def artifactName = artifact.moduleVersion.id.with { "$group:$name:$version" }
def intelliJLibraryPath = artifactPath.replace(userHomeDir, '$USER_HOME$')
def intelliJLibraryFileName = "Gradle__$artifactName".replace(':', '_').replace('.','_') + ".xml"
new File("$intelliJLibraryDir/$intelliJLibraryFileName").withWriter { writer ->
def dependencyXML = new MarkupBuilder( writer )
dependencyXML.component (name: "libraryTable") {
library (name: "Gradle: $artifactName") {
CLASSES {
root (url: "jar://$intelliJLibraryPath!/")
}
JAVADOC {}
SOURCES {}
}
}
}
}
}
task updateIntelliJModules(dependsOn: createIntelliJLibraries) << {
subprojects.each { project ->
def root = new XmlSlurper().parse(new File("${project.name}.iml"))
// Remove the existing dependencies
root.component.orderEntry.findAll { it.#type == "library" && it.#level == "project" }.replaceNode {}
// Add in the new dependencies
if (project.configurations.compile) {
project.configurations.compile.resolvedConfiguration.resolvedArtifacts.findAll {
it.moduleVersion.id.group != "my.project"
}.each { artifact ->
def artifactName = artifact.moduleVersion.id.with { "Gradle: $group:$name:$version" }
root.component.appendNode {
orderEntry (type: "library", exported: "", name: artifactName, level: "project")
}
}
}
def outputBuilder = new StreamingMarkupBuilder()
new File("${project.name}.iml").withWriter { writer ->
groovy.xml.XmlUtil.serialize(outputBuilder.bind{ mkp.yield root }, writer)
}
}
}