Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // SETTINGS FOR THE SCRIPT
- // enter the credentials of the Cloud user with admin permissions
- def username = "jiratestuser1"
- def password = "Jump2it!"
- // enter the corresponding statuses of the source and destination issue
- // omit statuses if they are the same
- final def workflowMapping = [
- "Source Status A" : "Dest Status B",
- "Source Status C" : "Dest Status D",
- "Source Status E" : "Dest Status F",
- ]
- // if requested by the support team, fill in the project / workflow configs:
- def projectWorkflowSchemeMapping = [ "SD" : 11103L ]
- def workflowSchemeMapping = [ 11103L : """{"id":11103,"name":"Service Desk Workflow Scheme","defaultWorkflow":"Service Desk Workflow","issueTypeMappings":{},"draft":false,"self":"https://foo.atlassian.net/rest/api/2/workflowscheme/11103","issueTypes":{"10304":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10304","id":"10304","description":"A digital or physical item to be tracked.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=11772&avatarType=issuetype","name":"Asset","subtask":false,"avatarId":11772},"10104":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10104","id":"10104","description":"A new feature of the product, which has yet to be developed.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10311&avatarType=issuetype","name":"New Feature","subtask":false,"avatarId":10311},"10004":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10004","id":"10004","description":"The sub-task of the issue","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10316&avatarType=issuetype","name":"Sub-task","subtask":true,"avatarId":10316},"10102":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10102","id":"10102","description":"Issue template","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=11404&avatarType=issuetype","name":"Issue template (WBSGantt)","subtask":false,"avatarId":11404},"10001":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10001","id":"10001","description":"Created by Jira Agile - do not edit or delete. Issue type for a user story.","iconUrl":"https://foo.atlassian.net/images/icons/issuetypes/story.svg","name":"Story","subtask":false},"10002":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10002","id":"10002","description":"A problem which impairs or prevents the functions of the product.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype","name":"Bug","subtask":false,"avatarId":10303},"10200":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10200","id":"10200","description":"Created by JIRA Service Desk.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10544&avatarType=issuetype","name":"Change","subtask":false},"10202":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10202","id":"10202","description":"For system outages or incidents. Created by JIRA Service Desk.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10542&avatarType=issuetype","name":"Incident","subtask":false},"10203":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10203","id":"10203","description":"Track underlying causes of incidents. Created by JIRA Service Desk.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10545&avatarType=issuetype","name":"Problem","subtask":false},"10204":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10204","id":"10204","description":"Created by JIRA Service Desk.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10543&avatarType=issuetype","name":"Service Request","subtask":false},"10205":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10205","id":"10205","description":"UAT Feedback via Issue Collector","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10322&avatarType=issuetype","name":"User Feedback","subtask":false},"10201":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10201","id":"10201","description":"Improvement to an existing feature or functionality","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10310&avatarType=issuetype","name":"Enhancement","subtask":false,"avatarId":10310},"10301":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10301","id":"10301","description":"","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10322&avatarType=issuetype","name":"Design","subtask":false,"avatarId":10322},"10303":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10303","id":"10303","description":"","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10315&avatarType=issuetype","name":"Marketing / Social","subtask":false,"avatarId":10315},"10306":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10306","id":"10306","description":"Created by Jira Agile - do not edit or delete. Issue type for a user story.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10300&avatarType=issuetype","name":"Story","subtask":false,"avatarId":10300},"10300":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10300","id":"10300","description":"A document requiring approval.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10306&avatarType=issuetype","name":"Document","subtask":false,"avatarId":10306},"10302":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10302","id":"10302","description":"","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10306&avatarType=issuetype","name":"Communication","subtask":false,"avatarId":10306},"10003":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10003","id":"10003","description":"A task that needs to be done.","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype","name":"Task","subtask":false,"avatarId":10318},"10101":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10101","id":"10101","description":"","iconUrl":"https://foo.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10304&avatarType=issuetype","name":"Video","subtask":false,"avatarId":10304},"10000":{"self":"https://foo.atlassian.net/rest/api/2/issuetype/10000","id":"10000","description":"Created by Jira Software - do not edit or delete. Issue type for a big user story that needs to be broken down.","iconUrl":"https://foo.atlassian.net/images/icons/issuetypes/epic.svg","name":"Epic","subtask":false}}}""".toString()]
- def workflowDetailsMapping = [ "Service Desk Workflow" : """{"name":"Service Desk Workflow","description":"","sources":[{"fromStatus":{"statusCategory":{"translatedName":"To Do","primaryAlias":"To Do","colorName":"blue-gray","aliases":["To Do"],"sequence":2,"name":"New","key":"new","id":2},"iconUrl":"/images/icons/statuses/open.png","description":"The issue is open and ready for the assignee to start work on it.","name":"Open","id":"1"},"targets":[{"toStatus":{"statusCategory":{"translatedName":"In Progress","primaryAlias":"In Progress","colorName":"yellow","aliases":[],"sequence":3,"name":"In Progress","key":"indeterminate","id":4},"iconUrl":"/images/icons/statuses/inprogress.png","description":"This issue is being actively worked on at the moment by the assignee.","name":"Writing / Editing","id":"3"},"transitionName":"Start Progress"},{"toStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/resolved.png","description":"A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.","name":"Resolved","id":"5"},"transitionName":"Resolve Issue","screen":{"id":3,"name":"Resolve Issue Screen"}},{"toStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/closed.png","description":"The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.","name":"Closed","id":"6"},"transitionName":"Close Issue","screen":{"id":3,"name":"Resolve Issue Screen"}}]},{"fromStatus":{"statusCategory":{"translatedName":"In Progress","primaryAlias":"In Progress","colorName":"yellow","aliases":[],"sequence":3,"name":"In Progress","key":"indeterminate","id":4},"iconUrl":"/images/icons/statuses/inprogress.png","description":"This issue is being actively worked on at the moment by the assignee.","name":"Writing / Editing","id":"3"},"targets":[{"toStatus":{"statusCategory":{"translatedName":"To Do","primaryAlias":"To Do","colorName":"blue-gray","aliases":["To Do"],"sequence":2,"name":"New","key":"new","id":2},"iconUrl":"/images/icons/statuses/open.png","description":"The issue is open and ready for the assignee to start work on it.","name":"Open","id":"1"},"transitionName":"Stop Progress"},{"toStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/resolved.png","description":"A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.","name":"Resolved","id":"5"},"transitionName":"Resolve Issue","screen":{"id":3,"name":"Resolve Issue Screen"}},{"toStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/closed.png","description":"The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.","name":"Closed","id":"6"},"transitionName":"Close Issue","screen":{"id":3,"name":"Resolve Issue Screen"}}]},{"fromStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/resolved.png","description":"A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.","name":"Resolved","id":"5"},"targets":[{"toStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/closed.png","description":"The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.","name":"Closed","id":"6"},"transitionName":"Close Issue","screen":{"id":2,"name":"Workflow Screen"}},{"toStatus":{"statusCategory":{"translatedName":"To Do","primaryAlias":"To Do","colorName":"blue-gray","aliases":["To Do"],"sequence":2,"name":"New","key":"new","id":2},"iconUrl":"/images/icons/statuses/reopened.png","description":"This issue was once resolved, but the resolution was deemed incorrect. From here issues are either marked assigned or resolved.","name":"Reopened","id":"4"},"transitionName":"Reopen Issue","screen":{"id":2,"name":"Workflow Screen"}}]},{"fromStatus":{"statusCategory":{"translatedName":"To Do","primaryAlias":"To Do","colorName":"blue-gray","aliases":["To Do"],"sequence":2,"name":"New","key":"new","id":2},"iconUrl":"/images/icons/statuses/reopened.png","description":"This issue was once resolved, but the resolution was deemed incorrect. From here issues are either marked assigned or resolved.","name":"Reopened","id":"4"},"targets":[{"toStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/resolved.png","description":"A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.","name":"Resolved","id":"5"},"transitionName":"Resolve Issue","screen":{"id":3,"name":"Resolve Issue Screen"}},{"toStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/closed.png","description":"The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.","name":"Closed","id":"6"},"transitionName":"Close Issue","screen":{"id":3,"name":"Resolve Issue Screen"}},{"toStatus":{"statusCategory":{"translatedName":"In Progress","primaryAlias":"In Progress","colorName":"yellow","aliases":[],"sequence":3,"name":"In Progress","key":"indeterminate","id":4},"iconUrl":"/images/icons/statuses/inprogress.png","description":"This issue is being actively worked on at the moment by the assignee.","name":"Writing / Editing","id":"3"},"transitionName":"Start Progress"}]},{"fromStatus":{"statusCategory":{"translatedName":"Done","primaryAlias":"Done","colorName":"green","aliases":["Done"],"sequence":4,"name":"Complete","key":"done","id":3},"iconUrl":"/images/icons/statuses/closed.png","description":"The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.","name":"Closed","id":"6"},"targets":[{"toStatus":{"statusCategory":{"translatedName":"To Do","primaryAlias":"To Do","colorName":"blue-gray","aliases":["To Do"],"sequence":2,"name":"New","key":"new","id":2},"iconUrl":"/images/icons/statuses/reopened.png","description":"This issue was once resolved, but the resolution was deemed incorrect. From here issues are either marked assigned or resolved.","name":"Reopened","id":"4"},"transitionName":"Reopen Issue","screen":{"id":2,"name":"Workflow Screen"}}]}],"id":11212,"displayName":"Service Desk Workflow","admin":true}""".toString()]
- // END SETTINGS FOR THE SCRIPT
- issue.assignee = nodeHelper.getUserByEmail(replica.assignee?.email)
- // sync comments
- issue.comments = commentHelper.mergeComments(issue, replica, { c ->
- c.executor = nodeHelper.getUserByEmail(c.author.email)
- if (c.executor == null) {
- c.body = "[${c.author.displayName}|mailto:${c.author.email}] commented:\n${c.body}".toString()
- }
- c
- })
- // EPIC NAME AND LINK SYNC
- ({
- final def jIssue = issue
- final def injector = play.api.Play$.MODULE$.current().injector()
- def issueLevelError = { String msg ->
- new com.exalate.api.exception.IssueTrackerException(msg)
- }
- def issueLevelError2 = { String msg, Throwable e ->
- new com.exalate.api.exception.IssueTrackerException(msg, e)
- }
- def await = { scala.concurrent.Future<?> f -> scala.concurrent.Await$.MODULE$.result(f, scala.concurrent.duration.Duration$.MODULE$.Inf()) }
- def orNull = { scala.Option<?> opt -> opt.isDefined() ? opt.get() : null }
- def none = { scala.Option$.MODULE$.<?>empty() }
- def pair = { l, r -> scala.Tuple2$.MODULE$.<?, ?>apply(l, r) }
- def seq = { ... ts ->
- def list = Arrays.asList(ts)
- def scalaBuffer = scala.collection.JavaConversions.asScalaBuffer(list)
- scalaBuffer.toSeq()
- }
- def getGeneralSettings = {
- def gsp = injector.instanceOf(com.exalate.api.persistence.issuetracker.jcloud.IJCloudGeneralSettingsPersistence.class)
- def gsOpt = await(gsp.get())
- def gs = orNull(gsOpt)
- gs
- }
- final def gs = getGeneralSettings()
- def removeTailingSlash = { String str -> str.trim().replace("/+\$","") }
- final def jiraCloudUrl = removeTailingSlash(gs.issueTrackerUrl)
- def getFieldsJson = {
- //"com.pyxis.greenhopper.jira:gh-epic-link"
- def fieldsResponse
- try {
- fieldsResponse = await(httpClient.thisJira("/rest/api/2/field", "GET", null, null).get())
- } catch (Exception e) {
- throw relationLevelError2("Unable to get the fields json, please contact Exalate Support: " + e.message, e)
- }
- if (fieldsResponse.status() != 200) {
- throw relationLevelError("Can not get fields (status "+ fieldsResponse.status() +"), please contact Exalate Support: "+ fieldsResponse.body())
- }
- groovy.json.JsonSlurper s = new groovy.json.JsonSlurper()
- /*
- [..., {"id":"customfield_10990","key":"customfield_10990","name":"Epic Link","custom":true,"orderable":true,"navigable":true,"searchable":true,"clauseNames":["cf[10990]","Epic Link"],"schema":{"type":"any","custom":"com.pyxis.greenhopper.jira:gh-epic-link","customId":10990}, ...}]
- */
- def fieldsJson
- try {
- fieldsJson = s.parseText(fieldsResponse.body())
- } catch (Exception e) {
- throw relationLevelError2("Can not parse fields json, please contact Exalate Support: " + fieldsResponse.body(), e)
- }
- if (!(fieldsJson instanceof List)) {
- throw relationLevelError("Fields json has unrecognized strucutre, please contact Exalate Support: " + fieldsResponse.body())
- }
- fieldsJson as List<Map<String, Object>>
- }
- final def fieldsJson = getFieldsJson().findAll { it.schema instanceof Map }
- final def epicLinkCfJson = fieldsJson.find { it.schema.custom == "com.pyxis.greenhopper.jira:gh-epic-link" }
- final def epicNameCfJson = fieldsJson.find { it.schema.custom == "com.pyxis.greenhopper.jira:gh-epic-label" }
- def updateIssue = { com.exalate.basic.domain.BasicIssueKey issueKeyToUpdate, Map<String, Object> json ->
- // PUT /rest/api/2/issue/{issueIdOrKey}
- /*
- {
- "fields": {
- "summary": "This is a shorthand for a set operation on the summary field",
- "customfield_10010": 1,
- "customfield_10000": "This is a shorthand for a set operation on a text custom field"
- }
- }
- */
- def jsonStr = groovy.json.JsonOutput.toJson(json)
- def response
- try {
- def writable = play.api.http.Writeable$.MODULE$.wString(play.api.mvc.Codec.utf_8())
- //noinspection GroovyAssignabilityCheck
- response = await(await(httpClient.authenticate(
- none(),
- httpClient
- .ws()
- .url(jiraCloudUrl+"/rest/api/2/issue/"+issueKeyToUpdate.id)
- .withHeaders(seq(pair("Content-Type", "application/json")))
- .withBody(jsonStr, writable)
- .withMethod("PUT"),
- gs
- )).execute())
- } catch (Exception e) {
- throw issueLevelError2("Unable to update issue `"+ issueKeyToUpdate.URN +"`, please contact Exalate Support: \n" +
- "PUT "+jiraCloudUrl+"/rest/api/2/issue/"+issueKeyToUpdate.id+"\nBody: "+jsonStr+"\nError Message:"+ e.message, e)
- }
- if (response.status() != 204) {
- throw issueLevelError("Can not update issue `"+ issueKeyToUpdate.URN +"` (status "+ response.status() +"), please contact Exalate Support: \nPUT "+jiraCloudUrl+"/rest/api/2/issue/"+issueKeyToUpdate.id+"\nBody: "+jsonStr+"\nResponse:"+ response.body())
- }
- }
- def getLocalIssue = { remoteSuspectId, currentIssue ->
- if(replica.id.equals((remoteSuspectId as Long) as String)) {
- return currentIssue
- }
- nodeHelper.getLocalIssueFromRemoteId(remoteSuspectId as Long)
- }
- def getLocalEpicIssue = { currentIssue ->
- def epicContext = replica.customKeys."epicContext"
- if (!(epicContext instanceof Map)) {
- return null
- }
- def remoteEpicId = epicContext.epic.id
- getLocalIssue(remoteEpicId, currentIssue)
- }
- // EPIC NAME SYNC
- if (replica.customKeys."Epic Name" != null) {
- def cf = issue.customFields[epicNameCfJson.schema.customId as String]
- if (cf == null) {
- throw issueLevelError("Can not find the `Epic Name` custom field by id `"+epicNameCfJson.schema.customId+"`, please contact Exalate Support")
- }
- cf.value = replica.customKeys."Epic Name"
- }
- // END: EPIC NAME SYNC
- // EPIC SYNC
- // try to link all the stories to the epic:
- def localEpicJissue = getLocalEpicIssue(jIssue)
- if (localEpicJissue != null) {
- replica
- .customKeys
- ."epicContext"
- .stories
- .collect { story -> getLocalIssue(story.id, jIssue) }
- .findAll { it != null }
- .each { localStory ->
- // log.debug("linking the localStory `"+localStory.key+"` to epic `"+ localEpicJissue.key +"` for the issue `"+ jIssue.key +"` for remote issue `"+ replica.key +"`")
- updateIssue(
- new com.exalate.basic.domain.BasicIssueKey(localStory.id as Long, localStory.key),
- [
- "fields" : [
- (epicLinkCfJson.key) : localEpicJissue.key
- ]
- ]
- )
- }
- }
- def epicLinkCfIdStr = epicLinkCfJson?.schema?.customId as String
- def epicLinkCfValueInternal = issue.customFields[epicLinkCfIdStr].value
- issue.customFields.remove(epicLinkCfIdStr)
- if (replica.customKeys."epicContext" == null &&
- epicLinkCfValueInternal != null) {
- issue.customFields[epicLinkCfIdStr].value = null
- }
- // END: EPIC SYNC
- })()
- //END: EPIC NAME AND LINK SYNC
- // STATUS SYNC
- ({
- try {
- def jIssue = issue
- def localExIssueKey = issueKey
- final def injector = play.api.Play$.MODULE$.current().injector()
- def issueLevelError = { String msg ->
- new com.exalate.api.exception.IssueTrackerException(msg)
- }
- def issueLevelError2 = { String msg, Throwable e ->
- new com.exalate.api.exception.IssueTrackerException(msg, e)
- }
- def await = { scala.concurrent.Future<?> f -> scala.concurrent.Await$.MODULE$.result(f, scala.concurrent.duration.Duration$.MODULE$.Inf()) }
- def orNull = { scala.Option<?> opt -> opt.isDefined() ? opt.get() : null }
- def none = { scala.Option$.MODULE$.<?> empty() }
- def pair = { l, r -> scala.Tuple2$.MODULE$.<?, ?> apply(l, r) }
- def seq = { ... ts ->
- def list = Arrays.asList(ts)
- def scalaBuffer = scala.collection.JavaConversions.asScalaBuffer(list)
- scalaBuffer.toSeq()
- }
- def getGeneralSettings = {
- def gsp = injector.instanceOf(com.exalate.api.persistence.issuetracker.jcloud.IJCloudGeneralSettingsPersistence.class)
- def gsOpt = await(gsp.get())
- def gs = orNull(gsOpt)
- gs
- }
- final def gs = getGeneralSettings()
- def removeTailingSlash = { String str -> str.trim().replace("/+\$", "") }
- final def jiraCloudUrl = removeTailingSlash(gs.issueTrackerUrl)
- def getWorkflowSchemeIdForProject = { String projectKey ->
- def wfsId = projectWorkflowSchemeMapping[projectKey]
- if (wfsId != null) {
- return wfsId
- }
- def response
- try {
- //noinspection GroovyAssignabilityCheck
- response = await(httpClient
- .ws()
- .url(jiraCloudUrl + "/rest/projectconfig/1/workflowscheme/" + projectKey)
- .withAuth(username, password, play.api.libs.ws.WSAuthScheme.BASIC$.MODULE$)
- .withMethod("GET")
- .execute()
- )
- } catch (Exception e) {
- throw issueLevelError2(
- "Unable to get workflow scheme for project `" + projectKey + "` on behalf of user `" + username + "` using a private REST API, please contact Exalate Support: " +
- "\nRequest: GET /rest/projectconfig/1/workflowscheme/" + projectKey +
- "\nAuth: " + username + ":" + password +
- "\nError: " + e.message,
- e
- )
- }
- if (response.status() == 401) {
- throw issueLevelError("Can not get workflow scheme for project `"+ projectKey +"`. " +
- "\nKnown projects / workflow schemes: `"+ projectWorkflowSchemeMapping +"`" +
- "\nPlease contact Exalate Support. " +
- "\nAlso failed to get it through REST API: "+
- "\nRequest: GET /rest/projectconfig/1/workflowscheme/" + projectKey +
- "\nAuth: " + username +
- "\nResponse: " + response.body()
- )
- }
- if (response.status() != 200) {
- throw issueLevelError(
- "Failed to get workflow scheme for project `" + projectKey + "` on behalf of user `" + username + "` using a private REST API (status " + response.status() + "), please contact Exalate Support: " +
- "\nRequest: GET /rest/projectconfig/1/workflowscheme/" + projectKey +
- "\nAuth: " + username + ":" + password +
- "\nResponse: " + response.body()
- )
- }
- def s = new groovy.json.JsonSlurper()
- def json
- try {
- json = s.parseText(response.body())
- } catch (Exception e) {
- throw issueLevelError2("Can not parse workflow scheme json from private REST API, please contact Exalate Support: " + response.body(), e)
- }
- if (!(json instanceof Map<String, Object>)) {
- throw issueLevelError("Workflow scheme json from private REST API has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- (json as Map<String, Object>).id as Long
- }
- def getWorkflowScheme = { Long workflowSchemeId ->
- def jsonStrInternal = workflowSchemeMapping[workflowSchemeId]
- if (jsonStrInternal == null) {
- def response
- try {
- //noinspection GrUnresolvedAccess
- response = await(httpClient
- .ws()
- .url(jiraCloudUrl + "/rest/api/2/workflowscheme/" + workflowSchemeId)
- .withAuth(username, password, play.api.libs.ws.WSAuthScheme.BASIC$.MODULE$)
- .withMethod("GET")
- .execute()
- )
- } catch (Exception e) {
- throw issueLevelError2(
- "Unable to get workflow scheme by id `" + workflowSchemeId + "`, please contact Exalate Support: " +
- "\nRequest: GET /rest/api/2/workflowscheme/" + workflowSchemeId +
- "\nAuth: " + username + ":" + password +
- "\nError: " + e.message,
- e
- )
- }
- if (response.status() == 401) {
- throw issueLevelError("Can not get details for workflow scheme by id `"+ workflowSchemeId +"`. " +
- "\nKnown projects / workflow schemes: `"+ workflowSchemeMapping +"`" +
- "\nPlease contact Exalate Support."+
- "\nAlso failed to get it through REST API: "+
- "\nRequest: GET /rest/api/2/workflowscheme/" + workflowSchemeId +
- "\nAuth: " + username +
- "\nResponse: " + response.body()
- )
- }
- if (response.status() != 200) {
- throw issueLevelError(
- "Failed to get workflow scheme by id `" + workflowSchemeId + "` (status " + response.status() + "), please contact Exalate Support: " +
- "\nRequest: GET /rest/api/2/workflowscheme/" + workflowSchemeId +
- "\nAuth: " + username + ":" + password +
- "\nResponse: " + response.body()
- )
- }
- jsonStrInternal = response.body()
- }
- def s = new groovy.json.JsonSlurper()
- def json
- try {
- json = s.parseText(jsonStrInternal)
- } catch (Exception e) {
- throw issueLevelError2("Can not parse workflow scheme json, please contact Exalate Support: " + jsonStrInternal, e)
- }
- if (!(json instanceof Map<String, Object>)) {
- throw issueLevelError("Workflow scheme json has unrecognized structure, please contact Exalate Support: " + jsonStrInternal)
- }
- if (!((json as Map<String, Object>).issueTypeMappings instanceof Map<String, Object>)) {
- throw issueLevelError("Workflow scheme issueTypeMappings json has unrecognized structure, please contact Exalate Support: " + jsonStrInternal)
- }
- if (!((json as Map<String, Object>).defaultWorkflow instanceof String)) {
- throw issueLevelError("Workflow scheme defaultWorkflow json has unrecognized structure, please contact Exalate Support: " + jsonStrInternal)
- }
- json
- }
- def getWorkflowName = { Long workflowSchemeId, String issueTypeId ->
- def workflowSchemeJson = getWorkflowScheme(workflowSchemeId)
- def wfName = workflowSchemeJson.issueTypeMappings[issueTypeId] ?: workflowSchemeJson.defaultWorkflow
- wfName as String
- }
- def getWorkflowDetailsForProject = { String workflowName, String projectKey ->
- def projectToWorkflowDetailsMapping = workflowDetailsMapping[workflowName]
- def jsonStr
- if (projectToWorkflowDetailsMapping != null) {
- jsonStr = projectToWorkflowDetailsMapping
- } else {
- def response
- try {
- response = await(httpClient
- .ws()
- .url(jiraCloudUrl + "/rest/projectconfig/1/workflow")
- .withQueryString(seq(
- pair("workflowName", workflowName),
- pair("projectKey", projectKey)
- ))
- .withAuth(username, password, play.api.libs.ws.WSAuthScheme.BASIC$.MODULE$)
- .withMethod("GET")
- .execute()
- )
- } catch (Exception e) {
- throw issueLevelError2(
- "Unable to get workflow details for name `" + workflowName + "` for project `" + projectKey + "` on behalf of user `" + username + "`, please contact Exalate Support: " +
- "\nRequest: GET /rest/projectconfig/1/workflow?workflowName=" + workflowName + "&projectKey=" + projectKey +
- "\nAuth: " + username + ":" + password +
- "\nError: " + e.message,
- e
- )
- }
- if (response.status() == 401) {
- throw issueLevelError("Can not get project to workflow details mapping for workflow name`"+ workflowName +"`. " +
- "\nKnown workflow name to project to details mapping: `"+ workflowDetailsMapping +"`" +
- "\nPlease contact Exalate Support."+
- "\nAlso failed to get it through REST API: "+
- "\nRequest: GET /rest/projectconfig/1/workflow?workflowName=" + workflowName + "&projectKey=" + projectKey +
- "\nAuth: " + username +
- "\nResponse: " + response.body()
- )
- }
- if (response.status() != 200) {
- throw issueLevelError(
- "Failed to get workflow details for name `" + workflowName + "` for project `" + projectKey + "` on behalf of user `" + username + "` (status " + response.status() + "), please contact Exalate Support: " +
- "\nRequest: GET /rest/projectconfig/1/workflow?workflowName=" + workflowName + "&projectKey=" + projectKey +
- "\nAuth: " + username + ":" + password +
- "\nResponse: " + response.body()
- )
- }
- jsonStr = response.body()
- }
- def s = new groovy.json.JsonSlurper()
- def json
- try {
- json = s.parseText(jsonStr)
- } catch (Exception e) {
- throw issueLevelError2("Can not parse workflow details json, please contact Exalate Support: " + jsonStr, e)
- }
- if (!(json instanceof Map<String, Object>)) {
- throw issueLevelError("Workflow details json has unrecognized structure, please contact Exalate Support: " + jsonStr)
- }
- if (!((json as Map<String, Object>).sources instanceof List<Map<String, Object>>)) {
- throw issueLevelError("Workflow details sources json has unrecognized structure, please contact Exalate Support: " + jsonStr)
- }
- json as Map<String, Object>
- }
- def getTransitionsForIssue = { String issueKeyStr ->
- def response
- try {
- response = await(await(httpClient.authenticate(
- none(),
- httpClient
- .ws()
- .url(jiraCloudUrl + "/rest/api/2/issue/" + issueKeyStr + "/transitions")
- .withMethod("GET"),
- gs
- )).get())
- } catch (Exception e) {
- throw issueLevelError2("Unable to get transitions for issue, please contact Exalate Support: " +
- "\nRequest: GET /rest/api/2/issue/" + issueKeyStr + "/transitions" +
- "\nError: " + e.message, e)
- }
- if (response.status() != 200) {
- throw issueLevelError("Can not get transitions for issue (status " + response.status() + "), please contact Exalate Support: " +
- "\nRequest: GET /rest/api/2/issue/" + issueKeyStr + "/transitions" +
- "\nResponse: " + response.body())
- }
- def resultStr = response.body()
- def s = new groovy.json.JsonSlurper()
- def json
- try {
- json = s.parseText(resultStr)
- } catch (Exception e) {
- throw issueLevelError2("Can not parse the get transitions for issue json, please contact Exalate Support: " + resultStr, e)
- }
- if (!(json instanceof Map)) {
- throw issueLevelError("Get transitions for issue json has unrecognized structure, please contact Exalate Support: " + resultStr)
- }
- if (!(json.transitions instanceof List)) {
- throw issueLevelError("Get transitions for issue .transitions json has unrecognized structure, please contact Exalate Support: " + resultStr)
- }
- json as Map<String, Object>
- }
- def getGlobalTransitionsViaIssue = { String issueKeyStr ->
- def tsResponse = getTransitionsForIssue(issueKeyStr)
- def ts = tsResponse.transitions as List<Map<String, Object>>;
- ts
- .findAll { t -> t.isGlobal }
- .collect { t ->
- [
- "id" : t.id as String,
- "name" : t.name as String,
- "to" : [
- "id" : t.to.id as String,
- "name": t.to.name as String
- ],
- "global": true
- ]
- }
- }
- def getWorkflow = { String workflowName, String projectKey, String issueKeyStr ->
- def json = getWorkflowDetailsForProject(workflowName, projectKey);
- def sources = (json as Map<String, Object>).sources as List<Map<String, Object>>;
- def transitions = sources
- .collect { src ->
- if (!(src.fromStatus instanceof Map<String, Object>)) {
- throw issueLevelError("Workflow details sources `" + src + "` from status `" + src.fromStatus + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- def fromStatus = src.fromStatus as Map<String, Object>
- if (!(fromStatus.id instanceof String)) {
- throw issueLevelError("Workflow details sources `" + src + "` from status `" + fromStatus + "` id `" + fromStatus.id + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- if (!(fromStatus.name instanceof String)) {
- throw issueLevelError("Workflow details sources `" + src + "` from status `" + fromStatus + "` name `" + fromStatus.name + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- if (!(src.targets instanceof List)) {
- throw issueLevelError("Workflow details sources `" + src + "` targets `" + src.targets + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- def targets = src.targets as List<Map<String, Object>>;
- def ts = targets.collect { target ->
- if (!(target instanceof Map<String, Object>)) {
- throw issueLevelError("Workflow details sources `" + src + "` target `" + target + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- if (!(target.toStatus instanceof Map<String, Object>)) {
- throw issueLevelError("Workflow details sources `" + src + "` target `" + target + "` toStatus `" + target.toStatus + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- def toStatus = target.toStatus as Map<String, Object>;
- if (!(toStatus.id instanceof String)) {
- throw issueLevelError("Workflow details sources `" + src + "` target `" + target + "` toStatus `" + toStatus + "` id `" + toStatus.id + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- if (!(toStatus.name instanceof String)) {
- throw issueLevelError("Workflow details sources `" + src + "` target `" + target + "` toStatus `" + toStatus + "` name `" + toStatus.name + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- if (!(target.transitionName instanceof String)) {
- throw issueLevelError("Workflow details sources `" + src + "` target `" + target + "` transitionName `" + target.transitionName + "` json has unrecognized structure, please contact Exalate Support: " + response.body())
- }
- [
- "name" : target.transitionName,
- "from" : [
- "id" : fromStatus.id,
- "name": fromStatus.name,
- ],
- "to" : [
- "id" : toStatus.id,
- "name": toStatus.name,
- ],
- "global": false
- ]
- }
- ts
- }
- .flatten()
- def allTransitions = transitions + getGlobalTransitionsViaIssue(issueKeyStr)
- [
- "name" : workflowName,
- "transitions": allTransitions,
- "steps" : allTransitions.inject([]) { List<Map<String, Object>> result, t ->
- def stepsToAddToResult = t.global ? [t.to] : [t.from, t.to]
- stepsToAddToResult.inject(result) { r, s ->
- def curStep = r.find { step -> step.id == s.id }
- if (curStep != null) {
- // the step is already in the result steps list
- if (t.from.id == s.id && !curStep.transitions?.any { it.name == t.name }) {
- // if the transition is from this step
- curStep.transitions += t
- }
- } else {
- // the step is not in the result steps list
- r += [
- "id" : s.id,
- "name" : s.name,
- "transitions": t.from.id == s.id ? [t] : []
- ]
- }
- r
- }
- }
- ]
- }
- def transition = { com.exalate.basic.domain.BasicIssueKey zissueKey ->
- { Map<String, Object> t, String transitionExecUserKey, Map<String, Object> fields ->
- if (t.id == null) {
- def currentlyAvailableTransitions = getTransitionsForIssue(zissueKey.URN).transitions as List<Map<String, Object>>;
- def zTransition = currentlyAvailableTransitions.find { Map<String, Object> aTransition ->
- aTransition.name as String == t.name as String &&
- aTransition.to?.id as Long == t.to.id as Long
- }
- if (zTransition == null) {
- throw issueLevelError("Failing to transition because the transition found by algorithm `" + t.name + "` is no longer available for current step `" + t.from.name + "` (" + t.from.id + "). Please contact Exalate Support" +
- "\nAvailable transitions:" + currentlyAvailableTransitions)
- }
- t.id = zTransition.id
- }
- def json = [
- "transition": [
- "id": t.id
- ],
- ] as Map<String, Object>
- if (fields != null) {
- json.fields = fields
- }
- def jsonStr = groovy.json.JsonOutput.toJson(json)
- def response
- try {
- def writable = play.api.http.Writeable$.MODULE$.wString(play.api.mvc.Codec.utf_8())
- //noinspection GroovyAssignabilityCheck
- response = await(await(httpClient.authenticate(
- none(),
- httpClient
- .ws()
- .url(jiraCloudUrl + "/rest/api/2/issue/" + zissueKey.URN + "/transitions")
- .withHeaders(seq(pair("Content-Type", "application/json")))
- .withBody(jsonStr, writable)
- .withMethod("POST"),
- gs
- )).execute())
- } catch (Exception e) {
- throw issueLevelError2("Unable to transition issue `" + zissueKey.URN + "`, please contact Exalate Support: \n" +
- "POST " + jiraCloudUrl + "/rest/api/2/issue/" + zissueKey.URN + "\nBody: " + jsonStr + "\nError Message:" + e.message, e)
- }
- if (response.status() != 204) {
- throw issueLevelError("Can not transition issue `" + zissueKey.URN + "` (http status " + response.status() + "), please contact Exalate Support: \nPUT " + jiraCloudUrl + "/rest/api/2/issue/" + zissueKey.id + "\nBody: " + jsonStr + "\nResponse:" + response.body())
- }
- }
- }
- def getTransitions = { String statusName, Map<String, Object> wf ->
- def step = wf.steps.find { s -> s.name == statusName }
- if (step == null) {
- throw issueLevelError("Can not find step `" + statusName + "`. Available steps: `" + wf.steps.collect { s -> s.name + " (" + s.id + ")" } + "`. Create it or review the transitioning script.")
- }
- step.transitions
- }
- def getGlobalTransitions = { Map<String, Object> wf ->
- wf
- .transitions
- .findAll { t -> t.global }
- }
- def getAllTransitions = { String statusName, List<String> visitedStates, Map<String, Object> wf ->
- (getTransitions(statusName, wf) + getGlobalTransitions(wf))
- .findAll { t -> !visitedStates.any { it == t.to.name } }
- }
- def getTransitionPathInternal
- getTransitionPathInternal = { transitionWithParent ->
- if (!transitionWithParent) return null;
- if (transitionWithParent.parentTransition == null) {
- return [transitionWithParent.transition]
- }
- getTransitionPathInternal(transitionWithParent.parentTransition) + [transitionWithParent.transition]
- }
- def getPathsFromAtoBInternal = { String currentStatusName, String targetStatusName, Map<String, Object> wf ->
- if (currentStatusName == targetStatusName) {
- return null
- }
- def q = [] as Queue<Map<String, Object>>;
- def visitedStates = [] as List<String>;
- def allFirstTransitions = getAllTransitions(currentStatusName, visitedStates, wf) as List<Map<String, Object>>;
- for (aTransition in allFirstTransitions) {
- def nextStatus = aTransition.to.name
- def transitionWithParent = ["transition": aTransition, "parentTransition": null]
- if (nextStatus == targetStatusName) {
- return transitionWithParent
- }
- if (aTransition.from) {
- visitedStates.add(aTransition.from.name as String)
- }
- q.add(transitionWithParent)
- }
- //solution -> every state has a from transition property
- while (!q.isEmpty()) {
- def transitionWithParent = q.remove()
- def nextStatus = transitionWithParent.transition.to.name as String
- def childTransitions = getAllTransitions(nextStatus, visitedStates, wf) as List<Map<String, Object>>;
- for (childTransition in childTransitions) {
- def nextChildStatus = childTransition.to.name
- if (targetStatusName == nextChildStatus) {
- return ["transition": childTransition, "parentTransition": transitionWithParent]
- }
- if (childTransition.from) {
- visitedStates.add(childTransition.from.name as String)
- }
- q.add(["transition": childTransition, "parentTransition": transitionWithParent])
- }
- }
- }
- def getEditIssueMeta = { String issueKeyStr ->
- // GET /rest/api/2/issue/{issueIdOrKey}/editmeta
- def response
- try {
- //noinspection GrUnresolvedAccess
- response = await(await(httpClient.authenticate(
- none(),
- httpClient
- .ws()
- .url(jiraCloudUrl + "/rest/api/2/issue/" + issueKeyStr + "/editmeta")
- .withMethod("GET"),
- gs
- )).get())
- } catch (Exception e) {
- throw issueLevelError2("Unable to get edit meta for issue, please contact Exalate Support: " +
- "\nRequest: GET /rest/api/2/issue/" + issueKeyStr + "/editmeta" +
- "\nError: " + e.message, e)
- }
- if (response.status() != 200) {
- throw issueLevelError("Can not get edit meta for issue (status " + response.status() + "), please contact Exalate Support: " +
- "\nRequest: GET /rest/api/2/issue/" + issueKeyStr + "/editmeta" +
- "\nResponse: " + response.body())
- }
- def resultStr = response.body()
- def s = new groovy.json.JsonSlurper()
- def json
- try {
- json = s.parseText(resultStr)
- } catch (Exception e) {
- throw issueLevelError2("Can not parse the get edit meta for issue json, please contact Exalate Support: " + resultStr, e)
- }
- /*
- {"fields":{
- "summary":{"required":true,"schema":{"type":"string","system":"summary"},"name":"Summary","key":"summary","operations":["set"]},
- "issuetype":{"required":true,"schema":{"type":"issuetype","system":"issuetype"},"name":"Issue Type","key":"issuetype","operations":[],"allowedValues":[{"self":"https://tsleft.atlassian.net/rest/api/2/issuetype/10002","id":"10002","description":"A task that needs to be done.","iconUrl":"https://tsleft.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype","name":"Task","subtask":false,"avatarId":10318},{"self":"https://tsleft.atlassian.net/rest/api/2/issuetype/10001","id":"10001","description":"Created by Jira Agile - do not edit or delete. Issue type for a user story.","iconUrl":"https://tsleft.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10315&avatarType=issuetype","name":"Story","subtask":false,"avatarId":10315},{"self":"https://tsleft.atlassian.net/rest/api/2/issuetype/10004","id":"10004","description":"A problem which impairs or prevents the functions of the product.","iconUrl":"https://tsleft.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype","name":"Bug","subtask":false,"avatarId":10303},{"self":"https://tsleft.atlassian.net/rest/api/2/issuetype/10000","id":"10000","description":"Created by Jira Software - do not edit or delete. Issue type for a big user story that needs to be broken down.","iconUrl":"https://tsleft.atlassian.net/images/icons/issuetypes/epic.svg","name":"Epic","subtask":false}]},
- "components":{"required":false,"schema":{"type":"array","items":"component","system":"components"},"name":"Component/s","key":"components","operations":["add","set","remove"],"allowedValues":[]},
- "description":{"required":false,"schema":{"type":"string","system":"description"},"name":"Description","key":"description","operations":["set"]},
- "customfield_10064":{"required":false,"schema":{"type":"string","custom":"com.atlassian.jira.plugin.system.customfieldtypes:textfield","customId":10064},"name":"Remote Issue ID","key":"customfield_10064","operations":["set"]},
- "customfield_10010":{"required":false,"schema":{"type":"array","items":"string","custom":"com.pyxis.greenhopper.jira:gh-sprint","customId":10010},"name":"Sprint","key":"customfield_10010","operations":["set"]},
- "fixVersions":{"required":false,"schema":{"type":"array","items":"version","system":"fixVersions"},"name":"Fix Version/s","key":"fixVersions","operations":["set","add","remove"],"allowedValues":[]},
- "priority":{"required":false,"schema":{"type":"priority","system":"priority"},"name":"Priority","key":"priority","operations":["set"],"allowedValues":[{"self":"https://tsleft.atlassian.net/rest/api/2/priority/1","iconUrl":"https://tsleft.atlassian.net/images/icons/priorities/highest.svg","name":"Highest","id":"1"},{"self":"https://tsleft.atlassian.net/rest/api/2/priority/2","iconUrl":"https://tsleft.atlassian.net/images/icons/priorities/high.svg","name":"High","id":"2"},{"self":"https://tsleft.atlassian.net/rest/api/2/priority/3","iconUrl":"https://tsleft.atlassian.net/images/icons/priorities/medium.svg","name":"Medium","id":"3"},{"self":"https://tsleft.atlassian.net/rest/api/2/priority/4","iconUrl":"https://tsleft.atlassian.net/images/icons/priorities/low.svg","name":"Low","id":"4"},{"self":"https://tsleft.atlassian.net/rest/api/2/priority/5","iconUrl":"https://tsleft.atlassian.net/images/icons/priorities/lowest.svg","name":"Lowest","id":"5"}]},
- "labels":{"required":false,"schema":{"type":"array","items":"string","system":"labels"},"name":"Labels","key":"labels","autoCompleteUrl":"https://tsleft.atlassian.net/rest/api/1.0/labels/suggest?query=","operations":["add","set","remove"]},
- "customfield_10008":{"required":false,"schema":{"type":"any","custom":"com.pyxis.greenhopper.jira:gh-epic-link","customId":10008},"name":"Epic Link","key":"customfield_10008","operations":["set"]},
- "attachment":{"required":false,"schema":{"type":"array","items":"attachment","system":"attachment"},"name":"Attachment","key":"attachment","operations":[]},
- "issuelinks":{"required":false,"schema":{"type":"array","items":"issuelinks","system":"issuelinks"},"name":"Linked Issues","key":"issuelinks","autoCompleteUrl":"https://tsleft.atlassian.net/rest/api/2/issue/picker?currentProjectId=&showSubTaskParent=true&showSubTasks=true¤tIssueKey=LPROJ-9&query=","operations":["add"]},
- "comment":{"required":false,"schema":{"type":"comments-page","system":"comment"},"name":"Comment","key":"comment","operations":["add","edit","remove"]},
- "assignee":{"required":false,"schema":{"type":"user","system":"assignee"},"name":"Assignee","key":"assignee","autoCompleteUrl":"https://tsleft.atlassian.net/rest/api/latest/user/assignable/search?issueKey=LPROJ-9&username=","operations":["set"]},
- "resolution":{"required":false,"schema":{"type":"resolution","system":"resolution"},"name":"Resolution","key":"resolution","operations":["set"],"allowedValues":[{"self":"https://tsleft.atlassian.net/rest/api/2/resolution/10000","name":"Done","id":"10000"},{"self":"https://tsleft.atlassian.net/rest/api/2/resolution/10001","name":"Won't Do","id":"10001"},{"self":"https://tsleft.atlassian.net/rest/api/2/resolution/10002","name":"Duplicate","id":"10002"},{"self":"https://tsleft.atlassian.net/rest/api/2/resolution/10003","name":"Cannot Reproduce","id":"10003"}]}
- }}
- */
- if (!(json instanceof Map)) {
- throw issueLevelError("Get edit meta for issue json has unrecognized structure, please contact Exalate Support: " + resultStr)
- }
- if (!(json.fields instanceof Map)) {
- throw issueLevelError("Get edit meta for issue `.fields` json has unrecognized structure, please contact Exalate Support: " + resultStr)
- }
- json as Map<String, Object>
- }
- // applying the resolution
- if (
- issue.resolution?.name != replica.resolution?.name &&
- (getEditIssueMeta(jIssue.key).fields as Map<String, Object>)
- .values()
- .any { meta ->
- meta.key == "resolution" &&
- meta.schema?.system == "resolution"
- }
- ) {
- if (replica.resolution?.name == null) {
- issue.resolution = null
- } else {
- def resolution = nodeHelper.getResolution(replica.resolution?.name)
- if (resolution == null) {
- throw issueLevelError("Could not find resolution `" + replica.resolution?.name + "`. Please create one and resolve the error or contact Exalate Supprt.")
- }
- issue.resolution = resolution
- }
- }
- def desiredStatusName = (workflowMapping[replica.status.name] ?: replica.status.name)
- if (jIssue.status.name != desiredStatusName) {
- def wfSchemeId = getWorkflowSchemeIdForProject(issue.project.key)
- def wfName = getWorkflowName(wfSchemeId, issue.type.id)
- def wf = getWorkflow(wfName, issue.project.key, jIssue.key)
- def shortestPath = getTransitionPathInternal(getPathsFromAtoBInternal(jIssue.status.name, desiredStatusName, wf))
- if (shortestPath == null) {
- throw issueLevelError(
- "Can not find path from `" + jIssue.status.name + "` to `" + desiredStatusName + "` " +
- "in workflow `" + wf.name + ". " +
- "Please review whether `" + wf.name + "` is the correct workflow for the issue `" + jIssue.key + "`."
- )
- }
- shortestPath.each { t ->
- transition(localExIssueKey)(t as Map<String, Object>, null, null as Map<String, Object>)
- }
- }
- } catch (com.exalate.api.exception.IssueTrackerException ite) {
- throw ite
- } catch (Exception e) {
- throw new com.exalate.api.exception.IssueTrackerException(e)
- }
- })()
- // END: STATUS SYNC
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement