Sync Jira linked issues to ADO

Originally asked by Pavel Kholodyr on 27 July 2022 (original question)


Hi all,

I’m try to make sync Jira linked issues to ADO,

from Jira side Outgoing sync we have:

replica.linkedIssues = issue.issueLinks

ADO side:

def linkTypeMapping = [
    "Duplicates": "System.LinkTypes.Duplicate-Forward",
    "Related": "System.LinkTypes.Related",
     ...
]

def linkedIssues = replica.linkedIssues
if (linkedIssues) {
    replica.linkedIssues.each{
        def await = { f -> scala.concurrent.Await$.MODULE$.result(f, scala.concurrent.duration.Duration.apply(1, java.util.concurrent.TimeUnit.MINUTES)) }
        def creds = await(httpClient.azureClient.getCredentials())
        def token = creds.accessToken()
        def baseUrl = creds.issueTrackerUrl()
        def project = workItem.projectKey
       
        def localParent = syncHelper.getLocalIssueKeyFromRemoteId(it.otherIssueId.toLong())
        
        if (!localParent.id) { return; }
        
        def localUrl = baseUrl + '/_apis/wit/workItems/' + localParent.id

        def createIterationBody = [
            [
                op: "test",
                path: "/rev",
                value: 3
            ],
            [
                op:"add",
                path:"/relations/-",
                value: [
                    rel:linkTypeMapping[it.linkName],
                    url:localUrl,
                    attributes: [
                        comment:""
                    ]
                ]
            ]
        ]
      
        def createIterationBodyStr = groovy.json.JsonOutput.toJson(createIterationBody)

           def result = await(httpClient.azureClient.ws
            .url(baseUrl+"/${project}/_apis/wit/workitems/${workItem.id}?api-version=6.0")
            .withAuth(token, token, play.api.libs.ws.WSAuthScheme$BASIC$.MODULE$)
            .withBody(play.api.libs.json.Json.parse(createIterationBodyStr), play.api.libs.ws.JsonBodyWritables$.MODULE$.writeableOf_JsValue)
            .withMethod("PATCH")
            .execute())
    }
}


And we have error

(StandaloneAhcWSResponse(400, Bad Request))RESULT BODY{"$id":"1","innerException":null,"message":"The request indicated a Content-Type of \"application/json\" for method type \"PATCH\" which is not supported. Valid content types for this method are: application/json-patch+json.","typeName":"Microsoft.VisualStudio.Services.WebApi.VssRequestContentTypeNotSupportedException, Microsoft.VisualStudio.Services.WebApi","typeKey":"VssRequestContentTypeNotSupportedException","errorCode":0,"eventId":3000}

Answer by Syed Majid Hassan on 05 August 2022

Hi,

The following worked for me:

        def createIterationBodyStr = groovy.json.JsonOutput.toJson(createIterationBody)
        converter = scala.collection.JavaConverters;
        arrForScala = [new scala.Tuple2("Content-Type","application/json-patch+json")]
        scalaSeq = converter.asScalaIteratorConverter(arrForScala.iterator()).asScala().toSeq();
        createIterationBodyStr = groovy.json.JsonOutput.toJson(createIterationBody)
        def result = await(httpClient.azureClient.ws
            .url(baseUrl+"/${project}/_apis/wit/workitems/${workItem.id}?api-version=6.0")
            .addHttpHeaders(scalaSeq)
            .withAuth(token, token, play.api.libs.ws.WSAuthScheme$BASIC$.MODULE$)
            .withBody(play.api.libs.json.Json.parse(createIterationBodyStr), play.api.libs.ws.JsonBodyWritables$.MODULE$.writeableOf_JsValue)
            .withMethod("PATCH")
            .execute())

Check this video (old community) to see it in action!

Please let me know if you have any further questions on this one.

Thanks

Majid


Answer by Francis Martens (Exalate) on 03 August 2022

Hi Pavel Kholodyr

The error returned by ADO is

The crux of this message is

"The request indicated a Content-Type of \"application/json\" for method type \"PATCH\" which is not supported. Valid content types for this method are: application/json-patch+json."

This indicates that you have to add a header to the request - this can be done using the addHttpHeaders method - as in

UNTESTED

