【问题标题】:Jenkins pipeline skip stage if copying fails如果复制失败,Jenkins 管道将跳过阶段
【发布时间】:2021-04-17 14:29:52
【问题描述】:

假设我们有一个像这样的简单管道设置:

pipeline {
   stages {
      stage('Stage1') {
         sh '''
           echo 'Copying files'
           cp ./file1 ./directory1
         '''
      }
      stage('Stage2') {
         sh '''
           echo 'This stage should still work and run'
           cp ./directory2/files ./directory2/subdirectory
         '''
      }
      stage('Stage3') { ... }
      ...
   }
}

每当我在 Stage1 或 Stage2 中没有文件时,构建失败会说:

'cp cannot stat ./file1 ./directory1''cp cannot stat ./directory2/files ./directory2/subdirectory'

当然,如果文件存在,则两个阶段都可以正常工作。问题是如果某个阶段失败,则其余阶段的构建将失败。因此,如果 Stage1 因为没有文件而失败,那么它之后的每个阶段都会失败并且它们甚至不会运行,如果 Stage2 失败也是如此,那么我们知道 Stage1 成功但随后 Stage3 及以后的失败并且甚至不运行。

有没有办法让它在cp 命令失败并且cp cannot stat 显示时,跳过这个阶段并继续下一个阶段?或者至少让它只有那个阶段失败,它可以继续构建下一个阶段?

【问题讨论】:

  • 检查文件是否存在然后再复制不是更好吗?

标签: linux jenkins groovy


【解决方案1】:

这可以使用catchError来实现

pipeline {
    agent any
    stages {
       
        stage('1') {
            steps {
                script{
                catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                    echo 'Copying files'
                    cp ./file1 ./directory1
                }
              }
            }
        }
        stage('2') {
            steps {
                script{
                catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                    echo 'This stage should still work and run'
                    cp ./directory2/files ./directory2/subdirectory
                }
              }
            }
        }

        stage('3') {
            steps {
                sh 'exit 0'
            }
        }
    }
}

从上面的管道脚本,所有阶段都将执行。如果cp 命令在阶段 1 或阶段 2 中的任何一个都不起作用,它将在该特定阶段显示为失败,但其余阶段将执行。

类似于下面的截图:


修改后的答案

以下管道脚本包括 sh ''' ''',它不必出现在 catchError 块内。

您只能在 catchError 中包含您想要捕获错误的那些命令。


pipeline {
    agent any
    stages {

        stage('1') {
            steps {
                sh """
                
                echo 'Hello World!!!!!!!!'
                curl https://www.google.com/
                
                """ 

                catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                    echo 'Copying files'
                    cp ./file1 ./directory1
                }
            }
        }
        stage('2') {
            steps {
                catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                    echo 'This stage should still work and run'
                    cp ./directory2/files ./directory2/subdirectory
                }
            }
        }

        stage('3') {
            steps {
                sh 'exit 0'
            }
        }
    }
}

【讨论】:

  • 脚本{}是什么原因?
  • 在这种情况下,您可以或不能使用script {}。它用于在声明性管道中执行脚本。完全取决于你想不想拥有script{}
  • 啊,所以我忘了包括我在每个阶段都有一个sh ''' ... '''。您能否更新您的代码,使其包含在我的sh ''' ... ''' 中。如果我有一个 sh ''' ''' ,我认为您不需要脚本 {} 对吗?另外,如果我在cp 命令之上还有其他 bash/linux 命令,我是在 catchError 中包含它还是在 catchError 中仅包含 cp 行?
  • 不,它不需要script{} 来运行sh ''' '''。此外,您可以使用catchError 添加您想要捕获错误的那些 bash/linux 命令。在这里,您只能在catchError 中使用cp 命令。我已经修改了答案。
【解决方案2】:

这是一种在文件不存在时跳过该阶段的简单方法,使用 when 指令:

pipeline {
   agent any   
   stages {
      stage('Stage1') {
         when { expression { fileExists './file1' } }
         steps {
            sh '''
            echo 'Copying files'
            cp ./file1 ./directory1
            '''
         }
      }
      stage('Stage2') {
         when { expression { fileExists './directory2/files' } }
         steps {
            sh '''
            echo 'This stage should still work and run'
            cp ./directory2/files ./directory2/subdirectory
            '''
         }
      }
      stage('Stage3') {
         steps {
            echo "stage 3"
         }
      }
   }
}

在上述情况下,您必须在when 指令和 sh 步骤中指定两次路径,最好以另一种方式处理它,例如使用变量或闭包。 由于声明式管道的限制,我建议您改用脚本式管道。

【讨论】:

    【解决方案3】:

    您可以在尝试使用如下条件复制文件之前检查文件是否存在:

    [ -f ./directory2/files ] && cp ./directory2/files ./directory2/subdirectory || echo "File does not exist"

    Source and more info

    【讨论】: