Skip to main content
Example scripts
arrow icon
To homepage
Bitbucket
Data centre icon
Data Center

Assign component to Jira issue

Features
Post hooks
Tags
Created 1 year ago, Updated 6 month(s) ago
App in script
ScriptRunner For Bitbucket
ScriptRunner For Bitbucket
by Adaptavist
Compatibility
compatibility bullet
Bitbucket (6.0 - 7.17)
compatibility bullet
ScriptRunner For Bitbucket (7.10.0)
Language |
groovy
import com.atlassian.applinks.api.ApplicationLinkRequestFactory
import com.atlassian.applinks.api.ApplicationLinkResponseHandler
import com.atlassian.applinks.api.ApplicationLinkService
import com.atlassian.applinks.api.application.jira.JiraApplicationType
import com.atlassian.bitbucket.hook.ScmHookDetails
import com.atlassian.integration.jira.JiraKeyScanner
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.sal.api.net.Response
import com.atlassian.sal.api.net.ResponseException
import com.onresolve.scriptrunner.runner.ScriptRunnerImpl
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import groovyx.net.http.ContentType

import static com.atlassian.sal.api.net.Request.MethodType.GET
import static com.atlassian.sal.api.net.Request.MethodType.PUT

def appLinkService = ComponentLocator.getComponent(ApplicationLinkService)
def appLink = appLinkService.getPrimaryApplicationLink(JiraApplicationType)
def appLinkRequestFactory = appLink.createAuthenticatedRequestFactory()
def handler = createAppLinkResponseHandler()

def jiraKeyScanner = ScriptRunnerImpl.scriptRunner.getBean(JiraKeyScanner)
def issueKeys = jiraKeyScanner.findAll(collectCommitMessages().join(' '))
if (!issueKeys.isEmpty()) {
    def issueKey = issueKeys.first()
    def projectKey = issueKey.split('-').first()

    try {
        def missingComponents = findMissingComponentsInJiraTicket(projectKey, issueKey, appLinkRequestFactory, handler)
        if (missingComponents) {
            addComponentsToJiraTicket(missingComponents, issueKey, appLinkRequestFactory, handler)
            writeMessage("Following components ${missingComponents.join(',')} has been assigned to Jira issue ${issueKey}")
        } else {
            writeMessage("Jira issue ${issueKey} has all required components")
        }
    } catch (IllegalStateException e) {
        writeErrorMessage(e.getMessage())
    }
} else {
    writeErrorMessage('Commit message should contain Jira ticket key')
}

void addComponentsToJiraTicket(
    List<Map> missingComponents, String issueKey,
    ApplicationLinkRequestFactory appLinkRequestFactory, ApplicationLinkResponseHandler<Map> handler
) {
    // https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/#editing-an-issue-examples
    missingComponents.each { missingComponent ->
        def requestBody = [
            "update": [
                "components": [
                    ["add": ["name": missingComponent['name']]]
                ] as List,
            ]
        ]

        def requestBodyAsString = JsonOutput.toJson(requestBody)
        appLinkRequestFactory.createRequest(PUT, "rest/api/2/issue/${issueKey}")
            .setRequestBody(requestBodyAsString, ContentType.JSON.toString())
            .execute(handler).output
    }
}

private List<Map> findMissingComponentsInJiraTicket(
    String projectKey, String issueKey, ApplicationLinkRequestFactory appLinkRequestFactory,
    ApplicationLinkResponseHandler<Map> handler
) {
    def components = appLinkRequestFactory.createRequest(GET, "rest/api/2/project/${projectKey}/components").execute(handler).output
    def issue = appLinkRequestFactory.createRequest(GET, "rest/api/2/issue/${issueKey}").execute(handler).output
    def commitMessages = collectCommitMessages()
    def componentsIdAssignedToIssue = issue['fields']['components'].collect { it['id'] } as Set<String>
    components.findAll { (it['id'] as String) !in componentsIdAssignedToIssue }
        .findAll { c -> commitMessages.any { it.contains(c['name'] as String) } } as List<Map>
}

private Collection<String> collectCommitMessages() {
    refChanges.collect {
        it.getCommits(repository)*.message
    }.flatten() as List<String>
}

private ApplicationLinkResponseHandler<Map> createAppLinkResponseHandler() {
    new ApplicationLinkResponseHandler<Map>() {
        @Override
        Map credentialsRequired(Response response) throws ResponseException {
            null
        }

        @Override
        Map handle(Response response) throws ResponseException {
            def bodyAsString = response.responseBodyAsString
            if (!response.successful) {
                throw new IllegalStateException("${response.statusCode}:${response.statusText}:${bodyAsString}")
            }
            def isJSON = response.getHeader('Content-Type').contains('application/json')
            ["output": isJSON ? (response.responseBodyAsString ? new JsonSlurper().parseText(bodyAsString) : []) : bodyAsString]
        }
    }
}

String wrapMessage(String message) {
    "\n" +
        "=====================================================================\n" +
        message +
        "=====================================================================\n" +
        "\n"
}

void writeMessage(GString message) {
    def scmHookDetails = hookRequest.scmHookDetails as Optional<ScmHookDetails>
    if (scmHookDetails.isPresent()) {
        scmHookDetails.get().out().println(wrapMessage(message))
    }
}

void writeErrorMessage(GString message) {
    def scmHookDetails = hookRequest.scmHookDetails as Optional<ScmHookDetails>
    if (scmHookDetails.isPresent()) {
        scmHookDetails.get().out().println(wrapMessage(message))
    }
}
Having an issue with this script?
Report it here