【问题标题】:How to get the changes since the last successful build in jenkins pipeline?自上次成功构建詹金斯管道以来如何获得更改?
【发布时间】:2016-10-31 06:55:18
【问题描述】:

任何人都有一个 Jenkins Pipeline 脚本,可以将自上次成功构建以来的所有更改填充到变量中?我正在使用 git 和多分支管道作业。

【问题讨论】:

    标签: jenkins jenkins-pipeline


    【解决方案1】:

    好吧,我设法拼凑了一些东西。我很确定我可以更好地迭代数组,但这是我现在所拥有的:

    node('Android') {
      passedBuilds = []
    
      lastSuccessfulBuild(passedBuilds, currentBuild);
    
      def changeLog = getChangeLog(passedBuilds)
      echo "changeLog ${changeLog}"
    }
    
    def lastSuccessfulBuild(passedBuilds, build) {
      if ((build != null) && (build.result != 'SUCCESS')) {
          passedBuilds.add(build)
          lastSuccessfulBuild(passedBuilds, build.getPreviousBuild())
       }
    }
    
    @NonCPS
    def getChangeLog(passedBuilds) {
        def log = ""
        for (int x = 0; x < passedBuilds.size(); x++) {
            def currentBuild = passedBuilds[x];
            def changeLogSets = currentBuild.rawBuild.changeSets
            for (int i = 0; i < changeLogSets.size(); i++) {
                def entries = changeLogSets[i].items
                for (int j = 0; j < entries.length; j++) {
                    def entry = entries[j]
                    log += "* ${entry.msg} by ${entry.author} \n"
                }
            }
        }
        return log;
      }
    

    【讨论】:

    • 不幸的是,工作的第一个构建返回 0 个更改。理想情况下,我会认为每个文件在第一次构建时都已更改。参考:issues.jenkins-ci.org/browse/JENKINS-26354
    • 你将如何修改它以接受某个 Jenkins 作业作为参数?
    • 这总是给我一个空的更改日志。在lastSuccessfulBuild()函数中,为什么if()语句是build.result != SUCCESS
    • @RaGe:经过努力,我以经验的方式意识到currentBuild.rawBuild.changeSets 是在调用checkout scm 期间初始化的。如果您在此说明之前拨打电话,您将一无所获。
    【解决方案2】:

    根据 CaptRespect 的回答,我想出了以下用于声明性管道的脚本:

    def changes = "Changes:\n"
    build = currentBuild
    while(build != null && build.result != 'SUCCESS') {
        changes += "In ${build.id}:\n"
        for (changeLog in build.changeSets) {
            for(entry in changeLog.items) {
                for(file in entry.affectedFiles) {
                    changes += "* ${file.path}\n"
                }
            }
        }
        build = build.previousBuild
    }
    echo changes
    

    这在stage-&gt;when-&gt;expression 部分非常有用,仅在某些文件更改时运行阶段。不过,我还没有达到那部分,我很想以此创建一个共享库,并使其可以传递一些通配符模式以进行检查。

    编辑:Check the docs 顺便说一句,以防您想更深入地研究。您应该能够将所有 object.getSomeProperty() 调用转换为 entry.someProperty

    【讨论】:

    • 不错。如果您愿意提供一些管道示例,可以使用 github 存储库:github.com/jenkinsci/pipeline-examples
    • 这不是声明式管道风格,而是脚本式管道!
    • @Lincoln,是的。您不能以声明方式执行此操作。您需要做的是将其包装在脚本块中或从共享库中使用它。
    【解决方案3】:

    这是我用过的:

    def listFilesForBuild(build) {
      def files = []
      currentBuild.changeSets.each {
        it.items.each {
          it.affectedFiles.each {
            files << it.path
          }
        }
      }
      files
    }
    
    def filesSinceLastPass() {
      def files = []
      def build = currentBuild
      while(build.result != 'SUCCESS') {
        files += listFilesForBuild(build)
        build = build.getPreviousBuild()
      }
      return files.unique()
    }
    
    def files = filesSinceLastPass()
    

    【讨论】:

      【解决方案4】:

      【讨论】:

      • 是的,我检查过了,但不知道如何从 JenkinsFile 访问它
      【解决方案5】:

      对于任何使用 Accurev 的人来说,这里是对 andsens 答案的改编。无法使用 andsens 答案,因为 Accurev 插件没有实现 getAffectedFiles。扩展 ChangeLogSet.Entry 类的 AccurevTransaction 的文档可以在here.找到。

      import hudson.plugins.accurev.*
      
      def changes = "Changes: \n"
      build = currentBuild
      // Go through the previous builds and get changes until the
      // last successful build is found.
      while (build != null && build.result != 'SUCCESS') {
          changes += "Build ${build.id}:\n"
      
          for (changeLog in build.changeSets) {
              for (AccurevTransaction entry in changeLog.items) {
                  changes += "\n    Issue: " + entry.getIssueNum()
                  changes += "\n    Change Type: " + entry.getAction()
                  changes += "\n    Change Message: " + entry.getMsg()
                  changes += "\n    Author: " + entry.getAuthor()
                  changes += "\n    Date: " + entry.getDate()
                  changes += "\n    Files: "
                  for (path in entry.getAffectedPaths()) {
                      changes += "\n        " + path;
                  }
                  changes += "\n"
              }
          }
          build = build.previousBuild
      }
      echo changes
      writeFile file: "changeLog.txt", text: changes
      

      【讨论】:

        【解决方案6】:

        为了将更改作为字符串列表返回,而不仅仅是打印它们,您可以使用此函数(基于@andsens 答案):

        def getChangesSinceLastSuccessfulBuild() {
            def changes = []
            def build = currentBuild
        
            while (build != null && build.result != 'SUCCESS') {
                changes += (build.changeSets.collect { changeSet ->
                    (changeSet.items.collect { item ->
                        (item.affectedFiles.collect { affectedFile ->
                            affectedFile.path
                        }).flatten()
                    }).flatten()
                }).flatten()
        
                build = build.previousBuild
            }
        
            return changes.unique()
        }
        

        【讨论】:

          猜你喜欢
          • 2021-11-14
          • 1970-01-01
          • 2017-01-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-11
          • 2019-01-09
          相关资源
          最近更新 更多