90

I have a jenkinsfile dropped into the root of my project and would like to pull in a groovy file for my pipeline and execute it. The only way that I've been able to get this to work is to create a separate project and use the fileLoader.fromGit command. I would like to do

def pipeline = load 'groovy-file-name.groovy' pipeline.pipeline() 

6 Answers 6

141

If your Jenkinsfile and groovy file in one repository and Jenkinsfile is loaded from SCM you have to do:

Example.Groovy

def exampleMethod() { //do something } def otherExampleMethod() { //do something else } return this 

JenkinsFile

node { def rootDir = pwd() def exampleModule = load "${rootDir}@script/Example.Groovy " exampleModule.exampleMethod() exampleModule.otherExampleMethod() } 
Sign up to request clarification or add additional context in comments.

15 Comments

Readers, note that in the Groovy, "return this" is crucial.
@AntonShishkin , What is the ${rootDir} variable, and where/how is it set? Is it intrinsic to Jenkins or custom? I am getting groovy.lang.MissingPropertyException: No such property: rootDir for class: groovy.lang.Binding.
Ok, so this is outdated. Instead of ${rootDir}, use ${workspace}, which is set by Jenkins. Also, be sure to uncheck "Lightweight checkout" in the pipeline job's configuration, or else your .groovy script(s) will not be downloaded from SCM.
So, I found a caveat -- when running 2 concurrent instances of the same job, Jenkins will append @2 to the workspace name... however, it does not to so for the @script directory, meaning that ${workspace}@script/Example.Groovy will not work when running concurrent builds.
I have a path to the pulled files including groovy (let's say it's in the root of the project) like workspace/Job Name@script/ecb7a9317b1ad6......../Example.groovy How can I determine or get rid of that additional automatically added folder with long ecb7a9317b1ad6........ name?
|
39

If you have pipeline which loads more than one groovy file and those groovy files also share things among themselves:

JenkinsFile.groovy

def modules = [:] pipeline { agent any stages { stage('test') { steps { script{ modules.first = load "first.groovy" modules.second = load "second.groovy" modules.second.init(modules.first) modules.first.test1() modules.second.test2() } } } } } 

first.groovy

def test1(){ //add code for this method } def test2(){ //add code for this method } return this 

second.groovy

import groovy.transform.Field @Field private First = null def init(first) { First = first } def test1(){ //add code for this method } def test2(){ First.test2() } return this 

1 Comment

can may be return someting not same return this - for example return "This"?
21

You have to do checkout scm (or some other way of checkouting code from SCM) before doing load.

2 Comments

This assumes the file to load is in SCM.
You are correct that if the file is in SCM, then you need to get it from there before trying to load it. But, if the library file is in the same repo as the main jenkinsfile, then you don't have to call checkout if the pipeline is configured to pull the repo automatically; in the job config.
12

Thanks @anton and @Krzysztof Krasori, It worked fine if I combined checkout scm and exact source file

Example.Groovy

def exampleMethod() { println("exampleMethod") } def otherExampleMethod() { println("otherExampleMethod") } return this 

JenkinsFile

node { // Git checkout before load source the file checkout scm // To know files are checked out or not sh ''' ls -lhrt ''' def rootDir = pwd() println("Current Directory: " + rootDir) // point to exact source file def example = load "${rootDir}/Example.Groovy" example.exampleMethod() example.otherExampleMethod() } 

2 Comments

This was what I needed to allow a Jenkins pipeline from SCM to work, now I have all my constants and functions centralized into a common Jenkinsfile.common.Groovy that is shared between my release pipeline and my integration test pipeline.
11

In case the methods called on your loaded groovy script come with their own node blocks, you should not call those methods from within the node block loading the script. Otherwise you'd be blocking the outer node for no reason.

So, building on @Shishkin's answer, that could look like

Example.Groovy

def exampleMethod() { node { //do something } } def otherExampleMethod() { node { //do something else } } return this 

Jenkinsfile

def exampleModule node { checkout scm // could not get it running w/o checkout scm exampleModule = load "script/Example.Groovy" } exampleModule.exampleMethod() exampleModule.otherExampleMethod() 

Jenkinsfile using readTrusted

When running a recent Jenkins, you will be able to use readTrusted to read a file from the scm containing the Jenkinsfile without running a checkout - or a node block:

def exampleModule = evaluate readTrusted("script/Example.Groovy") exampleModule.exampleMethod() exampleModule.otherExampleMethod() 

Unfortunately - as pointed out correctly by @sparrowt - the scripts loaded using readTrusted cannot be modified when replaying a Pipeline.

5 Comments

This works perfectly, even with more complex pipeline (ie. with try/catch, stages, parallel node). Thanks for the tip!
My question is how do you create these additional groovy files using jenkins and saving them somewhere where it's accessible by the build? that's what im confused about
how does 'scm checkout' know what repo to pull from or what credentials to use?
Please check the Jenkins documentation for checkout scm: It just checks out whatever repository the Jenkinsfile was read from. Therefore, it will obviuosly not work when writing the Jenkinsfile in the Jenkins web UI. But anyways that you should not do for productive jobs.
Using evaluate readTrusted is handy but sadly if you do this, then when using Replay if you edit the groovy file (which it calls "Script1") your changes won't take effect.
4

Very useful thread, had the same problem, solved following you.

My problem was: Jenkinsfile -> call a first.groovy -> call second.groovy

Here my solution:

Jenkinsfile

node { checkout scm //other commands if you have def runner = load pwd() + '/first.groovy' runner.whateverMethod(arg1,arg2) } 

first.groovy

def first.groovy(arg1,arg2){ //whatever others commands def caller = load pwd() + '/second.groovy' caller.otherMethod(arg1,arg2) } 

NB: args are optional, add them if you have or leave blank.

Hope this could helps further.

1 Comment

A quick reminder, load() only works within node(). Second load() works because whateverMethod() is called within node().

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.