Jenkins pipeline updates JIRA

Whenever a new tag is pushed to remote (Gerrit server), process all JIRA tickets of this tag and change their status.

Requirements
- An JIRA account has permission to create new release and change ticket status
- Using git-repo and Gerrit server
- Create a changes list between two tags

Solution
- Go to your Jenkins Credentials (like http://localhost:8080/credentials/store/system/domain/_/newCredentials) and create a "Username and Password" kind credential with ID as MY_TOKEN. Put above account info into it.
- Install plugin https://plugins.jenkins.io/gerrit-trigger
- Go to Jenkins http://localhost:8080/gerrit-trigger/ and configure your Gerrit server. Name it like MY_GERRIT
- Install https://plugins.jenkins.io/gerrit-trigger
- Go to Jenkins http://localhost:8080/configure and search for "JIRA Steps". Then configure it with above MY_TOKEN
- Install jq & curl onto the agent machine. Ubuntu can run "sudo apt-get install jq curl"
- Jenkins pipeline (scripted type)

properties([
    parameters([
        string( name: 'NODE_LABEL', defaultValue: 'my_node',
description: 'Agent to run this job, should have curl and jq installed', trim: true),
        booleanParam(name: 'DELETE_WS', defaultValue: true,
description: 'Delete workspace before operation, to ensure clean results'),
string( name: 'JIRA_PROJECT', defaultValue: 'MY_JIRA_PROJECT_NAME', description: 'JIRA project key name',
trim: false),
        string(name: 'MANIFEST_BRANCH', defaultValue: 'MY_BRANCH', description: 'The Branch to repo init',
 trim: true),
        string(name: 'MANIFEST_FILE', defaultValue: 'default_static.xml',
 description: 'The manifest file used to generate the change list', trim: true),
        string(name: 'MANIFEST_URL', defaultValue: 'ssh://MY_GERRIT.com:29418/projects/MY_PROJECT/MY_REPO',
 description: 'The manifest URL to repo init', trim: true),
        string(name: 'MANIFEST_GROUP', defaultValue: 'default',
 description: 'The manifest group to repo init', trim: true),
        string(name: 'MIRROR_REPO', defaultValue: '/media/REPO_MIRROR',
 description: 'The mirror repo for reference in repo init', trim: true)
    ]),

    buildDiscarder(logRotator(numToKeepStr: '30')),
    disableConcurrentBuilds(),
    pipelineTriggers([
        gerrit( customUrl: '',
                gerritProjects:
                    [[branches: [[compareType: 'ANT', pattern: 'refs/tags/TAG_NAME01_*'],
                                 [compareType: 'ANT', pattern: 'refs/tags/TAG_NAME02_*']],
                                compareType: 'PLAIN',
                                disableStrictForbiddenFileVerification: false,
                                pattern: 'projects/MY_PROJECT/MY_REPO']],
                    serverName: 'MY_GERRIT',
                    triggerOnEvents: [refUpdated()]
       )
    ])
])

node(params.NODE_LABEL) {
    catchError {

            def tagfull = "${GERRIT_REFNAME}"
            def tagSplit = tagfull.split('/')
            String CURRENT_RELEASE = tagSplit[2]

            stage('Clean workspace') {
                if (params.DELETE_WS) deleteDir()
            }
            stage('Generate Artifacts') {
                    getManifestFile(CURRENT_RELEASE)
                    String PREVIOUS_RELEASE = getPreviousTag(CURRENT_RELEASE)
                    getManifestFile(PREVIOUS_RELEASE)

                    //Generate Change list
                    String title = "Integrated commits between ${PREVIOUS_RELEASE} -> ${CURRENT_RELEASE}\n\n"
                    String diff_manifests = title + compare_manifests(PREVIOUS_RELEASE, CURRENT_RELEASE)
                    writeFile file: 'Integration_changes.txt', text: diff_manifests, encoding: 'UTF-8'
                    archiveArtifacts artifacts: 'Integration_changes.txt'

                    // Get tickets from change list
                    String Integrated_tickets = compare_manifests_to_get_JIRA_tickets(PREVIOUS_RELEASE, CURRENT_RELEASE, params.JIRA_PROJECT)
                    writeFile file: 'Integrated_tickets.txt', text: Integrated_tickets, encoding: 'UTF-8'
                    archiveArtifacts artifacts: 'Integrated_tickets.txt'
                }
            stage('Change JIRA fixed tickets to integrated') {
                    println "Create new release version"
                    try {
                            def newFixVersion = [   name: CURRENT_RELEASE,
                                                    archived: false,
                                                    released: true,
                                                    project: params.JIRA_PROJECT ]
                            jiraNewVersion version: newFixVersion
                    } catch(error) {
                            println error
                    }
                    println "Change DONE tickets to APPROVED"
                    try {
                           def file = readFile "Integrated_tickets.txt"
                            def lines = file.readLines()
                            lines.each { String ticket ->
                                def fields = jiraGetIssue idOrKey: "${ticket}"
                                def ticket_status = fields.data.fields.status.name.toString()
                                def ticket_issuetypeID = fields.data.fields.issuetype.id.toString()
                                if (ticket_status == "Done"){
                                    def ticket_reporter = fields.data.fields.reporter.name.toString()
                                    println "Updating ${ticket} to Approved status and assign it back to reporter ${ticket_reporter}"
                                    // Get below id 123 from JIRA REST API for status Approved
                                    def transitionInput = [transition: [id: '123']]
                                    jiraTransitionIssue idOrKey: ticket, input: transitionInput
                                    jiraAssignIssue idOrKey: "${ticket}", userName: "${ticket_reporter}"
                                    // Set fixVersions to current release
                                    def editedIssue = [fields: [ // id or key must present for project.
                                                                 project: [key: params.JIRA_PROJECT],
                                                                 // id or name must present for issuetype.
                                                                 issuetype: [id: ticket_issuetypeID],
                                                                 fixVersions: [[ name: CURRENT_RELEASE ]]
                                                                ]
                                                        ]
                                    def queryParams = [notifyUsers: false]
                                    response = jiraEditIssue idOrKey: "${ticket}", queryParams: queryParams, issue: editedIssue
                                    echo response.successful.toString()
                                    echo response.data.toString()
                                }
                            }

                    } catch(error) {
                            println error
                    }
            }
    }
}
def getManifestFile(def release) {
    def path = "${env.WORKSPACE}"
    def status = sh(script: "cd ${path};
repo init -u ${params.MANIFEST_URL} -b refs/tags/${release} -m ${params.MANIFEST_FILE} --reference=${params.MIRROR_REPO} --no-clone-bundle;
repo sync -d -c -q --force-sync --no-clone-bundle -j4",
                         returnStatus: true)
    if (status == 0) {
        sh(script: "cd ${path}; repo manifest -o ${release}.xml -r")
    } else {
        println "No $release tag found, please check if the build exists"
    }
}
def getPreviousTag(def release) {
    def path = "${env.WORKSPACE}"
    String previousTag = sh(script: "cd ${path}/.repo/manifests;
git describe --abbrev=0 ${release}^", returnStdout: true).toString().trim()
    return previousTag
}
def compare_manifests(def prev_release, def current_release) {
    def prev_manifest_file = "${prev_release}.xml"
    def current_manifest_file = "${current_release}.xml"
    def path = "${env.WORKSPACE}"
    String output = sh(script: """ cd $path;
repo diffmanifests $prev_manifest_file $current_manifest_file --no-color --pretty-format "%h %B" """,
 returnStdout: true).toString()
    output = clean_output(output)
    return output
}
def compare_manifests_to_get_JIRA_tickets(def prev_release, def current_release, def project) {
    def prev_manifest_file = "${prev_release}.xml"
    def current_manifest_file = "${current_release}.xml"
    def path = "${env.WORKSPACE}"
    String output = sh(script: """cd $path;
repo diffmanifests $prev_manifest_file $current_manifest_file --no-color --pretty-format "%h %B" | grep '[+]' | grep ${project} | tr -cd '0-9A-Zn- ' | sed -e 's/ //' | sed -e 's/ /n/g' """,
returnStdout: true).toString()
    output = clean_output(output)
    return output
}
def clean_output(String output) {
    output = output.trim()
    output = output.replaceAll('[m', '')
    output = output.replaceAll('[p{Cc}p{Cn}&&[^s]]', '')
    return output
}
Loading