How to get the changes since the last successful build in jenkins pipeline?

后端 未结 6 533
忘了有多久
忘了有多久 2020-12-09 10:44

Anyone have a Jenkins Pipeline script that can stuff all the changes since the previous successful build in a variable? I\'m using git and a multibranch pipeline job.

相关标签:
6条回答
  • 2020-12-09 11:08

    For anyone using Accurev here is an adaptation of andsens answer. andsens answer can't be used because the Accurev plugin doesn't implement getAffectedFiles. Documentation for the AccurevTransaction that extends the ChangeLogSet.Entry class can be found at 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
    
    0 讨论(0)
  • 2020-12-09 11:17

    This is what I've used:

    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()
    
    0 讨论(0)
  • 2020-12-09 11:26

    Well I managed to cobble something together. I'm pretty sure I you can iterate the arrays better but here's what I've got for now:

    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 讨论(0)
  • 2020-12-09 11:30

    In order to return the changes as a list of strings, instead of just printing them, you may use this function (based on @andsens answer):

    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()
    }
    
    0 讨论(0)
  • 2020-12-09 11:31

    Based on the answer from CaptRespect i came up with the following script for use in the declarative pipeline:

    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
    

    This is quite useful in stage->when->expression parts to run a stage only when certain files were changed. I haven't gotten to that part yet though, I'd love to create a shared library from this and make it possible to pass it some globbing patterns to check for.

    EDIT: Check the docs btw, in case you want to delve a little deeper. You should be able to convert all the object.getSomeProperty() calls into just entry.someProperty.

    0 讨论(0)
  • 2020-12-09 11:33

    There's the Changes Since Last Success Plugin that could help you with that.

    0 讨论(0)
提交回复
热议问题