Reuse block string without processing it on the fly



  • I have a block of code that work fine at the moment. But reuse that code is a little ugly.

    pipeline {
        agent any
        stages {
            stage('Stage 1') {
                steps {
                    script {
                        withCredentials([
                            gitUsernamePassword(credentialsId: 'jenkins-credentials', gitToolName: 'Default', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD')
                        ]) {
                            sh '''#!/bin/bash
                            export GIT_USERNAME=${GIT_USERNAME};
                            export GIT_PASSWORD=${GIT_PASSWORD};
                            export PROYECT_DIRECTORY=${PROYECT_DIRECTORY};
                            export CHECKOUT_POINT=${CHECKOUT_POINT};
                            export GIT_HTTPS_REPO_DEPLOY=${GIT_HTTPS_REPO_DEPLOY};
                            export MARIADB_HOSTNAME=${MARIADB_HOSTNAME};
    
                        ./scripts/awesome_script.sh
                        '''
                    }
                }
            }
        }
    }
    

    }

    The problem is when I apply if statements to use diferents scripts bash inside sh() block. The script ./scripts/awesome _script.sh need that variables exported. Therefore the code looks like this.

    script {
                        withCredentials([
                            gitUsernamePassword(credentialsId: 'jenkins-credentials', gitToolName: 'Default', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD')
                        ]) {
                            sh '''#!/bin/bash
                            export GIT_USERNAME=${GIT_USERNAME};
                            export GIT_PASSWORD=${GIT_PASSWORD};
                            export PROYECT_DIRECTORY=${PROYECT_DIRECTORY};
                            export CHECKOUT_POINT=${CHECKOUT_POINT};
                            export GIT_HTTPS_REPO_DEPLOY=${GIT_HTTPS_REPO_DEPLOY};
                            export MARIADB_HOSTNAME=${MARIADB_HOSTNAME};
    
                        ./scripts/awesome_script.sh
                        '''
                        if(env.APP_ENV == 'testing'){
                            sh '''#!/bin/bash
                            export GIT_USERNAME=${GIT_USERNAME};
                            export GIT_PASSWORD=${GIT_PASSWORD};
                            export PROYECT_DIRECTORY=${PROYECT_DIRECTORY};
                            export CHECKOUT_POINT=${CHECKOUT_POINT};
                            export GIT_HTTPS_REPO_DEPLOY=${GIT_HTTPS_REPO_DEPLOY};
                            export MARIADB_HOSTNAME=${MARIADB_HOSTNAME};
    
                            ./scripts/awesome_script_2.sh
                            '''
                        }
                    }
                }
    

    Very ugly, right ? 😕 😞

    What I am looking is something similar like to this, but with correct syntax:

    script {
                        env.STRING_BLOCK_WITHOUT_PROCESSING = '''
                            export GIT_USERNAME=${GIT_USERNAME};
                            export GIT_PASSWORD=${GIT_PASSWORD};
                            export PROYECT_DIRECTORY=${PROYECT_DIRECTORY};
                            export CHECKOUT_POINT=${CHECKOUT_POINT};
                            export GIT_HTTPS_REPO_DEPLOY=${GIT_HTTPS_REPO_DEPLOY};
                            export MARIADB_HOSTNAME=${MARIADB_HOSTNAME};
                        ''';
    
                    withCredentials([
                        gitUsernamePassword(credentialsId: 'jenkins-credentials', gitToolName: 'Default', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD')
                    ]) {
                        sh '''#!/bin/bash
                        ${STRING_BLOCK_WITHOUT_PROCESSING}
    
                        ./scripts/awesome_script.sh
                        '''
                        if(env.APP_ENV == 'testing'){
                            sh '''#!/bin/bash
                            ${STRING_BLOCK_WITHOUT_PROCESSING}
                            
                            ./scripts/awesome_script_2.sh
                            '''
                        }
                    }
                }
    

    Thanks for all help you can give me.



  • When you have a variable inside of a string that is called a gstring or groovy string.

    In Groovy, which is the language used inside of the script block, you have to use a certain style of quotes if you want to render the variables into their values. Also called string interpolation and the documentation for groovy's gstrings is https://groovy-lang.org/syntax.html#_string_interpolation .

    What you need to do is change your ''' blocks to """. Because string interpolation only works with " quotes and not ' quotes.

    Here is a full example of how I would probably write the code:

    script {
    
    // This single forward slash makes the first line of the string begin with export and not be empty
    String bashVars = """\
        export GIT_USERNAME=${GIT_USERNAME};
        export GIT_PASSWORD=${GIT_PASSWORD};
        export PROYECT_DIRECTORY=${PROYECT_DIRECTORY};
        export CHECKOUT_POINT=${CHECKOUT_POINT};
        export GIT_HTTPS_REPO_DEPLOY=${GIT_HTTPS_REPO_DEPLOY};
        export MARIADB_HOSTNAME=${MARIADB_HOSTNAME};
    """
    
    withCredentials([
        gitUsernamePassword(credentialsId: 'jenkins-credentials', gitToolName: 'Default', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD')
    ]) {
    
        // Groovy ternary operator aka one line if statement
        String scriptPath = env.APP_ENV == 'testing' ? './scripts/awesome_script_2.sh' : './scripts/awesome_script.sh'
    
        String script = """\
            #!/bin/bash
            ${bashVars}
            ${scriptPath}
        """
    
        sh(script)
    }
    

    }

    Notice I used variable typing? It will give you better error messages if something does go wrong in your pipeline.

    As you advance and become better with Jenkins you might want to switch to scripted pipelines. They are a lot more powerful than declarative.

    EDIT: While my answer is great for anyone wanting to know the specifics about string interpolation in groovy, the answer by https://devops.stackexchange.com/a/16330/4427#4427 is really good for someone wanting to have a scripted pipeline with conditional stages based on something like a variable.



Suggested Topics