RedmineのRest APIをcurlとjqで使ってみたサンプル

RedmineのRestAPIを使うことがあった・・・が、どんどん忘れていくのでメモしていくことにしました。

# プロジェクト情報を取得する

```zsh
# アクセス権のあるプロジェクトの一覧を取得する
$ curl -sS -X GET -H 'X-Redmine-API-Key:{APIキー}' {RedmineのURL}/projects.json | jq .
{
  "projects": [
    {
      "id": 1,
      "name": "プロジェクト名",
      "identifier": "sample",
      "description": "",
      "status": 1,
      "is_public": false,
      "created_on": "2019-07-22T00:48:43Z",
      "updated_on": "2019-07-22T00:48:43Z"
    },
    # ...省略...

# プロジェクトに設定された「トラッカー」と「カテゴリ」を取得して、jsonから抜き出して整形する
$ curl -sS -X GET -H 'X-Redmine-API-Key:{APIキー}' {RedmineのURL}/projects.json?include=trackers,issue_categories | jq '.projects[] | {name: .name, trackers: .trackers, issue_categories: .issue_categories}'
{
  "name": "プロジェクト名",
  "trackers": [
    {
      "id": 2,
      "name": "タスク"
    },
    # ...省略...
  ],
  "issue_categories": [
    {
      "id": 3,
      "name": "テストカテゴリ"
    }
  ]
}
```

:::note info
includeオプションをつけるとプロジェクトの設定項目も取得できます。
:::
> include: fetch associated data (optional). Possible values: trackers, issue_categories, enabled_modules (since 2.6.0). Values should be separated by a comma ",".
> [Rest Projects - Redmine](https://www.redmine.org/projects/redmine/wiki/Rest_Projects)

|includeで指定できる値|取得できるプロジェクトの設定|参考リンク|
|:--|:--|:--|
|trackers|トラッカー|[トラッカー &mdash; Redmine用語解説](https://redmine.jp/glossary/t/tracker/)|
|issue_categories|チケットのカテゴリ|[カテゴリ &mdash; Redmine用語解説](https://redmine.jp/glossary/c/category/)|
|enabled_modules|プロジェクトで使用するモジュール|[プロジェクトの設定 - Redmineガイド](http://guide.redmine.jp/RedmineProjectSettings/#Core-modules)|

## プロジェクト一覧をCSV出力したい

<details><summary>プロジェクト一覧をCSV出力するシェルのサンプル</summary><div>

```zsh
#!/bin/bash

# RestAPIのプロジェクト一覧を取得するURL(条件付き)
BASE_URL='{RedmineのURL}/projects.json'
# APIキー
API_KEY='{APIキー}'
# 出力するCSVファイルのファイル名
CSV_NAME=Projects.csv

# 1. プロジェクト一覧を取得する
total=`curl -sS -X GET -H "X-Redmine-API-Key:$API_KEY" $BASE_URL | jq .total_count`
# 2. 文字から数値へ変換する
total=`expr $total`

if [ $total -gt 0 ]; then
    echo 'id,name,identifier' > $CSV_NAME
    # 3. APIを呼び出す回数を算出する : 1ページ(回)につき100件(limit=100)で取得する
    count=$((total / 100))
    for ((i=0; i <= $count; i++)); do
        # 4. URLにlimitを設定する
        Url="$BASE_URL?limit=100&offset="
        # 5. offsetを設定する
        Url+=$(( i * 100 ))
        # 6. APIを呼び出してjqコマンドでカンマ区切りにしてファイルへ出力する
        curl -sS -X GET -H "X-Redmine-API-Key:$API_KEY" "$Url" | jq -r '.projects[] | .result = (.id|tostring) + "," + .name + "," + .identifier | .result' >> $CSV_NAME
    done
fi
```

```text:出力されるProjects.csv
id,name,identifier
1,プロジェクト名称1,project_1
6,プロジェクト名称2,project_2
....
```
</div></details>

CSVの文字コードは、UTF-8なのでExcelで開きたいときは、「UTF-8」を指定してCSVを取り込むとすると文字化けしない。
参考 : [CSVを文字コード指定して読み込む - Qiita](https://qiita.com/ponsuke0531/items/f0f73d345041d4d3bd99#csv%E3%82%92%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%A6%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80)

# チケット情報を取得する
:::note warn
status_idオプションを指定しないと未完了のチケットしか取得できません。
:::

> Returns a paginated list of issues. By default, it returns open issues only.
> [Rest Issues - Redmine](https://www.redmine.org/projects/redmine/wiki/Rest_Issues)

```zsh
# 未完了のチケットを取得したい
$ curl -X GET -H 'X-Redmine-API-Key:{APIキー}' {RedmineのURL}/issues.json | jq .

# ステータスに関わらずチケットを取得したい
$ curl -X GET -H 'X-Redmine-API-Key:{APIキー}' {RedmineのURL}/issues.json?status_id=* | jq
```


status_idオプションで「*」を指定することができるのですが、zshで[zsh: parse error near `&'
](https://qiita.com/ponsuke0531/items/6faad9bde45fdfa68ea0)となってしまうことがあります。そんなときは、URLを「'」で囲うといいです。


```zsh
# 取得した「id」「プロジェクト名」「チケットの題名」をカンマ区切りで並べる
$ curl -X GET -H 'X-Redmine-API-Key:{APIキー}' '{RedmineのURL}/issues.json?limit=100&sort=asc&status_id=*' | jq -r '.issues[] | .result = (.id|tostring) + "," + .project.name + "," + .subject | .result'
297,プロジェクトA,チケットのタイトル1
472,プロジェクトA,チケットのタイトル2
...
```

:::note info
limitパラメータで指定できる件数は、初期値が25件で最大100件です。
検索条件によってたくさんチケットを取得できそうな場合は、limitパラメータを設定しないと25件しか取得できません。
:::

> **Collection resources and pagination**
> The response to a GET request on a collection resources (eg. /issues.xml, /users.xml) generally won't return all the objects available in your database. ...省略...
> limit: the number of items to be present in the response (default is 25, maximum is 100)
> [Rest api - Redmine](https://www.redmine.org/projects/redmine/wiki/Rest_api)

```zsh
# チケットの取得件数を見たい
$ curl -X GET -H 'X-Redmine-API-Key:{APIキー}' {RedmineのURL}/issues.json | jq '[.issues[]] | length'

# ステータスに関わらず取得できたチケット数を見たい
$ curl -X GET -H 'X-Redmine-API-Key:{APIキー}' '{RedmineのURL}/issues.json?limit=100&sort=asc&status_id=*' | jq '[.issues[]] | length'
100

# 指定の条件に合う取得可能な件数を見たい
$ curl -sS -X GET -H 'X-Redmine-API-Key:{APIキー}' '{RedmineのURL}/issues.json?status_id=*' | jq .total_count
744
```

:::note info
条件に一致するチケット数が多いと１回のリクエストで全てのチケットは取得できません。
ただ、条件に一致するチケット数はtotal_countでわかります。
:::

> Responses to GET requests on collection resources provide information about the total object count available in Redmine and the offset/limit used for the response.
> [Rest api - Redmine](https://www.redmine.org/projects/redmine/wiki/Rest_api)

## チケットをCSV出力したい

<details><summary>複数のプロジェクトの課題一覧をCSV出力するシェルのサンプル</summary><div>

- 確認環境
    - macOS BigSur バージョン11.3.1
    - jq-1.6
    - bash-3.2

```bash
#!/bin/bash

# RestAPIのチケット一覧を取得するURL
BASE_URL='{RedmineのURL}/issues.json'
# APIキー
API_KEY='{APIキー}'
# 出力するCSVファイルのファイル名
CSV_NAME=Issues.csv
# 対象にしたいプロジェクトIDの配列
PROJECT_IDS=(10 3 4)

echo 'project_id,project_name,issue_id,subject' > $CSV_NAME

# 1プロジェクトずつ処理していく
for project_id in "${PROJECT_IDS[@]}"; do
    # 1. 各プロジェクト用のURLを作る
    project_url="$BASE_URL?status_id=*&subproject_id=!*&project_id=$project_id"
    # 2. プロジェクト毎の課題数を取得する
    total=`curl -sS -X GET -H "X-Redmine-API-Key:$API_KEY" $project_url | jq .total_count`
    # 3. 文字から数値へ変換する
    total=`expr $total`

    # 4. 100件ずつCSVに出力する
    if [ $total -gt 0 ]; then
        # 5. APIを呼び出す回数を算出する : 1ページ(回)につき100件(limit=100)で取得する
        count=$((total / 100))
        for ((i=0; i <= $count; i++)); do
            # 6. URLにlimitを設定する
            Url="$project_url&sort=id:asc&limit=100&offset="
            # 7. offsetを設定する
            Url+=$(( i * 100 ))
            # 8. APIを呼び出してjqコマンドでカンマ区切りにしてファイルへ出力する
            curl -sS -X GET -H "X-Redmine-API-Key:$API_KEY" "$Url" | jq -r '.issues[] | .result = (.project.id|tostring) + "," + .project.name + "," + (.id|tostring) + "," + .subject | .result' >> $CSV_NAME
        done
    fi
done
```

```text:出力されるIssues.csv
project_id,project_name,issue_id,subject
10,プロジェクト名称10,443,チケットの題名
3,プロジェクト名称3,751,チケットの題名
3,プロジェクト名称3,752,チケットの題名
4,プロジェクト名称4,465,チケットの題名
....
```
</div></details>