zAgileConnect API – Transition Jira Issues from Salesforce – Usage & Examples
Please note that zAgileConnect license is required for a user to invoke this API. The methods will throw a zsfjira.ZC.ZCApiLicenceException when executed by a user without a zAgileConnect license
Summary Steps
1. Retrieve the available Transitions for an Issue
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('SEL-1');
2. Create a Transition Issue Bean
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitionsResult.buildIssueTransitionFromName('In Progress');
3. Execute the Transition
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue('SEL-1', transitionIssueBean);
1. Retrieve Available Transitions for an Issue
You can get the Available Transitions Names as follows:
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('SEL-1');
List<String> transtionsNames = availableTransitionsResult.getAvailableTransitionsNames();
In some scenarios you may want to retrieve all the available transitions metadata returned by Jira API. It can be done using the method getTransitionsData(), it will return the metadata as a Map<String, Object>
ZCBeans.AvailableTransitionsResult availableTransitionsResult = ZC.Issues.getAvailableTransitions('SEL-1019');
Map<String, Object> transtionsData = availableTransitionsResult.getTransitionsData();
The retrieved metadata looks like:
{
"transitions": [
{
"fields": {},
"to": {
//...
},
"name": "Stop Progress",
"id": "301"
},
{
"fields":
{
"assignee": {
"operations": ["set"],
"autoCompleteUrl": "....",
"name": "Assignee",
"schema": {
"system": "assignee",
"type": "user"
},
"required": false
}
},
"to": {
//..
},
"name": "Resolve Issue",
"id": "5"
} ],
"expand": "transitions"
}
2. Create a Transition Issue Bean
There are two different ways of creating the Transition Issue Bean:
- From the AvailableTransitionsResult, where you first retrieve the available transitions for the Issue and then create the Transition Bean for a particular Transition Name.
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('SEL-1');
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitionsResult.buildIssueTransitionFromName('In Progress');
- From scratch specifying the Transition ID.
You can execute transition without calling first the getAvailableTransitions() method that retrieves Jira metadata, if you know the ID of the transition you want to try to execute. Please note the transitions that can be executed for an Issue depends on the Jira workflow, so it is possible that a transition can only be executed if the Issue has a specific status (for example an Issue can not execute the transitions “Close” if the issue is already closed).
You can create a IssueTransitionBean directly with the transition ID. Please note when setting transition screen field values (as described below) without retrieving the metadata for available Transitions you will need to set field values by its field ID (using setFieldById() method).
Integer transitionId = 41;//"Done" transition Id
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = new zsfjira.ZCBeans.TransitionIssueBean(transitionId);
transitionIssueBean.setFieldById('resolution', new Map<String, String>{'name' => 'Fixed'});
transitionIssueBean.setFieldById('summary', 'The new summary');
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue('OP-3165', transitionIssueBean);
2.1 Transition Screen Fields
Some Issue transitions may have a screen of fields configured in Jira, some of them may be required for the transition to be executed. You can set values for the Issue fields in the transition screen before executing the transition.
Getting Transition Screen Fields Names
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('OP-3165');
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitionsResult.buildIssueTransitionFromName('Done');
List<String> fieldsNames = transitionIssueBean.getFieldsNames();
Getting Required Transition Screen Fields Names
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('OP-3165');
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitionsResult.buildIssueTransitionFromName('Done');
List<String> requiredFeldsNames = transitionIssueBean .getRequiredFieldsNames();
Populating Transition Issue Screen Fields
You can populate transition Issue screen fields by using the ‘Issue Template’, just like the issue template used for creating or updating issues.
zsfjira.ZCBeans.IssueTemplate issueTemplate = new zsfjira.ZCBeans.IssueTemplate('OP-3165');
issueTemplate.setFixVersions(new zsfjira.ZCBeans.NameOrIdIssueFieldValue[]{new zsfjira.ZCBeans.NameIssueFieldValue('1.0.4')});
issueTemplate.setSummary('new summary for issue transitioned');
issueTemplate.setReporter(new zsfjira.ZCBeans.NameIssueFieldValue('zagile'));
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('OP-3165');
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitionsResult.buildIssueTransitionFromName('Done');
transitionIssueBean.populateFieldsWith(issueTemplate);
transitionIssueBean.setFieldByName('Resolution', new Map<String, String>{'name' => 'Fixed'});//you can also add more fields not supported in the issue template using the setFielByName or setFieldById
transitionIssueBean.setComment('A sample transition comment');
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue('OP-3165', transitionIssueBean);
3. Execute the Transition
To execute the transition you will need to pass the Issuekey and the Transition Issue Bean described above
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue('SEL-1', transitionIssueBean);
The execution will return a transition issue result that can be used for error handling.
3.1 Validate Transition Issue data before executing transition
You can validate and sanitize your Issue transition bean before trying to execute the transition. This will detect problems in the bean and try to correct them if possible. For example it will remove all transition screen fields that are not listed in the metadata and will return warning messages if there is a required field that is not set in the bean.
Integer transitionId = 41;// To Done
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = new zsfjira.ZCBeans.TransitionIssueBean(transitionId);
try{
String warningMessage = transitionIssueBean.validateAndSanitize();
}
catch (Exception e){
System.debug(System.LoggingLevel.ERROR, e.getMessage());
}
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('OP-3165');
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitionsResult.buildIssueTransitionFromName('Start Progress');
transitionIssueBean.setFieldById('resolution', null);
try{
String warningMessage = transitionIssueBean.validateAndSanitize();
}
catch (Exception e){
System.debug(System.LoggingLevel.ERROR, e.getMessage());
}
The validateAndSanitize() will raise an Exception when a field has an empty value or there is not the metadata.
3.2 Error handling
The method hasError() returns ‘true’ if issue transition fails. The method getErrorMessage() returns the error message.
Integer transitionId = 41;// To Done
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = new zsfjira.ZCBeans.TransitionIssueBean(transitionId);
transitionIssueBean.setFieldById('resolution', new Map<String, String>{'name' => 'Fixed'});
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue('OP-3165', transitionIssueBean);
if(transitionIssueResult.hasError()){
System.debug(System.LoggingLevel.ERROR, transitionIssueResult.getErrorMessage());
}
It may be also possible to run into some errors when trying to retrieve the available transitions, you can handle them as follows
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('SEL-1019');
if(availableTransitionsResult.hasError()){
System.debug(System.LoggingLevel.ERROR, availableTransitionsResult.getErrorMessage());
}
3.3 License Handling
All operations included in this API require the user to have a valid zAgileConnect license. Try..Catch blocks below show how to catch license exceptions.
try{
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('SEL-1019');
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitionsResult.buildIssueTransitionFromName('Start Progress');
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue('SEL-1019', transitionIssueBean);
}catch(Exception exe){
System.debug(System.LoggingLevel.ERROR, transitionIssueResult.getMessage());
// Will indicate: User [Username] does need a zAgileConnect Licence to perform this operation.
}
Close a Jira Issue on Case Closed Example
trigger OnCaseClosedJiraIssuesTrigger on Case (after update) {
List<Case> cases = new List<Case>();
for(Case oldCase: Trigger.old){
Case newCase = Trigger.newMap.get(oldCase.Id);
if(oldCase.Status != newCase.Status && newCase.Status == 'Closed'){
cases.add(oldCase);
}
}
for(Case scase: cases){
for ( zsfjira__ZIssue_SF__c issueSf :[SELECT zsfjira__ZIssue__r.zsfjira__IssueKey__c FROM zsfjira__ZIssue_SF__c WHERE zsfjira__Case__c = :scase.Id] ){
CaseClosedJiraIssuesHandler.closeIssue(issueSf.zsfjira__ZIssue__r.zsfjira__IssueKey__c);
}
}
}
public class CaseClosedJiraIssuesHandler {
@future (callout = true)
public static void closeIssue(String issueKey){
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitions = zsfjira.ZC.Issues.getAvailableTransitions(issueKey);
if(availableTransitions.getAvailableTransitionsNames().contains('Close Issue')){
zsfjira.ZCBeans.TransitionIssueBean transitionIssueBean = availableTransitions.buildIssueTransitionFromName('Close Issue');
transitionIssueBean.setFieldByName('Resolution', new Map<String, String>{'name' => 'Done'});
transitionIssueBean.setComment('Closed by case closed');
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue(issueKey, transitionIssueBean);
}
}
}
Transitioning Issues of a different Jira Connection
In the example above the Jira Connection ID was not specified, as a result, the transition will be executed in the Jira marked as 'Default' in zAgileConnect settings:
The Jira Connection ID is a unique identifier that can be specified when calling the zAgileConnect API. For example, to retrieve the available transitions of an Issue that belongs to Jira JccJiraCloud, specify its Jira connection id j01 when calling the method:
zsfjira.ZCBeans.AvailableTransitionsResult availableTransitionsResult = zsfjira.ZC.Issues.getAvailableTransitions('j01', 'SEL-1');
Same for transitioning the issue:
zsfjira.ZCBeans.TransitionIssueResult transitionIssueResult = zsfjira.ZC.Issues.transitionIssue('j01', 'SEL-1', transitionIssueBean);