【问题标题】:Using global variables in Jenkins Pipeline在 Jenkins Pipeline 中使用全局变量
【发布时间】:2019-02-03 10:35:14
【问题描述】:

我尝试了各种方法,但似乎没有任何效果。这是我的詹金斯文件。

def ZIP_NODE
def CODE_VERSION
pipeline{
    /*A declarative pipeline*/

    agent {
        /*Agent section*/ 
        // where would you like to run the code 
        label 'ubuntu' 
        }
    options{
        timestamps()
        }
    parameters {
        choice(choices: ['dev'], description: 'Name of the environment', name: 'ENV')
        choice(choices: ['us-east-1', 'us-west-1','us-west-2','us-east-2','ap-south-1'], description: 'What AWS region?', name: 'AWS_DEFAULT_REGION')
        string(defaultValue: "", description: '', name: 'APP_VERSION')

        }
    stages{
        /*stages section*/
        stage('Initialize the variables') {
            // Each stage is made up of steps
            steps{
                script{
                    CODE_VERSION='${BUILD_NUMBER}-${ENV}'
                    ZIP_NODE='abcdefgh-0.0.${CODE_VERSION}.zip'
                }
            }                
        }
        stage ('code - Checkout') {
            steps{
                checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'xxxxxxxxxxxxxxxxxxxxxxxxxx', url: 'http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.git']]]) 
            }  
        }

        stage ('code - Build'){
            steps{
                sh ''' 
                    echo ${JOB_NAME}
                    pwd
                    echo ${ZIP_NODE}
                    echo 'remove alraedy existing zip files'
                    rm -rf *.zip
                    zip -r ${ZIP_NODE} . 
                    chmod 777 $ZIP_NODE 
                ''' 
            }
        }
        stage('Deploy on Beanstalk'){
            steps{
                build job: 'abcdefgh-PHASER' , parameters: [[$class: 'StringParameterValue', name: 'vpc', value: ENV], [$class: 'StringParameterValue', name: 'ZIP_NODE', value: ZIP_NODE], [$class: 'StringParameterValue', name: 'CODE_VERSION', value: CODE_VERSION], [$class: 'StringParameterValue', name: 'APP_VERSION', value: BUILD_NUMBER], [$class: 'StringParameterValue', name: 'AWS_DEFAULT_REGION', value: AWS_DEFAULT_REGION], [$class: 'StringParameterValue', name: 'ParentJobName', value: JOB_NAME]]
            }
        }
    } 

}

阶段中步骤脚本的输出('初始化变量')什么也没给我,它没有设置全局变量 ZIP_NODE 的值:

