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 }