How to set and reference a variable in a Jenkinsfile
Asked Answered
F

5

43

I have a declarative pipeline script for my multibranch project in which I would like to read a text file and store the result as a string variable to be accessed by a later step in the pipeline. Using the snippet generator I tried to do something like this:

filename = readFile 'output.txt'

For which filename would be my string.

I get an error in the Jenkins console output:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 30: Expected a step @ line 30, column 5.
            filename = readFile 'output.txt'

Do I need to use a withEnv step to set the output of readFile to a Jenkins environment variable? If so, how?

Thanks

Fisken answered 1/3, 2017 at 19:16 Comment(1)
can you edit your question according to the mcve guide?Nagoya
P
70

The error is due to that you're only allowed to use pipeline steps inside the steps directive. One workaround that I know is to use the script step and wrap arbitrary pipeline script inside of it and save the result in the environment variable so that it can be used later.

So in your case:

pipeline {
    agent any
    stages {
        stage("foo") {
            steps {
                script {
                    env.FILENAME = readFile 'output.txt'
                }
                echo "${env.FILENAME}"
            }
        }
    }
}
Popsicle answered 1/3, 2017 at 19:36 Comment(5)
Strange, when run this (Jenkins 2.32.2) I get the expected result (added writeFile file: 'output.txt', text: 'asdsad' just before readFile, I get [Pipeline] echo asdsad as expected). Are you sure there is any contents in the file?Popsicle
Ya it's blank and that was due to some other issue in my logic, but I think your answer is what I was looking for. ThanksFisken
one hint: you may want to trim like this readFile('output.txt').trim()Confessedly
Note that you cannot assign a credential(...) to a variable like this. It renders out to a string "@credentials(<anonymous>=BLAHBLAH>" and will then silently not work.Violetvioleta
Yes, the env variable isn't backed by a normal map, instead it operates 100% with strings, i.e. all values which are assigned to keys in the env variable are converted to strings (using toString() i guess).Popsicle
W
28

According to the documentation, you can also set global environment variables if you later want to use the value of the variable in other parts of your script. In your case, it would be setting it in the root pipeline:

pipeline {
  ...
  environment {
    FILENAME = readFile ...
  }
  ...
}
Workhouse answered 16/8, 2017 at 0:14 Comment(1)
Just to clarify, as stated in other answers, value may be referenced as "${env.FILENAME}" later.Acrobatics
H
12

We got around this by adding functions to the environment step, i.e.:

environment {
    ENVIRONMENT_NAME = defineEnvironment() 
}
...
def defineEnvironment() {
    def branchName = "${env.BRANCH_NAME}"
    if (branchName == "master") {
        return 'staging'
    }
    else {
        return 'test'
    }
}
Heterocercal answered 25/9, 2018 at 8:8 Comment(2)
is "${env.BRANCH_NAME}" the same as env.BRANCH_NAME if BRANCH_NAME is a string already?Unclose
You might be right there, I'm not sure if the interpolation is strictly necessary. Give it a try.Heterocercal
I
2

A complete example for scripted pipepline:

       stage('Build'){
            withEnv(["GOPATH=/ws","PATH=/ws/bin:${env.PATH}"]) {
                sh 'bash build.sh'
            }
        }
Industrials answered 23/2, 2018 at 22:46 Comment(2)
This question doesn't say anything about running a build script, or adding to PATH.Huoh
True, but this is the only answer with scripted syntax, and this is a fine piece of example code.Lilylilyan
Z
2

I can' t comment yet but, just a hint: use try/catch clauses to avoid breaking the pipeline (if you are sure the file exists, disregard)

    pipeline {
        agent any
            stages {
                stage("foo") {
                    steps {
                        script {
                            try {                    
                                env.FILENAME = readFile 'output.txt'
                                echo "${env.FILENAME}"
                            }
                            catch(Exception e) {
                                //do something, e.g. echo 'File not found'
                            }
                        }
                   }
    }

Another hint (this was commented by @hao, and think is worth to share): you may want to trim like this readFile('output.txt').trim()

Zucchetto answered 28/11, 2018 at 17:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.