Within my Jenkinsfile I would like to read some metadata from a Gradle buildscript, e.g. group, baseNameand version. With Maven, I can do something like this:
def pom = readMavenPom file: 'pom.xml'
env.POM_VERSION = pom.version
env.POM_ARTIFACT_ID = pom.artifactId
env.POM_GROUP_ID = pom.groupId
Question is: how can I do the same thing with Gradle, given I have a build.gradle that looks like this:
ext {
group = 'my.group.com'
baseName = 'myapplication'
version = '0.5.2-SNAPSHOT'
}
Maybe there is a "trick" to read Gradle build information in a Jenkinsfile since both is Groovy, but I am a Groovy newb :)
Related
I have tried using readMavenPom like the following to get the pom version and so for this has been working very well as the pom.xml file has been present in the root of the project directory.
pom = readMavenPom file: 'pom.xml'
For some of our projects, this pom.xml won't be available in the root of the project repository instead it will be available inside the parent module so in that case, we modify the groovy script like the following.
pom = readMavenPom file: 'mtree-master/pom.xml'
There are only two possibilities, either the pom.xml file will present in the root or it will be inside the parent module. So is there a way to rule out this customization that we make every time?
I'd check if the file exists in a specific location with fileExisits:
def pomPath = 'pom.xml'
if (!(fileExists pomPath)) {
pomPath = 'mtree-master/pom.xml'
}
pom = readMavenPom file: pomPath
Bonus: Check multiple paths
def pomPaths = ['pom.xml', 'mtree-master/pom.xml']
def pomPath = ''
for (def path : pomPaths) {
if (fileExists path) {
pomPath = path
break
}
}
// check that pomPath is not empty and carry on
In my project I have to generate the grammar sources for more than one language (Java, Javascript and Python) using gradle.
I'm using the antlr plugin, so I have the following rows in my build.gradle file:
apply plugin: 'antlr'
generateGrammarSource {
def languageFlag = project.hasProperty('Language') ?project.property('Language') : 'Python2'
arguments = ['-Dlanguage=' + languageFlag]
def pythonOutputDirectory = "python/engine_lib/kpi_attributes"
switch (languageFlag) {
case "Java":
outputDirectory = file("../../../../XSpotterGUI/sviluppo/src/com/xech/xspotter4/grammars/kpiattributes")
arguments += ['-package', 'com.xech.xspotter4.grammars.kpiattributes']
break
case "JavaScript":
outputDirectory = file("../../../../XSpotterGUI/sviluppo/WebContent/xspotter4/js/xech/grammars/kpiattributes")
break
case "Python2":
outputDirectory = file(pythonOutputDirectory)
break
}
description = 'Generates Java sources from Antlr4 grammars.'
maxHeapSize = "64m"
sourceSets.main.antlr.srcDirs = ['.']
includes = ['KpiAttributes.g4']
doLast {
if (languageFlag.equals("Python2")) {
File file = new File("$pythonOutputDirectory/__init__.py")
file.write ""
}
}
}
I omitted the rows regarding repositories, dependencies and so on.
In this way I'm able to call gradle three times:
./gradlew generateGrammarSource -PLanguage=Java
./gradlew generateGrammarSource -PLanguage=Python2
./gradlew generateGrammarSource -PLanguage=JavaScript
But I have not been able to create a task 'generateAllGrammarSources' in order to call gradlew only ONE time and generate all sources
Let's say I have a custom property in my pom.xml set like this:
<properties>
<app>com.myProject.app</app>
</properties>
How can I access it in my jenkinsfile?
This:
def pom = readMavenPom file: 'pom.xml'
def appName = pom.app
returns
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified field org.apache.maven.model.Model app
Thanks in advance!
I know two approaches:
Use properties-maven-plugin to write the properties to a file. Use readProperties in the Jenkinsfile to read the properties.
Works only if properties aren't needed until after Maven ran.
Also, with the right circumstances, the properties file may be the stale one from a previous run, which is insiduous because the property values will be right anyway 99.9% of the time.
Use pom = readMavenPom 'path/to/pom.xml'. Afterwards, access the property like this: pom.properties['com.myProject.app'].
I like approach 2 much better: No extra plugin configuration in the POM, no file written, less sequencing constraints, less fragilities.
In pipeline style, inside Jenkinsfile you can access the value as follows
pipeline {
environment {
POM_APP = readMavenPom().getProperties().getProperty('app')
}
stages{
stage('app stage'){
steps{
script{
sh """
echo ${POM_APP}
"""
}
}
}
}
Read a maven project file
try this:
IMAGE = readMavenPom().getArtifactId()
VERSION = readMavenPom().getVersion()
jenkins pipeline add this stage.
more see
stage('info')
{
steps
{
script
{
def version = sh script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true
def artifactId = sh script: 'mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout', returnStdout: true
}
}
}
I went through the following link and successfully implemented a task which calls build.gradle file from another project. i.e. solution provided by #karl worked for me.
But I need something up on that.
Can somebody help me to know how I can pass command line arguments while calling another build.gradle? Command line argument should be the variable which I have generated from my current build.gradle file.
In my case, I am defining a buildNumber and doing something like this:
def buildNumber = '10.0.0.1'
def projectToBuild = 'projectName'
def projectPath = "Path_till_my_Project_Dir"
task executeSubProj << {
def tempTask = tasks.create(name: "execute_$projectToBuild", type: GradleBuild)
// ****** I need to pass buildNumber as command line argument in "$projectPath/$projectToBuild/build.gradle" ******
tempTask.tasks = ['build']
tempTask.buildFile = "$projectPath/$projectToBuild/build.gradle"
tempTask.execute()
}
You should never call execute directly on any gradle object. The fact it's feasible doesn't mean it should be done and it's highly discouraged since you intrude internal gradle's execution graph structure.
What you need is a task of type GradleBuild which has StartParameter field that can be used to carry build options.
So:
task buildP2(type: GradleBuild) {
buildFile = '../p2/build.gradle'
startParameter.projectProperties = [lol: 'lol']
}
Full demo can be found here, navigate to p1 directory and run gradle buildP2.
You should modify your script in the following way:
def buildNumber = '10.0.0.1'
def projectToBuild = 'projectName'
def projectPath = "Path_till_my_Project_Dir"
task executeSubProj(type: GradleBuild) {
buildFile = "$projectPath/$projectToBuild/build.gradle"
tasks = ['build']
startParameter.projectProperties = [buildNumber: '10.0.0.1']
}
In the project that is executed use project.findProperty('buildNumber') to get the required value.
To not clutter my project's top-level directory I would like the gradle wrapper JAR to land in a subdirectory, e.g. infra. I'm going for something like this:
root
L .infra
L gradle
L wrapper
L gradle-wrapper.jar
L gradle-wrapper.properties
I hoped that archiveBase or distributionBase would get me there but even if brute forcing these settings, I still end up with gradle in the top level.
configure(rootProject) {
task wrapper(type: Wrapper) {
description = 'Generates gradlew and gradlew.bat scripts'
gradleVersion = '3.2'
archiveBase = Wrapper.PathBase.PROJECT
archivePath = ".infra/"
distributionBase = Wrapper.PathBase.PROJECT
distributionPath = ".infra/"
}
}
What am I doing wrong?
These paths will be set in the gradle/wrapper/gradle-wrapper.properties.
distributionBase=PROJECT
distributionPath=infra/ <----
zipStoreBase=PROJECT
zipStorePath=infra/ <----
You can set the path to wrapper script and jar by using following properties.
jarFile = "${project.projectDir}/.infra/gradle-wrapper.jar" // archive
scriptFile = "${project.projectDir}/.infra/gradlew" // wrapper script