Issue
I'm looking for a way to modify the changeset list in Jenkins to list all changes since last successful build instead of since last build regardless of the status.
Is there a way to do this for multibranch pipelines?
I need it to be in my changeSet because I need the jira plugin to pick up all those commits
This is what I have so far
@NonCPS
def commitHashForBuild(build) {
def scmAction = build?.actions.find { action -> action instanceof jenkins.scm.api.SCMRevisionAction }
return scmAction?.revision?.hash
}
def getLastSuccessfulCommit() {
def lastSuccessfulHash = null
def lastSuccessfulBuild = currentBuild.rawBuild.getPreviousSuccessfulBuild()
if ( lastSuccessfulBuild ) {
lastSuccessfulHash = commitHashForBuild(lastSuccessfulBuild)
}
return lastSuccessfulHash
}
def modifyChangeSets(commits){
currentBuild.rawBuild.changeSets = commits
}
def call(Map config) {
def lastSuccessfulCommit = getLastSuccessfulCommit()
def currentCommit = commitHashForBuild(currentBuild.rawBuild)
commits = sh(script: "git rev-list $currentCommit \"^$lastSuccessfulCommit\" --pretty=oneline --abbrev-commit ", returnStdout: true).trim().split('\n').collect{it}
modifyChangeSets(commits)
}
There is no error in the console, but the changelist doesn't get generated at all and it breaks the status UI screen
Solution
You can use the following Groovy code to get the changeSets from the last successful build.
def allChangeSetsFromLastSuccessfulBuild() {
def job = Jenkins.instance.getItem("$JOB_NAME")
def lastSuccessBuild = job.lastSuccessfulBuild.number as int
def currentBuildId = "$BUILD_ID" as int
def changeSets = []
for(int i = lastSuccessBuild + 1; i < currentBuildId; i++) {
echo "Getting Change Set for the Build ID : ${i}"
def chageSet = job.getBuildByNumber(i).getChangeSets()
changeSets.addAll(chageSet)
}
changeSets.addAll(currentBuild.changeSets) // Add the current Changeset
return changeSets
}
Full Pipeline Example
The function getFilesChanged
will return the list of files changed in all change sets.
pipeline {
agent any
stages {
stage('Build') {
steps {
git (url: 'https://github.com/xxx/sample.git', branch: 'main')
script {
def changeSets = allChangeSetsFromLastSuccessfulBuild()
echo "ChangeSet Size : ${changeSets.size()}"
echo "Files Changed : ${getFilesChanged(changeSets)}"
}
}
}
}
}
def allChangeSetsFromLastSuccessfulBuild() {
def job = Jenkins.instance.getItem("$JOB_NAME")
def lastSuccessBuild = job.lastSuccessfulBuild.number as int
def currentBuildId = "$BUILD_ID" as int
def changeSets = []
for(int i = lastSuccessBuild + 1; i < currentBuildId; i++) {
echo "Getting Change Set for the Build ID : ${i}"
def chageSet = job.getBuildByNumber(i).getChangeSets()
changeSets.addAll(chageSet)
}
changeSets.addAll(currentBuild.changeSets) // Add the current Changeset
return changeSets
}
def getFilesChanged(chgSets) {
def filesList = []
def changeLogSets = chgSets
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]
def files = new ArrayList(entry.affectedFiles)
for (int k = 0; k < files.size(); k++) {
def file = files[k]
filesList.add(file.path)
}
}
}
return filesList
}
Answered By - ycr
Answer Checked By - Marilyn (JavaFixing Volunteer)