代码之家  ›  专栏  ›  技术社区  ›  Noah Watkins

将循环变量传递给Jenkins文件中的sh时作用域不正确

  •  1
  • Noah Watkins  · 技术社区  · 6 年前

    我尝试使用以下循环在Jenkins文件中动态创建作业。作业创建正确,任务名称以正确的名称显示在Jenkins中(例如。 ubuntu:bionic

    但是,每个任务中的 sh 命令似乎没有访问权限 images 作为 ${images[i]} 正在对其进行评估 null (例如。 sh ci/script.sh null

    def images = ["ubuntu:bionic", "ubuntu:xenial"]
    def tasks = [:]
    
    for (int i = 0; i < images.size(); i++) {
      tasks["${images[i]}"] = {
        node {
          lock("build") {
            stage('checkout') {
              checkout scm
            }
            stage('test') {
              sh "ci/script.sh ${images[i]}"
            }
          }
        }
      }
    }
    
    stage("matrix") {
      parallel tasks
    }
    

    如何正确构建这些动态命令?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Szymon Stepniak    6 年前

    并在循环中指定要创建的闭包 tasks["${images[i]}"] images.getAt(i) 顺流 i 2 在这两种情况下。请看下面的示例,其中包含一些当前 状态(我跳过了 scm checkout

    def images = ["ubuntu:bionic", "ubuntu:xenial"]
    def tasks = [:]
    
    for (int i = 0; i < images.size(); i++) {
      println "Using i = ${i}"                             // <- first print
      tasks["${images[i]}"] = {
        node {
          lock("build") {
            stage('checkout') {
              echo "ok"
            }
            stage('test') {
              println "Print i inside stage = ${i}"        // <- second print
              echo "Echo i inside stage = ${i}"            // <- third print
              sh "ci/script.sh ${images[i]}".toString()
            }
          }
        }
      }
    }
    
    stage("matrix") {
      parallel tasks
    }
    

    [Pipeline] echo
    Using i = 0
    [Pipeline] echo
    Using i = 1
    [Pipeline] stage
    [Pipeline] { (matrix)
    [Pipeline] parallel
    [Pipeline] [ubuntu:bionic] { (Branch: ubuntu:bionic)
    [Pipeline] [ubuntu:xenial] { (Branch: ubuntu:xenial)
    [Pipeline] [ubuntu:bionic] node
    [ubuntu:bionic] Running on Jenkins in /var/jenkins_home/workspace/test-pipeline
    [Pipeline] [ubuntu:xenial] node
    [ubuntu:xenial] Running on Jenkins in /var/jenkins_home/workspace/test-pipeline@2
    [Pipeline] [ubuntu:bionic] {
    [Pipeline] [ubuntu:xenial] {
    [Pipeline] [ubuntu:bionic] lock
    [ubuntu:bionic] Trying to acquire lock on [build]
    [ubuntu:bionic] Lock acquired on [build]
    [Pipeline] [ubuntu:bionic] {
    [Pipeline] [ubuntu:xenial] lock
    [ubuntu:xenial] Trying to acquire lock on [build]
    [ubuntu:xenial] Found 0 available resource(s). Waiting for correct amount: 1.
    [ubuntu:xenial] [build] is locked, waiting...
    [Pipeline] [ubuntu:bionic] stage
    [Pipeline] [ubuntu:bionic] { (checkout)
    [Pipeline] [ubuntu:bionic] echo
    [ubuntu:bionic] ok
    [Pipeline] [ubuntu:bionic] }
    [Pipeline] [ubuntu:bionic] // stage
    [Pipeline] [ubuntu:bionic] stage
    [Pipeline] [ubuntu:bionic] { (test)
    [Pipeline] [ubuntu:bionic] echo
    [ubuntu:bionic] Print i inside stage = 2
    [Pipeline] [ubuntu:bionic] echo
    [ubuntu:bionic] Echo i inside stage = 2
    [Pipeline] [ubuntu:bionic] sh
    [ubuntu:bionic] [test-pipeline] Running shell script
    [ubuntu:bionic] + ci/script.sh null
    [ubuntu:bionic] /var/jenkins_home/workspace/test-pipeline@tmp/durable-998289d1/script.sh: 2: /var/jenkins_home/workspace/test-pipeline@tmp/durable-998289d1/script.sh: ci/script.sh: not found
    [Pipeline] [ubuntu:bionic] }
    [Pipeline] [ubuntu:bionic] // stage
    [ubuntu:xenial] Lock acquired on [build]
    [Pipeline] [ubuntu:bionic] }
    [ubuntu:bionic] Lock released on resource [build]
    [Pipeline] [ubuntu:xenial] {
    [Pipeline] [ubuntu:bionic] // lock
    [Pipeline] [ubuntu:bionic] }
    [Pipeline] [ubuntu:xenial] stage
    [Pipeline] [ubuntu:xenial] { (checkout)
    [Pipeline] [ubuntu:bionic] // node
    [Pipeline] [ubuntu:bionic] }
    [ubuntu:bionic] Failed in branch ubuntu:bionic
    [Pipeline] [ubuntu:xenial] echo
    [ubuntu:xenial] ok
    [Pipeline] [ubuntu:xenial] }
    [Pipeline] [ubuntu:xenial] // stage
    [Pipeline] [ubuntu:xenial] stage
    [Pipeline] [ubuntu:xenial] { (test)
    [Pipeline] [ubuntu:xenial] echo
    [ubuntu:xenial] Print i inside stage = 2
    [Pipeline] [ubuntu:xenial] echo
    [ubuntu:xenial] Echo i inside stage = 2
    [Pipeline] [ubuntu:xenial] sh
    [ubuntu:xenial] [test-pipeline@2] Running shell script
    [ubuntu:xenial] + ci/script.sh null
    [ubuntu:xenial] /var/jenkins_home/workspace/test-pipeline@2@tmp/durable-b1807fa2/script.sh: 2: /var/jenkins_home/workspace/test-pipeline@2@tmp/durable-b1807fa2/script.sh: ci/script.sh: not found
    [Pipeline] [ubuntu:xenial] }
    [Pipeline] [ubuntu:xenial] // stage
    [Pipeline] [ubuntu:xenial] }
    [ubuntu:xenial] Lock released on resource [build]
    [Pipeline] [ubuntu:xenial] // lock
    [Pipeline] [ubuntu:xenial] }
    [Pipeline] [ubuntu:xenial] // node
    [Pipeline] [ubuntu:xenial] }
    [ubuntu:xenial] Failed in branch ubuntu:xenial
    [Pipeline] // parallel
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] End of Pipeline
    ERROR: script returned exit code 127
    Finished: FAILURE
    

    我用过 println matrix 阶段每个Groovy闭包都与绑定相关联——它的局部变量状态。看起来里面有 images 绑定,并跟踪 变量这就是它试图访问的原因 images[2] sh

    解决方案

    for-loop 具有 for-each

    def images = ["ubuntu:bionic", "ubuntu:xenial"]
    def tasks = [:]
    
    images.each { image ->
      tasks["${image}"] = {
        node {
          lock("build") {
            stage('checkout') {
              checkout scm
            }
            stage('test') {
              sh "ci/script.sh ${image}"
            }
          }
        }
      }
    }
    
    stage("matrix") {
      parallel tasks
    }
    

    [ubuntu:bionic] [test-pipeline] Running shell script
    [ubuntu:bionic] + ci/script.sh ubuntu:bionic
    [ubuntu:xenial] [test-pipeline@2] Running shell script
    [ubuntu:xenial] + ci/script.sh ubuntu:xenial
    

    您可以找到有关全球范围的解释 Pipeline - Parallel execution of tasks 关于云蜂的文章:

    注: for 块不是本地的,而是脚本的全局的。测试选项2时,您会注意到该变量 打印值始终为4,而 index 从0增加到3,然后 branch 从1点到4点。