Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Creating a reciprocal remote link with postfunction

Robert November 14, 2017

Hi,

 

I have 2 JIRA instances (01 & 02) and in them I created 2 projects (project "TEST01" in instance 01 & project "TEST02" in instance 02). My goal now is to write a postfunction for instance 01, that creates a new issue in instance 02 and furthermore creates a reciprocal remote link between the 2 issues.

I have already written a script, that creates a new issue (in instance 02) via the REST API. Then, also via the REST API the script links the new issue to the issue in instance 01.

The problem now is, that I don't know how I am supposed to create the link from issue in instance 01 to the new issue in instance 02.

 

Script overview:

  1. Creating application link
  2. Creating new issue in instance 02
  3. Creating URLs
  4. Create remote link from new issue (in instance 02) to original issue (in instance 01)
  5. Creating remote link

The error occurs in the last few lines - in the "Creating remote link" section.

Does somebody know why the validation result is invalid? Or is there a better approach to creating a reciprocal remote link?

 

Thank you for your help!

 

import com.atlassian.jira.issue.link.RemoteIssueLinkManager
import com.atlassian.jira.issue.link.RemoteIssueLinkBuilder
import com.atlassian.jira.bc.issue.link.RemoteIssueLinkService
import com.atlassian.jira.bc.issue.link.RemoteIssueLinkService.CreateValidationResult
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.applinks.api.ApplicationLinkService
import com.atlassian.applinks.api.application.jira.JiraApplicationType
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.sal.api.net.Response
import com.atlassian.sal.api.net.ResponseException
import com.atlassian.sal.api.net.ResponseHandler
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import static com.atlassian.sal.api.net.Request.MethodType.POST
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager
import org.apache.log4j.Category
import org.apache.log4j.Level

def Category log = Category.getInstance("com.onresolve.jira.groovy.PostFunction")
log.setLevel(org.apache.log4j.Level.DEBUG)


// Get access to 2nd Jira instance
///////////////////////////////////////////////////////////////////////////////////////////
def appLinkService = ComponentLocator.getComponent(ApplicationLinkService)
def appLink = appLinkService.getPrimaryApplicationLink(JiraApplicationType)
def applicationLinkRequestFactory = appLink.createAuthenticatedRequestFactory()

// Creating new issue in instance 02
///////////////////////////////////////////////////////////////////////////////////////////
def input = new JsonBuilder([
    fields: [
        project: [
            id: "10006"                    // Determines in which project the issue is created
        ],
        summary: "I am new",
        issuetype: [
            id: "10001"                    // Determines the IssueType that is created
        ],
        reporter: [
            name: "admin"
        ]
    ]
]).toString()

def createdIssue            
def responseContentJson
def request = applicationLinkRequestFactory.createRequest(POST, "/rest/api/2/issue")
    .addHeader("Content-Type", "application/json")
    .setEntity(input)

request.execute(new ResponseHandler<Response>() {
    @Override
    void handle(Response response) throws ResponseException {
        responseContentJson = response.responseBodyAsString                // The response is converted to a Json String
        def jsonSlurper = new JsonSlurper()
        createdIssue = jsonSlurper.parseText(responseContentJson)        // The Slurper parses the Json Format, so that the properties can be extracted
        if ( response.statusCode != 201) {
            log.error("Creating jira issue failed: ${response.responseBodyAsString}")
        }
    }
})
///////////////////////////////////////////////////////////////////////////////////////////



// Creating URLs
///////////////////////////////////////////////////////////////////////////////////////////
def createdIssueKey = createdIssue.key.toString()
def injectedIssueKey = issue.getKey().toString()
def injectedIssueUrl = ("http://manubox01.bytesource.info/jira/browse/" + injectedIssueKey)
def createdIssueUrl = ("http://manubox02.bytesource.info/jira/browse/" + createdIssueKey)
def post2 = ("/rest/api/2/issue/" + createdIssueKey + "/remotelink")

log.debug('URL from created Issue: ' + createdIssueUrl)
log.debug('URL from injected Issue: ' + injectedIssueUrl)
///////////////////////////////////////////////////////////////////////////////////////////



// Create remote link from new issue (in instance 02) to original issue (in instance 01)
///////////////////////////////////////////////////////////////////////////////////////////
def input2 = new JsonBuilder([
    object: [
        url: injectedIssueUrl,
        title: injectedIssueKey
        ]
]).toString()

def request2 = applicationLinkRequestFactory.createRequest(POST, post2)
    .addHeader("Content-Type", "application/json")
    .setEntity(input2)

