Connector Synchronize REST API - automating the synchronization process

This guide will help you configure your Salesforce using the Connector Synchronize REST API so that it has the ability to automate the synchronization process between Salesforce and Jira.

The benefits of using this method include not requiring Jira credentials to log in every time and streamlining the process so that time is saved.

This method will require writing several Apex Classes, the codes of which will be provided below. Also provided are Unit Test Codes for the Create REST API.

All Apex Class codes provided are also provided on our Bitbucket Repository for your reference.

(warning) This setup can only be used if your Jira instance is not behind a firewall.

Writing the Apex Class

This example will guide you on how to call the Synchronize REST API.

Before you write the Apex code that calls the remote URL, you have to allow Salesforce.com to make a call to the external server.

  1. Log in into Salesforce.
  2. Go to Your Name > Setup > Administration Setup > Security Controls > Remote Site Settings.
  3. Click New Remote Site.
  4. Enter the name of remote site.
  5. Enter your Jira URL in Remote Site URL, e.g.: http://yourjiraurl.com/
  6. Click Save.

Once you are done, you can start writing the code. Here are the steps to write a Salesforce Apex Class.

  1. Log in into Salesforce.
  2. Go to Setup > App Setup > Develop > Apex Classes > New. (If you have already created this Apex Class, you do not need to do this step).
  3. Now, create another Apex Class (follow the same steps in Step 2) and paste the following code into the field:

    global class JIRAConnectorWebserviceCalloutSync {
    
        @future (callout=true) WebService static void synchronizeWithJIRAIssue(String baseUrl, String systemId, String objectType, String caseId) {
            try {
                HttpRequest req = buildRequest(baseUrl, JIRA.username, JIRA.password, systemId, objectType, caseId);
                JIRA.sendRequest(req);
            } catch(System.CalloutException e) {         
                System.debug(e);
            }
        }
    
        // Constructs request needed to synchronize a JIRA issue from provided parameters.
        public static HttpRequest buildRequest(String baseUrl, String username, String password,
                                               String systemId, String objectType, String caseId) {
            HttpRequest req = new HttpRequest();
            String basicAuthHeader = JIRA.authHeader(username, password);
            String endpoint = getEndpoint(baseUrl, systemId, objectType, caseId);
            req.setHeader('Authorization', basicAuthHeader);
            req.setHeader('Content-Type', 'application/json');
            req.setHeader('Content-Length', '0');
            req.setEndpoint(endpoint);
            req.setMethod('PUT');
            return req;
        }
    
        // Creates the endpoint to synchronize the issue from provided parameters.
        private static String getEndpoint(String baseUrl, String systemId, String objectType, String caseId) {
            return baseUrl + '/rest/customware/connector/1.0/' + systemId + '/' + objectType +  '/' + caseId + '/issue/synchronize.json';
        }
    
    }

    Copying the above code and pasting it directly into the field may result in additional, unwanted characters being included. To avoid this from happening, we recommend pasting the code into a text editor that accepts plain text (e.g. Notepad.exe) and then recopying it again before pasting it into the field.

  4. Click Save.

WARNING

Please use this class with care. It can cause an infinite loop of Issue and Case synchronization if conflicted with Jira push updates.

Create a Jira Agent

It's important to create a custom profile called "Jira Agent" in Salesforce to avoid the problem of infinite loops.

Then we will assign a user to that profile and block it to execute the trigger. With this method, any Case updated from Jira will not trigger synchronization of issues back to Jira.

First, create a custom profile called "Jira Agent":

  1. Log in to Salesforce.
  2. Go to Setup > Administration Setup > Manage Users > Profiles > New Profile.
  3. Choose Existing Profile to be: Custom: Support Profile
  4. Fill in Profile Name with: "Jira Agent"
  5. Click Save.

    "CUSTOM: SUPPORT PROFILE" NOT AVAILABLE?

    Your version of Salesforce may not have the Custom: Support Profile option.

    If so, you can create a new profile or clone from any existing profile. But please make sure that the profile has ReadEdit and Create permissions for the relevant object.

     

Second, assign the created profile to specific user that will be used in the Connector:

  1. Go to Setup > Administration Setup > Manage Users > Users
  2. Create/Edit the user that is used as the Jira agent.
  3. Use the created profile as profile of the user.
  4. Click Save.

    WARNING

    Make sure that this user is used in Application Links authentication in Jira.

Usage of the written class

Now that the class is ready to be used and it can be called in various ways including:

  1. From within a Trigger
  2. From a Synchronize JIRA Issue Button
  3. From a Case Comment Trigger

Trigger

A Salesforce trigger can be used to automate the synchronization of Case with Jira issue. It is an event-based process similar to Jira workflow, yet more flexible.

In this example, we want to automate Jira issue synchronization when a Case is updated:

Add a Trigger code to the Case Trigger.

  1. Write Apex Class as described above.
  2. Go to Setup > Application Setup > Customize > Cases > Triggers.
  3. Create a New Trigger and replace the code with:

    trigger SynchronizeWithJIRAIssue on Case (after update) {
      
        // Check whether current user is not JIRA agent so that we don't create an infinite loop.
        if (JIRA.currentUserIsNotJiraAgent()) {
            for (Case c : Trigger.new) {   
                String objectType ='Case'; //Please change this according to the object type
                String objectId = c.id;
                // Calls the actual callout to synchronize with the JIRA issue.
                JIRAConnectorWebserviceCalloutSync.synchronizeWithJIRAIssue(JIRA.baseUrl, JIRA.systemId, objectType, objectId);
            }
        }
    
    }

    Copying the above code and pasting it directly into the field may result in additional, unwanted characters being included. To avoid this from happening, we recommend pasting the code into a text editor that accepts plain text (e.g. Notepad.exe) and then recopying it again before pasting it into the field.

  4. Change the variable accordingly:

    VariablesDetails
    objectType
    Salesforce object that is used in Connection. In our example, it is Case
  5. Click Save.

