Creating a reciprocal remote link with postfunction

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

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

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

Suggest an answer

Log in or Sign up to answer
How to earn badges on the Atlassian Community

How to earn badges on the Atlassian Community

Badges are a great way to show off community activity, whether you’re a newbie or a Champion.

Learn more
Community showcase
Published Thursday in Jira

5 ways you can make the most of Jira Software and Bitbucket Cloud

As part of the Bitbucket product team I'm always interested in better understanding what kind of impact the use of our tools have on the way you work. In a recent study we conducted of software devel...

75 views 0 5
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you