def result = await(httpClient.azureClient.ws
            .url(baseUrl+"/${project}/_apis/wit/workitems/${workItem.id}?api-version=6.0")
            .withAuth(token, token, play.api.libs.ws.WSAuthScheme$BASIC$.MODULE$)
            .withBody(play.api.libs.json.Json.parse(createIterationBodyStr), play.api.libs.ws.JsonBodyWritables$.MODULE$.writeableOf_JsValue)
            .addHttpHeaders([scala.Tuple2.apply("Content-Type", "application/json-patch+json")])
            .withMethod("PATCH")
            .execute())

Can you give it a try and let me know?


Comments:

Pavel Kholodyr commented on 04 August 2022

Hi, Francis Martens (Exalate) ,

  1. Tried your code but got another error: img.png
  2. Tried to remove array brackets- got error: img1.png

3. Tried to convert another way but now I get another error img2. Row 392-img3(code in block and in picture is the same)

 converter = scala.collection.JavaConverters;
  arrForScala = ["Content-Type","application/json-patch+json"]
  scalaSeq = converter.asScalaIteratorConverter(arrForScala.iterator()).asScala().toSeq();
debug.error("SCALA" + scalaSeq+"SCALA"+ scalaSeq.class)
        def createIterationBodyStr = groovy.json.JsonOutput.toJson(createIterationBody)
        // debug.error("JSON" + createIterationBodyStr+"JSON TYPE" + createIterationBodyStr.class)
       // debug.error("debug "+workItem.id + "  "+baseUrl+"/${project}/_apis/wit/workitems/${workItem.id}?api-version=6.0")
           def result = await(httpClient.azureClient.ws
            .url(baseUrl+"/${project}/_apis/wit/workitems/${workItem.id}?api-version=6.0")
            .withAuth(token, token, play.api.libs.ws.WSAuthScheme$BASIC$.MODULE$)
            .withBody(play.api.libs.json.Json.parse(createIterationBodyStr), play.api.libs.ws.JsonBodyWritables$.MODULE$.writeableOf_JsValue)
           // .addHttpHeaders("Content-Type", "application/json-patch+json")
            .addHttpHeaders(scalaSeq)
            .withMethod("PATCH")
            .execute())

Serhiy Onyshchenko commented on 04 August 2022

Hey, Pavel Kholodyr , please try

converter = scala.collection.JavaConverters;
  arrForScala = [new scala.Tuple2("Content-Type","application/json-patch+json")]
  scalaSeq = converter.asScalaIteratorConverter(arrForScala.iterator()).asScala().toSeq();
debug.error("SCALA" + scalaSeq+"SCALA"+ scalaSeq.class)
        def createIterationBodyStr = groovy.json.JsonOutput.toJson(createIterationBody)
        // debug.error("JSON" + createIterationBodyStr+"JSON TYPE" + createIterationBodyStr.class)
       // debug.error("debug "+workItem.id + "  "+baseUrl+"/${project}/_apis/wit/workitems/${workItem.id}?api-version=6.0")
           def result = await(httpClient.azureClient.ws
            .url(baseUrl+"/${project}/_apis/wit/workitems/${workItem.id}?api-version=6.0")
            .withAuth(token, token, play.api.libs.ws.WSAuthScheme$BASIC$.MODULE$)
            .withBody(play.api.libs.json.Json.parse(createIterationBodyStr), play.api.libs.ws.JsonBodyWritables$.MODULE$.writeableOf_JsValue)
           // .addHttpHeaders("Content-Type", "application/json-patch+json")
            .addHttpHeaders(scalaSeq)
            .withMethod("PATCH")
            .execute())
Oleksandra Honcharenko commented on 04 August 2022

Hello Serhiy Onyshchenko I am working with Pavel on the same script. And we tried your fix but got error:

We used this debug code:

debug.error("RESULT"+result+"RESULT  BODY"+result.body() + "  " + baseUrl+"/_apis/wit/workitems/${workItem.id}?api-version=6.0")
Oleksandra Honcharenko commented on 08 August 2022

Serhiy Onyshchenko Any ideas?
(Also we will need DELETE request to delete links from ADO.)

Francis Martens (Exalate) commented on 08 August 2022

Oleksandra Honcharenko - checkout the suggestion from Majid ^^^