13

We are using the Pipeline Shared Libraries plugin to factorize the code common to our different Jenkins pipelines.

From its documentation, it offers a resources top-level folder for non-Groovy files. As we rely on different bash functions, we would like to host them in a separate .sh file (thus they could also be used by other processes than Jenkins). The same documentation tells us about using libraryResource step to load those resource files. We can successfully call this method within our Groovy script, giving it our resource file name as argument (function.sh). But from here, we were not able to find a way to invoke the foofoo function defined in function.sh from the same Groovy script.

sh "foofoo"  #error: foofoo is not defined

We also tried to first source it like this:

sh "source function.sh && foofoo"

But it fails at the source step, stating that function.sh is not found.

What would be the correct procedure to invoke a bash function defined in function.sh

Ad N
  • 7,930
  • 6
  • 36
  • 80

4 Answers4

19

According to the documentation

External libraries may load adjunct files from a resources/ directory using the libraryResource step. The argument is a relative pathname, akin to Java resource loading:

def request = libraryResource 'com/mycorp/pipeline/somelib/request.json'

The file is loaded as a string, suitable for passing to certain APIs or saving to a workspace using writeFile.

It is advisable to use an unique package structure so you do not accidentally conflict with another library.

I assume the following will work

def functions = libraryResource 'com/mycorp/pipeline/somelib/functions.sh'
writeFile file: 'functions.sh', text: functions
sh "source function.sh && foofoo"
Yuri G.
  • 4,323
  • 1
  • 17
  • 32
  • 2
    what to do when you have a list of scripts that you want to load but without knowing neither the number of files nor the files names (people may add resources and inside of pipeline I must load all those scripts) – sirineBEJI Jul 04 '18 at 08:56
  • 7
    Rediculous you cannot use the file directly but need to create a copy of the file. – jaques-sam Feb 20 '20 at 10:57
  • Is there any requirement to use Java-style path? It seems to work just fine by specifying just a filename relative to 'resources' directory: `libraryResource 'functions.sh'` – zett42 Sep 18 '20 at 15:16
6

Since you are using Jenkins Pipelines V2, it would be better for you to create a shared library for this. The code below will work. Along with writing the file, you will need to provide execute privilege to the file as well:

def scriptContent = libraryResource "com/corp/pipeline/scripts/${scriptName}"
writeFile file: "${scriptName}", text: scriptContent
sh "chmod +x ${scriptName}"

Hope this helps!!

anuj0901
  • 573
  • 6
  • 8
5

All the previous answers are poor solutions as the script is parsed as a text file when it is transferred which corrupts it.

Quotes etc are messed up and it attempts to substitute variables.

It needs to be transferred verbatim.

The only solutions are to store the script on a file server, download it and run it e.g.:

sh """
    wget http://some server/path../yourscript.sh
    chmod a+x yourscript.sh
   """

...or checkout the script from the repo directly and use it locally like this:

withCredentials([usernamePassword(
    credentialsId: <git access credentials>,
    usernameVariable: 'username',
    passwordVariable: 'password'
)])
{
    sh  """
        git clone http://$username:$password@<your git server>/<shared library repo>.git gittemp
        cd gittemp
        git checkout <the branch in the shared library>
        cd ..
        mv -vf gittemp/<path to file>/yourscript.sh ./
    """
}

...then later run your script:

sh "./yourscript.sh ...."
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/low-quality-posts/22112372) – common sense Feb 04 '19 at 12:54
  • Hope this clarifies – TurboElectricLtd Feb 04 '19 at 15:35
  • @TurboElectricLtd what do you mean "when it is transferred"? Do you mean when it is read from the library? Or something master/slave related? – jam01 Feb 27 '21 at 17:51
4

Use bash shebang (#!/bin/bash) at the beginning of your sh step to tell Jenkins to use bash, and then load your lib like you would in bash, e.g.:

sh '''#!/bin/bash
      . path/to/shared_lib.bash
       myfunc $myarg
    '''

Mind the fact, that path/to/shared_lib.bash has be checked in your repo in order for this to work.

Gregory
  • 63
  • 3