JiraとConfluenceを連携させて使っていると、Jiraでかゆいところに手が届かないのをREST APIで何とかしたいと思うことがある。個人的に作業するだけならcurl
でも良いが、慣れていない人も含め、複数の人が同じことをしやすいようにしたいので、UIが欲しい。
定型的なチケット作成や、テンプレートチケットのクローン程度であれば簡単にできるので、Confluenceページ上のHTMLマクロ内にスクリプトを少し書くだけで実現できる。
HTML部分
AUIでは色々なコンポーネントが用意されているが、まずはフォームがあればそれらしい画面が作れそうだった。AUIのフォームの説明ページでは基本的なフォームの形が紹介されている。
例えば、ボタンを押したら何かするようにしたければ、以下のようにする。
<form ... class="aui">
<div class="field-group">...</div>
<div class="field-group">...</div>
<div class="buttons-container">
<div class="buttons" onclick="onClick()">...</div>
</div>
</form>
<script type="text/javascript">
(function () {
const API_BASE="<JIRAサーバ>/rest/api/2"
async function onClick() {
...
}
})();
</script>
テキストボックスでEnterキーを押したり、Submitボタンをクリックしたりすると、意図しないSubmitアクションが実行されてしまった。ボタンは
type="submit"
の代わりにtype="button"
にすることでSubmitアクションを止められたが、テキストボックスは一工夫いるらしい。「Enterキーを無効にする方法」がうまく使えるか試してみる。
Jiraチケットを取得する
チケットを取得するときは、/rest/api/2/issue/<KEY or ID>
をGET
する。HTTPリクエストを出すにはAJS.$.ajax()
(jQueryの機能)を使う。
async function getIssue( key ) {
var issue;
await AJS.$.ajax( {
url: API_BASE + '/issue/' + key,
type: 'get',
successs: function( data ) {
issue = data;
}
} );
return issue;
}
JiraとConfluenceを連動して使っているのであれば多分Originが同じになるのでCORSを気にすることはないが、同一PCで動かしていてポートが違うような場合、Jiraサーバ側に特定のOriginを許可する設定が必要になる。
Jiraチケットを作成する
チケットを作成するときは、{ fields: { field: value } }
という形のJSONを/rest/api/2/issue
にPOST
する。以下では、戻り値(issue)のfields
だけ取り出して返している。
async function postIssue( fields ) {
var resultFields;
await AJS.$.ajax( {
url: API_BASE + '/issue',
type: 'post',
data: JSON.stringify( { 'fields': fields } ),
headers: {
'Content-Type': 'application/json'
},
success: function( data ) {
resultFields = data.fields;
}
} );
return resultFields;
}
Jiraチケットを複製する
チケットを作る際のルール・テンプレートが柔らかく、暫定的にチーム内で統一して作りたい場合があると思う。そんなとき、ベースとなるチケットを複製するという手段がある。
以下は、srcKey
(string)で指定したチケットをparentKey
(string)以下にコピーする関数。コピーする対象のフィールドはfields
(string[])で指定する。
function extractFields( src, fieldNames ) {
let fields = {};
for( let fieldName of fieldNames ) {
let tmp = src[ fieldName ];
// null, undefined を受け付けない場合があるので除外しておく
if( tmp ) {
fields[ fieldName ] = tmp;
}
}
}
async function cloneIssue( srcKey, parentKey, fieldNames ) {
const src = await getIssue( srcKey );
const parent = await getIssue( parentKey );
if( !src || !parent ) {
throw new Error( 'Invalid Key.' ); // 適当
}
const projectKey = parent.fields.project.key;
let fields = extractFields( src.fields, fieldNames );
fields[ 'project' ] = { key: projectKey };
fields[ 'parent' ] = { key: parentKey };
await postIssue( fields );
}
UIと繋ぐ
先ほどのcloneIssue
関数をUIと繋ぐ場合、ボタン操作などをトリガとして実行する関数(ここではonClick
)で、設定値を持つinput要素等からval()
関数で設定値を取得し、cloneIssue
関数をコールする。成功・失敗を通知する機能もあると良いかもしれないが、基本は以下のようなイメージ。
const API_BASE="<JIRAサーバ>/rest/api/2"
const src = AJS.$('#src'); // コピーしたいチケットのキーを入力するinput要素のID
const parent = AJS.$('#parent'); // コピー先の親チケットのキーを入力するinput要素のID
const FIELDNAMES = [
'custom_field_xxxxx',
'custom_field_yyyyy',
'custom_field_zzzzz',
'description',
'issuetype',
'summary'
]; // コピーしたいフィールド
// イベント処理の関数…UIのボタンから呼ぶようにする。
async function onClick() {
try {
const srcKey = src.val();
const parentKey = parent.val();
await cloneIssue( srcKey, parentKey, FIELDNAMES );
} catch( err ) {
console.log( err ); // 適当
}
}
参考情報
Confluence
ConfluenceのHTMLマクロでは、AUI(Atlassian User Interface)で提供されるUI部品やヘルパ関数AJS
を使うことができる。AJSにはjQuery
が含まれていて、AJS.$
で利用できる。また、ページのメタ情報をAJS.params
で取得することもできる。
AUIのコードサンプルには「Edit in codepen」や「Edit in jsfiddle」と書かれたリンクがあり、AJSも含めどんな結果になるかを確認しながらコードを書くことができるようになっている。
Jira
REST API資料
JiraのREST APIについては、サーバ版とCloud版で異なるらしい。どちらが使えるか調べて、リンク先からREST APIの資料を参照する。
400 Bad Requestが返ってくる
REST APIでチケットを作ろうとすると、fieldsメンバ内に必ず設定しなくてはならない項目が不足するか、設定してはいけない項目があることで、400応答が返ってくることがある。そんな時は応答に含まれるエラーメッセージ(error.responseText
)から、何がダメだったかが分かるようになっている。例えばissuetype
が無い、親チケットが無い、エピックにエピック名が無いなどがある。
401 Unauthorizedが返ってくる
ConfluenceとJiraでユーザの情報を共有して連携している場合(大抵はこれ)、ブラウザでJiraにログインすることで解消する。
415 Unsupported Media Typeが返ってくる
HTTPリクエスト時に、data
の中身をJSON.stringify
し忘れるか、Content-Type
ヘッダを忘れるかのどちらかで起きる。
カスタムフィールドと設定値を調べる
チケットのカスタムフィールドはcustom_field1234
のような名前なので、何を示すか分からない。また、priority
のような選択式のメンバについても、設定値がid:10500
のようになっていて、何を示すか分からない。これらは、以下APIで調べることができる。
- カスタムフィールド: /rest/api/2/customFields
- フィールドの選択肢: /rest/api/2/customFieldOption/{id}
フィールドの選択肢
customFieldOption
は、idが分かってからでないと呼び出せないので、用途としてはidに対応する文字列を取得する程度にしか使えない。