Jira で指定した課題を一気にクローズする方法

# 沢山の課題を手作業で閉じるのは大変
多数の課題をひとつひとつ手作業で閉じる作業には色々と辛いものがありますよね。

# 検索クエリからやるのであればバルク変更を使う

## バルク変更の使い方
下図のように検索した上で右上の … から「なんちゃら個の課題をバルク変更」を叩けば、検索で見つけたチケットの状態を一度に変えられます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633175/49cdb2d7-d2ee-5c85-5e84-ae9bcdb1db7a.png)
バルク変更をクリックした後は適当にぽちぽちしているだけで課題を全部更新できます。便利。
なお、一部の課題だけを選択して更新することも可能です。すごく便利。

## だがそれは Not for me
便利ですね、"Not for me" って言葉。
私の所属しているチームでは、特定の条件にかけた Jira の課題を Excel 形式で出力して、
Google Spread Sheets に転記して複数人で囲んでわちゃわちゃレビューしています。
その中で「この課題の対応・説明は不十分だ、クローズできないよ」という場面にはしばしばあたります。

クローズできないものがあった場合、レビュー後にバルク変更からクローズできない課題を探して対象から外すという作業が発生します。
しかし、これは私のようなおっちょこちょいには難しいです……探すの大変ですしね。
実際、間違ってクローズしてしまったこともあります。関係各位、ごめんなさい。

# 課題のID一覧を渡してそれらを一気にクローズする
Jiraなら課題を外からAPIを叩いて更新できます。
今この記事を書いている時点でのバージョンは8.5.15ですから、
[JIRA Server platform REST API reference JIRA 8.5.15](https://docs.atlassian.com/software/jira/docs/api/REST/8.5.15/)に目を通してみます。

## Edit Issue じゃなくて Do Transition
今やりたいのは「課題（Issue）のステータスを変えてクローズにする」ですから[Edit issue](https://docs.atlassian.com/software/jira/docs/api/REST/8.5.15/#api/2/issue-editIssue)でやれそうですが、これだと駄目です。
課題の現在の状態を管理するのは課題が持つ Transition という値なのですが、Edit Issueからはこれは変更できませんでした。

課題の現在の状態を更新するにはEdit Issueではなく[Do Transition](https://docs.atlassian.com/software/jira/docs/api/REST/8.5.15/#api/2/issue-doTransition)を使います。

## Step 1：Transition の ID を把握する
[Do Transition](https://docs.atlassian.com/software/jira/docs/api/REST/8.5.15/#api/2/issue-doTransition)の使い方を確認するとtransitionのIDの情報がないと手も足も出ないことがわかります。
つまり、クローズにあたるtransitionのIDを把握しなければならないのです。
しかし、transitionのIDなんてわかりません。これをまずは調べましょう。

幸いにして各課題が次に持てるtransitionの値は簡単に取得できます。

クローズされうる課題のURLを確認しましょう。
例えばそれが `https://chrysanthemum94.atlassian.net/browse/IS-2929` であると仮定します。
この課題が取りうるtransitionの情報は `https://chrysanthemum94.atlassian.net/rest/api/2/issue/IS-2929/transitions?expand=transitions.fields` にアクセスすることでわかります。

### 取得できる情報のサンプル
大分実際のものから編集しているが、以下のような情報が取得できます。
この場合、"クローズ"というtransitionのIDは`91`である、とわかります。

```json
{
  "expand": "transitions",
  "transitions": [
    {
      "id": "14",
      "name": "さしもどし",
      "to": {
        "self": "https://chrysanthemum94.atlassian.net/rest/api/2/status/6",
        "description": "なんかだめなので書き直してきて",
        "iconUrl": "https://chrysanthemum94.atlassian.net/images/icons/statuses/working.png",
        "name": "destructed",
        "id": "6",
        "後は略": true
    },
    {
      "id": "91",
      "name": "クローズ",
      "to": {
        "self": "https://chrysanthemum94.atlassian.net/rest/api/2/status/10030",
        "description": "ばっちぐーなのでタスク完了",
        "iconUrl": "https://chrysanthemum94.atlassian.net/images/icons/statuses/closed.png",
        "name": "クローズ",
        "id": "10030",
        "後は略": true
      }
    }
  ]
}
```

## Step 2：一気に閉じるよ
JiraはjQueryを使っているようなのでjQueryを使ってさらっとAPIを叩くのが楽です。
無論、jQueryを使う必要はまったくないのでお好きな方法で叩けばいいと思いますし、Token等を添えて外から叩いても構わないです。
ともあれ、jQueryでサラッとやるのであれば課題の画面を開いて F12 キーを叩いて開発者コンソールを呼び出します。
そして、コンソールに以下の文字列を打ち込んで実行すれば OK です。

```javascript
const doTransitionForIssues = (transitionId, issueIds) => {
  issueIds.forEach((issueId) => {
    // ドメイン名は実際のものに変えないとだめですよ
    jQuery.ajax({
      type: 'POST',
      url: `https://chrysanthemum94.atlassian.net/rest/api/2/issue/${issueId}/transitions`,
      contentType: 'application/json',
      data: `{"transition": {"id": "${transitionId}"}}`,
      dataType: 'json'
    });
  });
};

// 第一引数（transitionId）も実際の値にしてください
// 第ニ引数も実際に閉じたい課題のIDにしてください
doTransitionForIssues(91,
`IS-2929
IS-3939
IS-5151`.trim().split('\n'));
// 第ニ引数は Google Spread Sheets から ID をコピペしてくることを想定しているので
// 改行区切りの文字列を split するように書いています。実際には以下をするのが意図です。
// doTransitionForIssues(91, ['IS-2929', 'IS-3939', 'IS-5151']);
```

forEach がぐるんぐるん回って課題を全て閉じていきます。お疲れさまでした。