I have the following directory structure
(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global 'foo' variable
And I have the following lines of code in the following files
Bar.groovy
package org.foo
class Bar implements Serializable {
def config
def script
Bar(script, config){
this.script = script
this.config = config
}
def accessGlobalVars(){
this.script.echo "${foo.GlobalVar}" // throws an err
}
}
foo.groovy
import groovy.transform.Field
#Field GlobalVar="Hello World!"
I'm able to access the variable in the Jenkinsfile inside the script block
echo "${foo.GlobalVar}"
Is it possible to access the same variable inside the class since the vars folder is at src folder level?
The "${foo.GlobalVar}" in your example code is trying to resolve the foo against the Bar type. Since there is no foo reference it cannot be resolved and you will probably get something like a MissingPropertyException.
Jenkins Pipeline Groovy does some different compilation and binding using the Groovy compilation and runtime APIs. The global variables can also be resolved through the script object through its dynamic GroovyObject APIs (demonstrated in the source code here). The easiest way is to let the dynamic Groovy object resolution implemented by Jenkins resolve your variable.
Change your line from:
this.script.echo "${foo.GlobalVar}"
To instead lookup the foo from the script object (which I am presuming is the this or script in your Jenkins pipeline by new Foo(this, config)):
this.script.echo "${this.script.foo.GlobalVar}"
Related
I have a file which loads a library dynamically like this
def lib=library(identifier: 'pipeline-core#master', retriever: modernSCM(
[$class: 'GitSCMSource',
remote: 'https://scm.intra/scm/jenins/pipeline-core.git',
credentialsId: 'bitbucket.service.user'
])).ch.swisscard.pipeline.util.Utils
defaultCdPipeline {}
Whereas defaultCdPipeline is a jenkins pipeline definition which uses the Utils class like
import ch.mycompany.jenkins.pipeline.util.*
...
Utils.isRunning()
...
The file structure is this:
+- src
| +- mycompany
| +- jenkins
| +- pipeline
| +- util
| +- Utils.groovy
| +- Commons.groovy
+- vars
+- defaultCdPipeline.groovy
That works so far. When I look at the dynamic import my understanding I would use lib so lib.isRunning() rather than Utils.isRunning() but this generates the following error
No such property: lib for class: groovy.lang.Binding
Why? Going forward I would like to use both Utils.groovy and Commons.groovy. This I would "preselect the package" as this is shown in the example thus only using .ch.swisscard.pipeline.util
def lib=library(identifier: 'pipeline-core#master', retriever: modernSCM(
[$class: 'GitSCMSource',
remote: 'https://scm.intra/scm/jenins/pipeline-core.git',
credentialsId: 'bitbucket.service.user'
])).ch.swisscard.pipeline.util
defaultCdPipeline {}
This however also does not work as the call lib.Uils.isRunning()
...
stages {
stage('Deployment') {
steps {
script {
lib.Uils.isRunning()`
...
throws the same exception as mentioned above
No such property: lib for class: groovy.lang.Binding
Content if Utils
package ch.mycompany.jenkins.pipeline.util
class Utils implements Serializable {
#NonCPS
def static String isRunning() {
return "isRunning()"
}
}
Can somebody shed some light into this issue and tell me how I can properly load a package/multiple classes?
you should have only declare the library load like this:
def lib = library(
identifier: 'pipeline-core#master', retriever: modernSCM
(
[
$class: 'GitSCMSource',
remote: 'https://scm.intra/scm/jenins/pipeline-core.git',
credentialsId: 'bitbucket.service.user'
]
)
)
assuming this is the groovy class:
package ch.mycompany.jenkins.pipeline.util
class Utils implements Serializable
{
#NonCPS
def static String isRunning()
{
return "isRunning()";
}
def String isItReallyRunning()
{
return "isItReallyRunning()";
}
}
then you call a static method like this:
lib.ch.mycompany.jenkins.pipeline.util.Utils.isRunning();
and an instance method like this:
// call the constructor (you can also call a constructor with parameters)
def utils = lib.ch.mycompany.jenkins.pipeline.util.Utils.new();
// call your instance method
utils.isItReallyRunning();
I want to invoke method of src directory from vars directory, which it works in IDE. But it seems not work in Jenkins.
1.project structure
├── src
│ └── foo
│ └── DemoClass.groovy
└── vars
└── varDemo.groovy
2.Content of DemoClass.groovy
#!groovy
package foo
class DemoClass {
def testDemoMethod() {
println("src DemoClass testDemoMethod")
}
}
3.Content of varDemo.groovy
#!groovy
import foo.DemoClass
def testVarsDemo() {
println("vars varDemo.groovy testVarsDemo")
}
def testVarsInvokeDemoMethod() {
println("vars varDemo.groovy testVarsInvokeDemoMethod")
def demoClass = new DemoClass()
demoClass.testDemoMethod()
println("end vars varDemo.groovy testVarsInvokeDemoMethod")
}
4.Jenkins pipeline
#Library('tools') _
varDemo.testVarsDemo()
varDemo.testVarsInvokeDemoMethod()
5.execute result in pipeline
> git checkout -f b6176268be99abe300d514e1703ff8a08e3ef8da
Commit message: "test"
> git rev-list --no-walk c1a50961228ca071d43134854548841a056e16c9 # timeout=10
[Pipeline] echo
vars varDemo.groovy testVarsDemo
[Pipeline] echo
vars varDemo.groovy testVarsInvokeDemoMethod
[Pipeline] echo
end vars varDemo.groovy testVarsInvokeDemoMethod
[Pipeline] End of Pipeline
It seem like demoClass.testDemoMethod() not work. Why can't invoke demoClass.testDemoMethod()? If I want to invoke the method in src directory, what should I do? Thank you!
Without reimplementing your code sections locally, Here are some differences I notice between yours and mine that is working.
JENKINSFILE
I don't have a space before the underscore on my #Library line
Immediately after my #Library line I am importing my shared library class that implements the methods I want to call. In your case this would be import foo.DemoClass
My call to my method is of the form (new DemoClass(config, this)).testVarsInvokeDemoMethod()
SHARED LIBRARY CLASSES
I don't have #!groovy in any of my groovy classes.
My class is public and implements Serializable
Hopefully one of these difference is the source of why its not getting called.
We need to follow the below structure
src/packagename/GroovyFile.groovy
vars/callFromJenkinsPipelne.groovy
The jenkins pipeline should be like this .
library('libracyname#Branchname')
callFromJenkinsPipelne()
Inside the vars file ( callFromJenkinsPipelne) , we can call the groovy file which is in src folder
//code in vars folder groovy file will be like this
for callFromJenkinsPipelne groovy file
def call(){
GroovyFile groovyFile = new com.jenkins.mypackagename.GroovyFile()
groovyFile.methodName(parameters)
}
I want to use environment variable "WORKSPACE" in the active choice plugin groovy script.
I tried to retrieve it like this but it didnt work. WORKSPACE is not recognised.
${WORKSPACE}
Can anyone help me here?
Snippet:
def sout = new StringBuffer(), serr = new StringBuffer()
def proc ='/test/script.sh'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
Here instead of /test/script.sh i need to access the script as following:
def process='$workspace path/test/script.sh
It's not possible to get that "environment" variable. A better name would be "property". Those are dynamically generated by Jenkins when the build starts, not when the parameters are set.
You can get some environment variables with EnvVars when you're setting the parameters, but they are very few. This can be tested on the Jenkins Script Console with the following code:
import hudson.EnvVars
for (envVarName in EnvVars.masterEnvVars.keySet()) {
def envVarValue = EnvVars.masterEnvVars[envVarName]
println("${envVarName}=${envVarValue}")
}
Result:
_=/etc/alternatives/java
HOME=/home/jenkins
LANG=en_US.UTF-8
LOGNAME=jenkins
NLSPATH=/usr/dt/lib/nls/msg/%L/%N.cat
PATH=/sbin:/usr/sbin:/bin:/usr/bin
PWD=/
SHELL=/bin/bash
SHLVL=2
TERM=xterm-256color
USER=jenkins
XFILESEARCHPATH=/usr/dt/app-defaults/%L/Dt
WORKSPACE property has more to it. The directory may not exist when you launch the build, specially if it's the first time you are doing it. My recommendation, if it makes sense to you, is to place the script in userContent directory and work out the rest based on that.
I am trying to automate testing Jenkins groovy dsl scripts, like here:
https://github.com/sheehan/job-dsl-gradle-example
The idea I think is very straight forward, what I'm having issues with is setting environment variables for the dummy Jenkins. I followed the instructions here:
https://wiki.jenkins-ci.org/display/JENKINS/Unit+Test
Specifically "How to set env variables" section and added the following to my test executor:
import hudson.slaves.EnvironmentVariablesNodeProperty
import hudson.EnvVars
/**
* Tests that all dsl scripts in the jobs directory will compile.
*/
class JobScriptsSpec extends Specification {
#Shared
#ClassRule
JenkinsRule jenkinsRule = new JenkinsRule()
EnvironmentVariablesNodeProperty prop = new EnvironmentVariablesNodeProperty();
EnvVars envVars = prop.getEnvVars();
#Unroll
void 'test script #file.name'(File file) {
given:
envVars.put("ENVS", "dev19");
jenkinsRule.jenkins.getGlobalNodeProperties().add(prop);
JobManagement jm = new JenkinsJobManagement(System.out, [:], new File('.'))
when:
new DslScriptLoader(jm).runScript(file.text)
then:
noExceptionThrown()
where:
file << jobFiles
}
However when I run the actual tests for one of the scripts, I still see the following:
Failed tests
test script Build.groovy
Expected no exception to be thrown, but got 'javaposse.jobdsl.dsl.DslScriptException'
at spock.lang.Specification.noExceptionThrown(Specification.java:118)
at com.dslexample.JobScriptsSpec.test script #file.name(JobScriptsSpec.groovy:40)
Caused by: javaposse.jobdsl.dsl.DslScriptException: (script, line 3) No such property: ENVS for class: script
The script Build.groovy uses the variable "${ENVS}" (as if it were provided by parameter in seed job of Jenkins), which works as expected when actually running in Jenkins... So any way to set these "parameters" or env variables in the test jenkins context?
Example of how I use the ENVS variable in the Build.groovy:
def envs = '-'
"${ENVS}".eachLine{
def env = it
envs+=env+'-'
}
envs.substring(0,envs.length()-1)
job('Build'+envs) {
...
}
The second argument of the JenkinsJobManagement constructor is a map of environment variables which will be available in the DSL scripts.
Map<String, String> envVars = [
FOO: 'BAR'
]
JobManagement jm = new JenkinsJobManagement(System.out, envVars, new File('.'))
I need to monitor what are the changes going with a job on jenkins(update the changes to a file). Need to list the env variables of a job. JOB_NAME,BUILD_NUMBER,BUILD_STATUS,GIT_URL for that build(all the builds of a job). I didn't find out a good example with the groovy. What is the best way to fetch all the info?
build.getEnvironment(listener) should get you what you need
Depending on what you would like to achieve there are at least several approaches to retrieve and save environment variables for:
current build
all past builds
Get environments variables for current build (from slave)
Execute Groovy script
// Get current environment variables and save as
// a file in $WORKSPACE.
new File(".",'env.txt').withWriter('utf-8') { writer ->
System.getenv().each { key, value ->
writer.writeLine("${key}:${value}")
}
}
Using Groovy Plug-in.
Get environment variables for current build (from master)
Execute system Groovy script
// Get current environment variables and save as
// a file in $WORKSPACE.
import hudson.FilePath
def path = "env-sys.txt"
def file = null
if (build.workspace.isRemote()) {
file = new FilePath(build.workspace.channel, build.workspace.toString() + "/" + path)
} else {
file = new FilePath(build.workspace.toString() + "/" + path)
}
def output = ""
build.getEnvironment(listener).each { key, value ->
output += "${key}:${value}\n"
}
file.write() << output
Using Groovy Plug-in.
Environment variables returned by Groovy scripts are kept in map. If you don't need all of them, you can access individual values using standard operators/methods.
Get environment variables for all past builds (from master)
This approach expecst that you have installed EnvInject Plug-in and have access to $JENKINS_HOME folder:
$ find . ${JENKINS_HOME}/jobs/[path-to-your-job] -name injectedEnvVars.txt
...
ps. I suspect that one could analyze EnvInject Plug-in API and find a way to extract this information directly from Java/Groovy code.
Using EnvInject Plug-in.
To look for only specific variables you can utilize find, grep and xargs tools .
You can use below script to get the Environment Variables
def thread = Thread.currentThread()
def build = thread.executable
// Get build parameters
def buildVariablesMap = build.buildVariables
// Get all environment variables for the build
def buildEnvVarsMap = build.envVars
String jobName = buildEnvVarsMap?.JOB_NAME // This is for JOB Name env variable.
Hope it helps!