[Pipeline] stage
[Pipeline] { (Initialize the variables)
[Pipeline] script
[Pipeline] {
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage

然后我们进入阶段(代码 - 构建)我们没有得到 ZIP_NODE 的值。请参阅 22:34:17 的 echo 声明

[Pipeline] stage
[Pipeline] { (code - Build)
[Pipeline] sh
22:34:16 [abcdefgh-ci-dev-pipeline] Running shell script
22:34:17 + echo abcdefgh-ci-dev-pipeline
22:34:17 abcdefgh-ci-dev-pipeline
22:34:17 + pwd
22:34:17 /home/advisor/Jenkins/workspace/abcdefgh-ci-dev-pipeline
22:34:17 + echo
22:34:17 
22:34:17 + echo remove alraedy existing zip files

感谢@awefsome,我有一些观察,我想补充一下细节: 当我使用下面的代码时,我得到了所需的输出,即 ZIP_NODE 的正确值:

 stage ('code - Build'){
            steps{
                sh "echo ${JOB_NAME} && pwd && echo ${ZIP_NODE} && echo 'remove alraedy existing zip files' && rm -rf *.zip && zip -r ${ZIP_NODE} . && chmod 777 $ZIP_NODE"
            }
        }

但是当我使用下面的代码时,我没有得到 ZIP_NODE 的值:

stage ('code - Build'){
            steps{

                sh ''' 
                        echo ${ZIP_NODE}
                        echo ${JOB_NAME}
                        pwd
                        echo ${ZIP_NODE}
                        echo ${CODE_VERSION}
                        #rm -rf .ebextensions
                        echo 'remove alraedy existing zip files'
                        rm -rf *.zip
                        zip -r ${ZIP_NODE} . 
                        chmod 777 $ZIP_NODE 
                    '''
            }
        }

【问题讨论】:

    标签: jenkins groovy environment-variables jenkins-pipeline global-variables


    【解决方案1】:
    sh '''
    '''
    

    应该是

    sh """
    """
    

    带有单引号的变量不会被处理。

    【讨论】:

    【解决方案2】:

    试试看,看看效果如何:

    def ZIP_NODE
    def CODE_VERSION
    pipeline{
        /*A declarative pipeline*/
    
        agent {
            /*Agent section*/ 
            // where would you like to run the code 
            label 'master' 
            }
        options{
            timestamps()
            }
        parameters {
            choice(choices: ['dev'], description: 'Name of the environment', name: 'ENV')
            choice(choices: ['us-east-1', 'us-west-1','us-west-2','us-east-2','ap-south-1'], description: 'What AWS region?', name: 'AWS_DEFAULT_REGION')
            string(defaultValue: "", description: '', name: 'APP_VERSION')
    
            }
        stages{
            /*stages section*/
            stage('Initialize the variables') {
                // Each stage is made up of steps
                steps{
                    script{
                        CODE_VERSION="${BUILD_NUMBER}-${ENV}"
                        ZIP_NODE="abcdefgh-0.0.${CODE_VERSION}.zip"
                    }
                }                
            }
            stage ('code - Checkout') {
                steps{
                    println "checkout skipped"
                    //checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'xxxxxxxxxxxxxxxxxxxxxxxxxx', url: 'http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.git']]]) 
                }  
            }
    
            stage ('code - Build'){
                steps{
                    sh "echo ${JOB_NAME} && pwd && echo ${ZIP_NODE} && echo 'remove alraedy existing zip files' && rm -rf *.zip && zip -r ${ZIP_NODE} . && chmod 777 $ZIP_NODE"
                }
            }
            stage('Deploy on Beanstalk'){
                steps{
                    println "build job skipped"
                    //build job: 'abcdefgh-PHASER' , parameters: [[$class: 'StringParameterValue', name: 'vpc', value: ENV], [$class: 'StringParameterValue', name: 'ZIP_NODE', value: ZIP_NODE], [$class: 'StringParameterValue', name: 'CODE_VERSION', value: CODE_VERSION], [$class: 'StringParameterValue', name: 'APP_VERSION', value: BUILD_NUMBER], [$class: 'StringParameterValue', name: 'AWS_DEFAULT_REGION', value: AWS_DEFAULT_REGION], [$class: 'StringParameterValue', name: 'ParentJobName', value: JOB_NAME]]
                }
            }
        } 
    }
    

    我得到以下输出:

    Started by user jenkins
    Running in Durability level: MAX_SURVIVABILITY
    [Pipeline] node
    Running on Jenkins in /Users/Shared/Jenkins/Home/workspace/test
    [Pipeline] {
    [Pipeline] timestamps
    [Pipeline] {
    [Pipeline] stage
    [Pipeline] { (Initialize the variables)
    [Pipeline] script
    [Pipeline] {
    [Pipeline] }
    [Pipeline] // script
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] stage
    [Pipeline] { (code - Checkout)
    [Pipeline] echo
    21:19:06 checkout skipped
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] stage
    [Pipeline] { (code - Build)
    [Pipeline] sh
    21:19:06 [test] Running shell script
    21:19:06 + echo test
    21:19:06 test
    21:19:06 + pwd
    21:19:06 /Users/Shared/Jenkins/Home/workspace/test
    21:19:06 + echo abcdefgh-0.0.17-dev.zip
    21:19:06 abcdefgh-0.0.17-dev.zip
    21:19:06 + echo 'remove alraedy existing zip files'
    21:19:06 remove alraedy existing zip files
    21:19:06 + rm -rf '*.zip'
    21:19:06 + zip -r abcdefgh-0.0.17-dev.zip .
    21:19:06 
    21:19:06 zip error: Nothing to do! (try: zip -r abcdefgh-0.0.17-dev.zip . -i .)
    [Pipeline] }
    [Pipeline] // stage
    

    【讨论】:

    • 同样的问题仍然存在
    • 我已经编辑了我的答案以适应输出。它似乎至少在我的最后工作。您能否详细说明一下,按照答案中的建议进行更改后,您得到了什么确切的错误。
    • 以下代码有效:stage ('code - Build'){ steps{ sh "echo ${JOB_NAME} && pwd && echo ${ZIP_NODE} && echo 'remove alraedy existing zip files' && rm - rf *.zip && zip -r ${ZIP_NODE} . && chmod 777 $ZIP_NODE" } } 但这不会暂存 ('code - Build'){ steps{ sh ''' echo ${ZIP_NODE} ''' } }
    • 对我来说,它只有在我定义没有“def”且没有类型说明的全局变量时才有效。
    • 是否可以使用相同的模式,但是使用 powershell 内联脚本而不是 sh inline?
    【解决方案3】:

    jenkins 上的全局环境应该在管道之外,可以在脚本内部初始化/使用,当然管道内的所有范围都知道:

    示例

    def internal_ip
    
    pipeline {
        agent { node { label "test" } }
            stages {
                stage('init') {
                    steps {
                        script {
                            def x
                            if(env.onHold.toBoolean() == true){
                                x=1
                            }else{
                                x=2
                            }
                            internal_ip = sh (
                                script: "echo 192.168.0.${x}",
                                returnStdout: true
                            ).trim()   
                        }
                    }
                }
                stage('test') {
                    steps {
                        script {
                            echo  "my internal ip is: ${internal_ip}"
                        }
                    }
                }
            }    
        }
    }
    

    【讨论】:

      【解决方案4】:

      除了@avivamganswer 是正确的。

      剩下的一个问题是,如果你想访问 Jenkins 的环境变量(参见 http://<JENKINS_URL>/env-vars.html/)来初始化这些全局变量,例如:

      def workspaceDir=${WORKSPACE}
      

      你得到:

      groovy.lang.MissingPropertyException: No such property: WORKSPACE for class: groovy.lang.Binding
      

      的想法:

      def workspaceDir
      
      pipeline {
          
          environment {
              workspaceDir=${WORKSPACE}
          }
      
          stages {
              stage('Globals test') {
                  steps {
                      script {
                         echo "workspaceDir=${workspaceDir}"
                         echo workspaceDir
                      }
                  }
              }
          }
      }
      

      导致输出:

      workspaceDir=null
      null
      

      因为涉及到两个不同的上下文:environmentGroovy,它们显然是相互独立的。

      它适用于:

      environment {
          workspaceDir=${WORKSPACE}
      }
      

      但那是一个环境变量,而不是 Groovy 上下文中的变量。

      在 Groovy 上下文中声明和初始化是通过阶段进行的:

      def workspaceDir
      
      pipeline {
      
          stages {
              stage('Initializing globals') {
                  steps {
                      script {
                          workspaceDir = "${WORKSPACE}"
                      }
                  }
              }
      
              stage('Globals test') {
                  steps {
                      script {
                         echo "workspaceDir=${workspaceDir}"
                         echo workspaceDir
                      }
                  }
              }
          }
      }
      

      输出:

      workspaceDir=C:\Users\jenkins\AppData\Local\Jenkins\.jenkins\workspace\Globals-test-project
      C:\Users\jenkins\AppData\Local\Jenkins\.jenkins\workspace\Globals-test-project
      

      【讨论】:

      • 这是因为环境变量在环境范围内声明时是不可变的。当在脚本范围内声明时,它们是完全可变的。不过,无论哪种情况,它们都只能是字符串。我的首选资源是e.printstacktrace.blog/…
      【解决方案5】:

      我在 groovy shellscript 中使用全局变量的经验是将它们声明为全局变量,然后使用阶段环境变量。看起来 shell 脚本只能访问这个私有环境变量,而不能访问全局。作为样本:

      environment{
        COMMIT_ID = "foo"
      }               
      stages{
      stage('Build'){
        environment {
          commitId = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
        }
        steps {
          script {
            COMMIT_ID = commitId
          }
        }
      }
      stage ('Build-Win-Container'){
        environment {
          commitId = "${COMMIT_ID}"
        }
        steps{
          sh label: 'build/push container', script: '''
          echo "With Windows commitId: ${commitId}"
          '''
        }
      }
      }
      
      

      我也从 * 尝试了十几种方法,但没有一种方法可以访问 shell 脚本中的变量。我认为这是因为 shell 脚本是一个步骤中的私有实例,并且只能访问此步骤中的变量(我的观点) 所以我设置了一个全局环境变量 在步骤 1 中填写此脚本 在下一步中设置环境变量并在那里填充。 最后,它在 shell 脚本中可用。没有其他方法对我有用。

      【讨论】: