I have a Gradle 6.0.1 project. The build.gradle (excerpt) looks like:
plugins {
id "application"
id "com.github.edeandrea.xjc-generation"
id "eclipse"
id "idea"
id "java"
id "org.springframework.boot"
}
...
dependencies {
implementation platform("org.springframework.boot:spring-boot-dependencies:${property("spring-boot.version")}")
// ...more stuff here
}
// ...more stuff here
I'm managing all the plugin versions in settings.gradle:
pluginManagement {
plugins {
id "application"
id "com.github.edeandrea.xjc-generation" version "1.0"
id "eclipse"
id "idea"
id "java"
id "org.springframework.boot" version "${spring-boot.version}"
}
}
rootProject.name = "spring-core"
...and I usually put the artifact versions in gradle.properties:
#
# Dependency Versions
oracle.version = 18.3.0.0
spring-boot.version = 2.2.1.RELEASE
#
# Gradle Settings
org.gradle.configureondemand = false
org.gradle.daemon = false
#
# System Settings
systemProp.file.encoding = UTF-8
systemProp.sun.jnu.encoding = UTF-8
Now the problem is I can't read dot-properties in settings.gradle (from gradle.properties) in the same way I do it inside build.gradle — I already tried using ${property("spring-boot.version")}.
Is there any way to achieve that? I can easily change the key to something like springBootVersion and it works, but I wonder if there is a way to have in the way I currently have it: spring-boot.version.
use getProperty("spring-boot.version")
simple gradle project with additional variants
task test{
doLast {
//success
println project.property('aaa.bbb.ccc')
println project.'aaa.bbb.ccc'
println getProperty('aaa.bbb.ccc')
//failure: Could not get unknown property 'aaa.bbb.ccc' for task ':test' of type org.gradle.api.DefaultTask
println property('aaa.bbb.ccc')
}
}
gradle.properties
aaa.bbb.ccc=12345
property('aaa.bbb.ccc') fails because it tries to get property on current object (task) but aaa.bbb.ccc defined for project
however project.property('aaa.bbb.ccc') succeeds because it should
project.'aaa.bbb.ccc' is the same as project.getProperty('aaa.bbb.ccc') in groovy
project.getProperty('aaa.bbb.ccc') works because of groovy basic object GroovyObject (IHMO)
and getProperty(name) without prefix actualy located in org.gradle.groovy.scripts.BasicScript and not really documented...
For me the solution from #daggett doesn't work. But I was able to access a property defined inside the ~/.gradle/gradle.properties from the settings.gradle this way:
settings.ext.find('MY_PROPERTY')
To provide some context, I'm using this to read the credentials for the Gradle Build Cache Node remote server:
buildCache {
boolean isCiServer = System.getenv().containsKey("CI")
remote(HttpBuildCache) {
enabled = settings.ext.find('GRADLE_BUILD_CACHE_NODE_PWD') != null
url = 'https://myserver:443/cache/'
allowUntrustedServer = true
push = isCiServer
credentials {
username = settings.ext.find('GRADLE_BUILD_CACHE_NODE_USR')
password = settings.ext.find('GRADLE_BUILD_CACHE_NODE_PWD')
}
}
}
EDIT
Another solution that does not require the use of ext:
username = settings.hasProperty('GRADLE_BUILD_CACHE_NODE_USR') ? settings.GRADLE_BUILD_CACHE_NODE_USR : null
Related
TL;DR
I'm trying to configure two Gradle projects in a way that one project uses files built by the other one.
The first project is added to the second one by includeBuild and the file is defined in the second project as a dependency.
Project testA
settings.gradle:
rootProject.name = 'testA'
build.gradle:
group = 'org.test'
version = '0.0.0.1_test'
task someZip (type: Zip) {
from './settings.gradle'
archiveName = 'xxx.zip'
destinationDir = file("${buildDir}/test")
}
artifacts {
//TODO add something here?
}
Project testB
settings.gradle:
rootProject.name = 'testB'
if (System.getenv('LOCAL_COMPILATION') == 'true') {
includeBuild '../testA'
}
build.gradle:
if (System.getenv('LOCAL_COMPILATION') != 'true') {
repositories {
maven { url '192.168.1.100' }
}
}
configurations {
magic
}
dependencies {
magic 'org.test:xxx:0.0.0.+#zip'
}
task ultimateZip (type: Zip) {
from configurations.magic
archiveName = 'ultimate.zip'
destinationDir = file("${buildDir}/ultimate-test")
}
Description
You may noticed that the example has an option use a maven repository. I wanted to highlight that eventually there will be a possibility to do that.
Using Maven repository is not the point of this question, though, other than the solution should not interfere with that.
(In other words you can assume that System.getenv('LOCAL_COMPILATION') == 'true'.)
The question is how to define the artifact in a way that the other project is able to recognize it.
The preferred solution should be similar to what the Java plugin does because I'm using jar dependencies in my projects and they are working both through includeBuild and through a repository.
The following setup should work (tested with Gradle 5.5.1). It mostly corresponds to your original setup with the exception of the changes indicated by XXX.
Project testA
settings.gradle:
rootProject.name = 'testA'
build.gradle:
group = 'org.test'
version = '0.0.0.1_test'
task someZip (type: Zip) {
from './settings.gradle'
archiveName = 'xxx.zip'
destinationDir = file("${buildDir}/test")
}
// XXX (replaced your empty "artifacts" block)
configurations.create('default')
def myArtifact = artifacts.add('default', someZip) {
name = 'xxx'
}
// XXX (only added to show that publishing works)
apply plugin: 'maven-publish'
publishing {
repositories {
maven { url = 'file:///tmp/my-repo' }
}
publications {
myPub(MavenPublication) {
artifactId myArtifact.name
artifact myArtifact
}
}
}
Project testB
settings.gradle:
rootProject.name = 'testB'
if (System.getenv('LOCAL_COMPILATION') == 'true') {
// XXX (added a dependency substitution to let Gradle know that
// "org.test:xxx" corresponds to the testA project)
includeBuild('../testA') {
dependencySubstitution {
substitute module('org.test:xxx') with project(':')
}
}
}
build.gradle:
if (System.getenv('LOCAL_COMPILATION') != 'true') {
repositories {
// XXX (only changed to show that resolution still works after
// publishing)
maven { url = 'file:///tmp/my-repo' }
}
}
configurations {
magic
}
dependencies {
magic 'org.test:xxx:0.0.0.+#zip'
}
task ultimateZip (type: Zip) {
from configurations.magic
archiveName = 'ultimate.zip'
destinationDir = file("${buildDir}/ultimate-test")
}
As requested in the comments, here’s some more explanation on the created default configuration and the added artifact in project testA.
Composite builds in Gradle currently have the limitation that substituted project dependencies “will always point to the default configuration of the target project”. In your example this means that testA needs to publish in the default configuration. We thus first create the default configuration. Note that some plugins (like java) already create this configuration; you don’t need to create it yourself when using such plugins.
It doesn’t seem to be mentioned explicitly anywhere but as you seem to have found out yourself already, the PublishedArtifacts of a project (as declared with project.artifacts) are important for Gradle to figure out the dependency wiring in composite builds. Hence, we make sure to declare such a PublishedArtifact in testA using this API. The artifact (e.g., its extension) is configured based on the properties of the someZip task. The name seems to not be taken from the someZip task in your example because you manually set archiveName; hence we need to explicitly declare it. If you use archiveBaseName = 'xxx' in someZip instead, then you don’t need the closure when adding the artifact.
Here's the Error:
FAILURE: Build failed with an exception.
Where: Build file '/home/wieland/GitGradlePackaging/build.gradle' line: 22
What went wrong: A problem occurred evaluating root project 'GitGradlePackaging'.
Could not get unknown property 'org' for object of type org.gradle.api.internal.initialization.DefaultScriptHandler.
And Here's my build.gradle File:
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at https://docs.gradle.org/4.6/userguide/tutorial_java_projects.html
*/
//From example: http://mrhaki.blogspot.co.at/2015/04/gradle-goodness-use-git-commit-id-in.html
buildscript {
repositories {
jcenter()
}
dependencies {
//Add dependencies for build script, so we can access Git from our build script
classpath 'org.ajoberstar:grgit:1.1.0'
}
def git = org.ajoberstar.grgit.Grgit.open(file('.'))
//To save Githash
def githash = git.head().abbreviatedId
}
plugins {
// Apply the java plugin to add support for Java
id 'java'
// Apply the application plugin to add support for building an application
id 'application'
// Apply the groovy plugin to also add support for Groovy (needed for Spock)
id 'groovy'
id 'distribution'
}
// Set version
project.version = mainProjectVersion + " - " + githash
project.ext.set("wholeVersion", "$project.version - $githash")
project.ext.set("buildtimestamp", "2000-01-01 00:00")
def versionfilename = "versioninfo.txt"
def GROUP_DEBUG = 'Debug'
// Task to print project infos
task debugInitialSettings {
group = GROUP_DEBUG
doLast {
println 'Version: ' + project.wholeVersion
println 'Timestamp: ' + project.buildtimestamp
println 'Filename: ' + project.name
}
}
// To add the githash to zip
task renameZip {
doLast {
new File ("$buildDir/distributions/$project.name-${project.version}.zip")
.renameTo ("$buildDir/distributions/$project.name-${project.wholeVersion}.zip")
}
}
distZip.finalizedBy renameZip
// To add the githash to tar
task renameTar{
doLast {
new File ("$buildDir/distributions/$project.name-${project.version}.tar")
.renameTo ("$buildDir/distributions/$project.name-${project.wholeVersion}.tar")
}
}
distTar.finalizedBy renameTar
// Define the main class for the application
mainClassName = 'App'
dependencies {
// This dependency is found on compile classpath of this component and consumers.
compile 'com.google.guava:guava:23.0'
// Use the latest Groovy version for Spock testing
testCompile 'org.codehaus.groovy:groovy-all:2.4.13'
// Use the awesome Spock testing and specification framework even with Java
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
testCompile 'junit:junit:4.12'
}
// In this section you declare where to find the dependencies of your project
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
//To generate Testreports as HTML
test {
reports {
junitXml.enabled = false
html.enabled = true
}
}
distributions {
main {
contents {
from { 'build/docs' }
into ('reports') {
from 'build/reports'
}
}
}
}
//To make sure that test and javadoc ran before zip and tar
distTar.dependsOn test
distZip.dependsOn test
distTar.dependsOn javadoc
distZip.dependsOn javadoc
Please keep in mind I have not much knowledge about gradle as I'm just starting to learn it!
Thanks in advance :)
You have to move the githash definition outside the buildscript block
buildscript {
repositories {
jcenter()
}
dependencies {
//Add dependencies for build script, so we can access Git from our build script
classpath 'org.ajoberstar:grgit:1.1.0'
}
}
def git = org.ajoberstar.grgit.Grgit.open(file('.'))
//To save Githash
def githash = git.head().abbreviatedId
The reason is that when the buildscript block is evaluated line by line, its dependencies are not yet loaded. When the rest of the script is evaluated, the dependencies of the buildscript block have already been loaded. This is actually the reason for the buildscript block existence: to be run before the rest of the build and prepare the setup.
I am trying to load properties and use it in liquibase task. I am able to load the properties and able to print it out. But when I use it in liquibase task, gradle complains that properties are not found.
I am using:
classpath 'org.liquibase:liquibase-gradle-plugin:1.1.0'
Loading properties:
def springApplicationProperties = "src/main/resources/application-${System.env.SPRING_PROFILES_ACTIVE}.properties"
def springProps = new Properties()
InputStream is = new FileInputStream("${springApplicationProperties}")
springProps.load(is)
println "${springProps['spring.datasource.url']}"
Liquibase block:
liquibase{
activities {
main {
changeLogFile 'src/main/database/changelog.groovy'
url ${springProps['spring.datasource.url']}
username ${springProps['spring.datasource.user']}
password ${springProps['spring.datasource.password']}
}
}
runList = 'main'
}
And I am getting
No such property: $springProps for class:
org.liquibase.gradle.Activity
Looks like springProps is not visible in the liquibase activity. I tried to use ext and project scope, both not visible in liquibase block.
It will work this way:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.liquibase:liquibase-gradle-plugin:1.1.0'
}
}
apply plugin: 'java'
apply plugin: 'org.liquibase.gradle'
ext.springProps = new Properties()
InputStream is = new FileInputStream("src/main/resources/lol.properties")
springProps.load(is)
liquibase {
activities {
main {
url springProps['spring.datasource.url']
username springProps['spring.datasource.user']
password springProps['spring.datasource.password']
}
}
runList = 'main'
}
You unnecessarily added ${}. I've changed script a bit while trying out myself - but it has no side effects.
I wrote a gradle script where I am creating the zip and war file and then I need to upload/publish it to the artifactory but the issue is I specified the war file in my artifact task even after that it is publishing everything to the artifactory zip,tar and war instead of only war file.
apply plugin: 'war'
apply plugin: 'java'
apply plugin: 'distribution'
//-- set the group for publishing
group = 'com.xxx.discovery'
/**
* Initializing GAVC settings
*/
def buildProperties = new Properties()
file("version.properties").withInputStream {
stream -> buildProperties.load(stream)
}
//add the jenkins build version to the version
def env = System.getenv()
if (env["BUILD_NUMBER"]) buildProperties.coveryadBuildVersion += "_${env["BUILD_NUMBER"]}"
version = buildProperties.coveryadBuildVersion
println "${version}"
//name is set in the settings.gradle file
group = "com.aaa.covery"
version = buildProperties.discoveryadBuildVersion
println "Building ${project.group}:${project.name}:${project.version}"
repositories {
maven {
url "http://cxxxxt.tshaaaaa.tho.com:9000/artifactory/libselease"
}
maven {
url "http://cxxxxt.tshaaa.tho.com:9000/artifactory/cache"
}
}
dependencies {
compile ([
"com.uters.omni:HermesSessionAPI:1.2",
"com.uters.proxy:ProxyResources:1.1",
"com.uters.omni:SeshataDirectory:1.0.1" ,
"com.euters.omni:CybeleInfrastructure:1.1.2",
"com.euters:JSONBus:1.4.1",
"javaee:javaee-api:5"
])
}
distributions {
main {
contents {
from {
war.outputs
}
}
}
}
// for publishing to artifactory
artifacts {
archives war
}
According to gradle distribution plugin documentation:
All of the files in the “src/$distribution.name/dist” directory will automatically be included in the distribution.
And also,
The distribution plugin adds the distribution archives as candidate for default publishing artifacts.
In other words, by default all the files will be published so this explains the behavior you're experiencing.
What you can probably do in order to workaround this behavior is to define the contents copySpec more accurately by explicitly exclude the unwanted files, i.e.:
distributions {
main {
contents {
exclude('**/.zip')
exclude('**/.tar')
from {
war.outputs
}
}
}
}
Note that I didn't try the above by myself though so some fine tuning might be needed. However I believe that you can find the data you need in the CopySpec Interface documentation
How can I set a global variable that can be accessed from build.gradle and tasks?
To set a global variable
project.ext.set("variableName", value)
To access it from anywhere in the project:
project.variableName
For instance:
project.ext.set("newVersionName", versionString)
and then...
println project.newVersionName
For more information see: http://www.gradle.org/docs/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html
EDIT:
As commented by Dmitry, In new versions you can use the following shorthand:
project.ext.variableName = value
The answer from Guy is excellent. I just want to add the practical code.
Example:
Put something like this in the Project build.gradle:
project.ext {
minSdkVersion = 21
targetSdkVersion = 23
}
And put something like this in the Module build.gradle to access it:
defaultConfig {
minSdkVersion.apiLevel project.minSdkVersion
targetSdkVersion.apiLevel project.targetSdkVersion
}
You can also do this. Let's say you want to add appcompat with the version 25.3.1, you can add a variable version_name in your project level build.gradle.
buildscript{
ext.version_name = '25.3.1'
}
Now you can add this to your application level build gradle and avoid any conflicts.
compile "com.android.support:appcompat-v7:$version_name"
compile "com.android.support:recyclerview-v7:$version_name"
compile "com.android.support:design:$version_name"
You cant create a Gradle file in the project's root directory and put all variables there, like this:
lib-versions.gradle
ext {
kt_core = '1.6.0'
app_compat = '1.3.1'
material = '1.4.0'
constraintlayout = '2.1.1'
nav_version = '2.3.5'
junit = '4.13.2'
junit_ext = '1.1.3'
escpresso = '3.4.0'
}
Then in the project build.gradle file on the bottom you should apply the Gradle file like this:
buildscript {
...
}
task clean(type: Delete) {
delete rootProject.buildDir
}
apply from: 'lib-versions.gradle' //apply it like this
Then you are able to use the variables in any module-level build Gradle file (app/build.gradle) like this:
implementation "androidx.core:core-ktx:$rootProject.ext.kt_core"
implementation "androidx.appcompat:appcompat:$rootProject.ext.app_compat"
implementation "com.google.android.material:material:$rootProject.ext.material"
implementation "androidx.constraintlayout:constraintlayout:$rootProject.ext.constraintlayout"
...
Additional, for dynamic global variables you can define global functions in the master build.gradle file:
First, define your function, for example for git branch:
def getGitBranch = { ->
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim()
}
In allProjects section set the variable:
allprojects {
repositories {
google()
jcenter()
}
project.ext {
gitBranch="\"${getGitBranch()}\""
}
}
In your build.gradle files of your sub projects or android modules, get this variable like this:
android {
compileSdkVersion project.mCompileSdkVersion.toInteger()
defaultConfig {
minSdkVersion project.mMinSdkVersion.toInteger()
...
buildConfigField "String", "GitBranch", project.gitBranch
}
...
}
Finally, you can use it in your code like this:
public static String getGitBranch() {
return BuildConfig.GitBranch;
}
This is for Kotlin DSL (build.gradle.kts).
Root (top-level) build file:
val myVariable by extra("watermelon")
// Alternative notations:
// extra.set("myVariable", "watermelon")
// extra["myVariable"] = "watermelon"
Extra properties on a project object are visible from its subprojects. Note that extra. is equivalent to project.extra.; in other words the project object is implicit.
A sub-project build file:
val myVariable: String by rootProject.extra
// Alternative notations:
// val myVariable: String by rootProject
// val myVariable: String = rootProject.extra["myVariable"] as String
// val myVariable: String = rootProject.extra.get("myVariable") as String
Note that when using Kotlin delegation (by keyword) the name of the variables should be the same in both build files.
See Gradle Docs: Extra properties for more information.