【Jiraお勧めアドオン】 ScriptRunner の使い方( Script Listeners & REST Endpoint 編)


はじめに

個人的に熱いScriptRunnerの使い方をご紹介します。
「こんな使い方もできるよ!」って言う紹介記事みたいなもんです。

この記事で取り上げるのは Hipchat Datacenter 3.x.x との連携です。
標準の連携機能ではできない、細かい制御がしたくて作りました。

個人的に意識しているポイントは、以下2点です。
1. ScriptListnerは簡単な処理!
2. REST Endpointでやや面倒な処理!

バージョン

ScriptRunner 5.0.14
Hipchat Datacenter 3.x.x

ScriptListeners

Endpointで処理するための情報を幾つか付与した上で、AsyncHTTPBuilderを使って非同期通信します。
あまりゴテゴテ処理は書かないようにしてます。

途中、postHeadersに入れているBasic認証については、Jira BASIC認証を参照ください。
※コード例は、「fred:fred」をbase64でエンコードした文字列になります。
※base64のエンコードは「base64 エンコード」でググるとWEBサイトいっぱいでてくるので、そこでやりましょう。

import groovyx.net.http.AsyncHTTPBuilder
import groovy.json.JsonBuilder
import static groovyx.net.http.ContentType.*

String baseurl = "https://ホスト名/jira/rest/scriptrunner/latest/custom/notificationToHipchat";
String queryParams = "eventName=Assign";
String url = baseurl + "?" + queryParams;
def http = new AsyncHTTPBuilder(poolSize: 5, uri: url)
def postBody = event.getIssue().getId().toString();
def postHeaders= [Authorization: 'Basic ZnJlZDpmcmVk']; //Jira Basic Authentication

http.post( body: postBody, headers : postHeaders, requestContentType : JSON , contentType : JSON) 

REST Endpoint

以下のことやってます。
1. データを受け取る
2. メッセージ生成
3. hipchatに送信
実際に運用しているソースでは、条件に応じてpostするroomを分けているため、hipchatにpostするところを関数化してます。

//for endpoint
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

//for RestAPI
import groovyx.net.http.RESTClient
import groovyx.net.http.HttpResponseException
import static groovyx.net.http.ContentType.URLENC

//for json
import groovy.json.JsonOutput
import groovy.json.JsonBuilder
import java.util.HashMap

//for process
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventTypeManager
import com.atlassian.jira.event.type.EventType
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager

//url&token
String baseurl = "https://ホスト名/"


@BaseScript CustomEndpointDelegate delegate


//define a method
def post(RESTClient https, String path, String token, messagejson, Issue issue) {
    try {
        def resp = https.post(
            path: path,
            query:['auth_token': token],
            requestContentType: URLENC,
            headers: ['Content-Type': 'application/json'],
            body: JsonOutput.toJson(messagejson),
        )
    } catch(HttpResponseException e) {
        def r = e.response
        log.error(issue.key.toString());
        log.error(issue.summary.toString());
        log.error("Success: $r.success");
        log.error("Status:  $r.status");
        log.error("Reason:  $r.statusLine.reasonPhrase");
        log.error("Content: \n${JsonOutput.prettyPrint(JsonOutput.toJson(r.data))}");
    }
}

//main process
notificationToHipchat(httpMethod: "POST", groups: ["jira-software-users"]) { MultivaluedMap queryParams, String body ->
    //get request
    String id = body;
    IssueManager issueManager = ComponentAccessor.getIssueManager();
    Issue issue = issueManager.getIssueObject((Long)id.toInteger());
    String eventName = queryParams.getFirst("eventName") ?: "";

    log.info(eventName);

    //message generate
    String messageValue = "";
    String colorValue = "red";
    String notifyValue = "false";
    def messagejson = [:];

    messageValue = "【" + eventName + "】"
        //generic event
        if (eventName=="Transition") {
            messageValue = messageValue + " to " + issue.status.name;
            colorValue = "yellow";
        }
    messageValue = messageValue + "\r\nsummary: " + issue.summary
    messageValue = messageValue + "\r\ntype: " + issue.getIssueType().getName();
    messageValue = messageValue + "\r\nlink: https://ホスト名/jira/browse/" + issue.key
    messageValue = messageValue + "\r\nassignee: @" + issue.assignee?.displayName?.replaceAll(" ","");
    messagejson = [
        message: messageValue,
        color: colorValue,
        notify: notifyValue,
        message_format: 'text'
    ]

    //post
    String path = "v2/room/20/notification"; //test room
    String token = "hipchatトークン"; //test room
    def https = new RESTClient(baseurl);

    post(https, path, token, messagejson, issue);

    return Response.ok(new JsonBuilder(body).toString()).build();
}

メンションしたい場合、JIRAのフルネームがhipchatのメンション対象になります。
ただし、hipchat側で空白をカットされているので、そこを補正してあげる必要があります。
上記コードの中にも記載されていますが、抜き出すと以下コードです。

messageValue = messageValue + "\r\nassignee: @" + issue.assignee?.displayName?.replaceAll(" ","");

最後に

個人的にこの使い方便利だなーと感じつつも、まとまって記載された記事を見かけなかったので、作った感じです。

ScriptRunner:本当に便利なので、ぜひご活用下さい。

以上です。