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
}