Now you are ready to use the trigger. Try creating a Case in Salesforce.com as a normal user and check if the JIRA Issue is synchronized.

Button

Other than the trigger, you can use the written Apex class for button. Using this method, you can eliminate some processes, including:

  1. The required Login page
  2. The prompt page of choosing Project and Issue type.

Steps:

  1. Write Apex Class as in above
    Then, you can follow the steps in Configuring JIRA Issue Creation Button to create a button, there are slight changes in Step 8:

    Label

    Synchronize JIRA Issue

    Name

    Synchronize_JIRA_Issue (this is auto-populated when you add a new label)

    Display Type

    Detail Page Button

    Behaviour

    Execute Javascript

    Content Source

    On Click Javascript

    Content

    {!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
    {!REQUIRESCRIPT("/soap/ajax/29.0/apex.js")}
    sforce.apex.execute("JIRAConnectorWebserviceCalloutSync","synchronizeWithJIRAIssue", {baseUrl:"http://jira.com", systemId:"1", objectType:"Case", caseId:"{!Case.Id}"});
    window.alert("JIRA Issue should now be synchronized.");
  2. Change the variables accordingly:

    VariablesDetails
    baseUrl

    Your Jira URL

    systemId

    Your system Id in Connection. You should check this in Jira under Connection

    objectType

    Salesforce object that is used in Connection. In our example, it is Case

Now you are ready to test:

  1. Create a new Case in Jira.
  2. Click on the Synchronize JIRA Issue button.
  3. You should see a pop-up window: "JIRA Issue should now be synchronized."
  4. Check your JIRA instance to see whether the issue was created.

Case Comment Trigger

The Salesforce Case Comment Trigger can be used to automate the synchronization of Case Comments with Jira Issue comments.

In this example, we want to automate the Jira Issue comment synchronization when Case is updated:

Add a Trigger code to Case Comment Trigger.

  1. Write Apex Class as described above.
  2. Go to Setup > Application Setup > Customize > Cases > Case Comments > Triggers.
  3. Create New Trigger and replace the code with:

    trigger CaseCommentSync on CaseComment (after insert, after update) {
       
        // Check whether current user is not JIRA agent so that we don't create an infinite loop.
        if (JIRA.currentUserIsNotJiraAgent()) {
            for (CaseComment cc : Trigger.new) {  
                String objectType ='Case'; // Please change this according to the object type.      
                String objectId = cc.ParentId;
                // Calls the actual callout to synchronize with the JIRA issue.
                JIRAConnectorWebserviceCalloutSync.synchronizeWithJIRAIssue(JIRA.baseUrl, JIRA.systemId, objectType, objectId);
            }
        }
    
    }

    Copying the above code and pasting it directly into the field may result in additional, unwanted characters being included. To avoid this from happening, we recommend pasting the code into a text editor that accepts plain text (e.g. Notepad.exe) and then recopying it again before pasting it into the field.

  4. Change the variable accordingly:

    VariablesDetails
    objectType
    Salesforce object that is used in Connection. In our example, it is Case
  5. Click Save.

Now you are ready to use the Case Comment trigger. Try creating a comment in a Salesforce Case as a normal user and check whether the JIRA Issue comment is synchronized.

Unit test for synchronize REST API

Provided below is the Unit Test code for this class.

Do remember to also include the Fixtures and Mock Objects found on the Apex Class Parent Code page before using the following code:

@isTest private class JIRAConnectorWebserviceCalloutSyncTest {

    // Tests synchronizeWithJIRAIssue method in JIRAConnectorWebserviceCalloutSync.
    static testMethod void synchronizeWithJIRAIssueTest() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new MockHttpResponseJIRAConnector());
        JIRAConnectorWebserviceCalloutSync.synchronizeWithJIRAIssue(TestFixture.baseUrl, TestFixture.systemId, TestFixture.objectType, TestFixture.caseId);
        Test.stopTest();
    }

    // Tests buildRequest method in JIRAConnectorWebserviceCalloutSync.
    static testMethod void buildRequestTest() {
        HttpRequest req = JIRAConnectorWebserviceCalloutSync.buildRequest(TestFixture.baseUrl, TestFixture.username,
                TestFixture.password, TestFixture.systemId, TestFixture.objectType, TestFixture.caseId);
        System.assertEquals(req.getMethod(), 'PUT');
        System.assertEquals(req.getEndpoint(), 'http://jira.com/rest/customware/connector/1.0/1/Case/1/issue/synchronize.json');
    }

    // Tests SynchronizeWithJIRAIssue trigger.
    static testMethod void synchronizeWithJIRAIssueTriggerTest() {
        Test.setMock(HttpCalloutMock.class, new MockHttpResponseJIRAConnector());
        // insert case
        Case case1 = new Case();
        insert case1;

        //update case 
        case1.Description = 'updated case description';
        update case1;
    }

    // Tests caseCommentSync trigger.
    static testMethod void caseCommentSyncTriggerTest() {
        Test.setMock(HttpCalloutMock.class, new MockHttpResponseJIRAConnector());
        // insert case
        Case case1 = new Case();
        insert case1;

        // insert casecomment
        CaseComment caseComment = new CaseComment();
        caseComment.ParentId = case1.id;
        insert caseComment;    
    }
    
}

Notes

If you are only using a Case Trigger and not using a Case Comment Trigger, synchronization will not initiate after adding or editing a comment unless the case fields have been modified.

In order for new or edited comments to automatically synchronize from Salesforce.com to JIRA, you first need to configure a Case Comment Trigger.