def responseContentJson2
request2.execute(new ResponseHandler<Response>() {
    @Override
    void handle(Response response2) throws ResponseException {
        responseContentJson2 = response2.responseBodyAsString
        if ( response2.statusCode != 201) {
            log.error ("Remote linking jira issue failed: ${response2.responseBodyAsString}")
        }
    }
})
///////////////////////////////////////////////////////////////////////////////////////////



// Create reciprocal link
///////////////////////////////////////////////////////////////////////////////////////////
def user = ComponentAccessor.getUserManager().getUserByName("admin")
log.info('User: ' + user)

def linkBuilder = new RemoteIssueLinkBuilder()
linkBuilder.url(createdIssueUrl)
linkBuilder.title(createdIssueKey)

def remoteIssueLinkService = ComponentManager.getComponentInstanceOfType(RemoteIssueLinkService.class)

def validationResult = remoteIssueLinkService.validateCreate(user, linkBuilder.build())
log.debug("Validation result: " + validationResult)

remoteIssueLinkService.create(user, validationResult)
///////////////////////////////////////////////////////////////////////////////////////////

 

2017-11-14 10:28:48,403 DEBUG [groovy.PostFunction]: URL from created Issue: http://manubox02.bytesource.info/jira/browse/TEST02-18
2017-11-14 10:28:48,427 DEBUG [groovy.PostFunction]: URL from injected Issue: http://manubox01.bytesource.info/jira/browse/TEST01-3
2017-11-14 10:28:48,532 INFO [groovy.PostFunction]: User: admin(admin)
2017-11-14 10:28:48,564 DEBUG [groovy.PostFunction]: Validation result: com.atlassian.jira.bc.issue.link.RemoteIssueLinkService$CreateValidationResult@1f2386c9
2017-11-14 10:28:48,602 ERROR [workflow.ScriptWorkflowFunction]: *************************************************************************************
2017-11-14 10:28:48,604 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: TEST01-3, actionId: 31, file: <inline script>
java.lang.IllegalStateException: You cannot create a remote issue link with an invalid validation result.
	at com.atlassian.jira.bc.issue.link.DefaultRemoteIssueLinkService.create(DefaultRemoteIssueLinkService.java:201)
	at com.atlassian.jira.bc.issue.link.RemoteIssueLinkService$create$0.call(Unknown Source)
	at Script41.run(Script41.groovy:128)

 

1 answer

1 accepted

1 vote
Answer accepted
Thanos Batagiannis [Adaptavist]
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 16, 2017

Hi Robert,

I think you are close enough. So for the create remote issue link part hopefully the following script will help you.

import com.atlassian.jira.bc.issue.link.RemoteIssueLinkService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.link.RemoteIssueLinkBuilder

def user = ComponentAccessor.getUserManager().getUserByName("admin")

//this will be the issue that the remote link will get created
def sourceIssue = ComponentAccessor.issueManager.getIssueByCurrentKey("ATG-1")

def linkBuilder = new RemoteIssueLinkBuilder()

linkBuilder.issueId(sourceIssue.id)
linkBuilder.url("https://www.google.co.uk")
linkBuilder.title("Google")

def remoteIssueLinkService = ComponentAccessor.getComponent(RemoteIssueLinkService)
def validationResult = remoteIssueLinkService.validateCreate(user, linkBuilder.build())

if (validationResult.isValid()) {
remoteIssueLinkService.create(user, validationResult)
log.debug "Remote link created"
}
else {
log.error validationResult.errorCollection.errorMessages
}

Please ping me if this does not help. Hopefully now you will be able to get more info in your logs why the validationResult is not valid.

regards, Thanos

Robert November 16, 2017

Hi Thanos,

 

thank you very much for your help! Indeed that was the problem. I simply did not specify the source issue. The "linkBuilder.issueId()" was missing. Now it's working!

For whatever reason I thought that this was already given in a post function.

Again, thank you for your help!

 

Best regards

Robert

Tarun Sapra
Community Champion
February 14, 2018
Adolfo Casari
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 4, 2018

@RobertThanks for sharing this code. I see you're using appLink.createAuthenticatedRequestFactory() to create the request.

I wonder how have you configured your app links, since I can´t make it work for me. I get a code 401 (Unauthorized) from request.execute.

I also would like to know if in your scenario the user that is executing the transition in jira 01 always exists and has the permission to create issues in Jira 02, even when you are setting the reporter to admin in the issue in Jira 02.

Thanks!

 

Suggest an answer

Log in or Sign up to answer