Here’s a comprehensive solution that addresses all the issues:
Problem 1: Missing authentication in curl command
Your curl command needs proper Jira authentication. Use a Jenkins credential to store a Jira API token:
withCredentials([string(credentialsId: 'jira-api-token', variable: 'JIRA_TOKEN')]) {
sh """
curl -X POST ${JIRA_URL}/rest/api/2/issue/${ISSUE_KEY}/transitions \
-H 'Authorization: Bearer ${JIRA_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"transition": {"id": "21"}}'
"""
}
Problem 2: Incorrect transition ID
Transition IDs are workflow-specific. To find the correct ID, query Jira’s transitions endpoint:
GET ${JIRA_URL}/rest/api/2/issue/${ISSUE_KEY}/transitions
This returns available transitions for the issue. Look for the transition named “Start Progress” or “In Progress” and use its ID.
Problem 3: Issue key extraction from branch name
Use a robust regex to extract the issue key from Git branch names:
def branchName = env.GIT_BRANCH.replaceAll('origin/', '')
def matcher = (branchName =~ /DEF-\d+/)
if (matcher.find()) {
def issueKey = matcher.group(0)
echo "Found issue key: ${issueKey}"
} else {
echo "No issue key found in branch name"
return
}
This handles branches like origin/bugfix/DEF-456-memory-leak and extracts DEF-456.
Problem 4: SonarQube quality gate integration
Instead of transitioning on every Jenkins rerun, transition based on SonarQube quality gate status:
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: false
}
script {
def qg = waitForQualityGate()
if (qg.status == 'OK') {
transitionJiraIssue(issueKey, '21') // In Progress
} else {
transitionJiraIssue(issueKey, '31') // Failed
}
}
}
}
Problem 5: Jira Automation vs direct API
For reliability, use a combination:
- Direct API from Jenkins: For immediate feedback during pipeline execution
- Jira Automation: As a fallback to handle missed transitions or complex workflow rules
Create a Jira Automation rule:
- Trigger: “Build status changed”
- Condition:
{{issue.key}} matches branch name AND build status is “IN_PROGRESS”
- Action: Transition issue to “In Progress”
This ensures transitions happen even if Jenkins API calls fail.
Complete Jenkins pipeline function:
def transitionJiraIssue(issueKey, transitionId) {
withCredentials([string(credentialsId: 'jira-api-token', variable: 'JIRA_TOKEN')]) {
def response = sh(
script: """
curl -s -w "\n%{http_code}" -X POST \
${JIRA_URL}/rest/api/2/issue/${issueKey}/transitions \
-H 'Authorization: Bearer ${JIRA_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"transition": {"id": "${transitionId}"}}'
""",
returnStdout: true
).trim()
def lines = response.split(' ')
def httpCode = lines[-1]
if (httpCode == '204') {
echo "Issue ${issueKey} transitioned successfully"
} else {
error "Failed to transition issue ${issueKey}. HTTP code: ${httpCode}"
}
}
}
Key points:
- Always check HTTP response codes to catch API failures
- Use Jenkins credentials for secure token storage
- Extract issue keys with robust regex patterns
- Verify transition IDs for your specific workflow
- Handle SonarQube quality gate status explicitly
- Implement both API calls and Jira Automation for redundancy
Permissions checklist:
- Jenkins service account needs “Transition Issues” permission in Jira
- Workflow transition must not have conditions that block automated transitions (e.g., required fields)
- API token must have appropriate scopes (read/write issues)
This approach has been stable for us across 100+ microservices with SonarQube quality gates integrated into Jira defect tracking.