Redmine APIを利用して全チケットを一括で取得しCSV出力する

Redmineに登録されているチケットを全て取得し、CSV出力するスクリプトを作成しました。
手動で行おうとすると、Redmineのチケット一覧からCSVエクスポートボタンを押す作業が発生します。
スクリプト化しておけば、毎朝定期的に実行させておき、ファイルを開くだけで確認ができます。

また、応用すれば、ステータスの状況などを集計させておき、現在何%程度完了しているのか、メールで送信などとすることも可能だと思います。

まずは、「全チケットを一括で取得する」までを対象とします。

RedmineのAPIの仕様上、デフォルトで取得できる上限チケット数は「20」、上限を引き上げても「100」のため、
100件以上のチケットを一度に取得するには、少々面倒です。

参考：[Redmine wiki](http://www.redmine.org/projects/redmine/wiki/Rest_Issues)

作成したスクリプトの言語はPythonです。

# 環境
- Redmine 3.4.4.stable
- Python 3.6.5

# 事前準備
#### ①設定変更
Redmineにログインし、[管理][設定][API]より、以下の項目にチェックを入れてください。

- [x] RESTによるWebサービスを有効にする

<img width="1354" alt="スクリーンショット 2018-07-28 3.40.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/210323/e6b92428-7112-cdd6-1d3c-656219c0676a.png">

#### ②アクセスキーをメモ
[個人設定]より、画面右下のAPIアクセスキーを後ほどスクリプトに記述します。

<img width="1357" alt="スクリーンショット 2018-07-28 3.39.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/210323/9f2f71de-3a0e-090b-f6ee-f890c255cf61.png">

# 必要なライブラリ
ライブラリをimportします。必要に応じてpipでインストールしてください。

```python:解説
#!/usr/bin/env python

import requests
import json
import pandas as pd
```

# 変数
変数を定義します。
URLはRedmineが構築されたサーバに合わせて変更してください。

```python:解説
url = "http://localhost:10080/issues.json"

json_dict = {}
page = 0
offset = 0
page_size = 100 # limmitとあわせる
```

# 繰り返し条件
前述したように、100件以上のチケットがある場合は、繰り返し取得しに行きます。

```python:解説
　# 複数ページ分(100件以上のチケット)繰り返し
while page_size >= 100:
```

# パラメータ
パラメータを設定します。取得対象ステータスを指定しないと、「新規」ステータスのみが取得対象となります。
APIアクセスキーは、事前準備の画面に記載されたキーを入れてください。

```python:解説
    payload = {"limit" : "100", # ページの上限
               "offset" : offset, # 開始チケット
               "key" : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", # APIアクセスキー
               "status_id" : "*", # 取得対象ステータス
               "project_id" : "test-sub", # 取得対象プロジェクト
               }
```


# チケット取得
リクエストを投げます。json形式のレスポンスを変数に入れ、チケット数を更新しておきます。
100件に以下になれば終わらせるためです。

```python:解説
    r = requests.get(url, params=payload)
    json_dict[page] = r.json()
    page_size = len(json_dict[page]["issues"])
```








# リスト追加
2回目移行の繰り返しであれば、元のリストに追加します。
繰り返しはここまでです。100件分のチケットをスキップし、次の繰り返しに入ります。

```python:解説
    if page != 0:
        json_dict["issues"].extend(json_dict[page]["issues"])
    else:
        json_dict = json_dict[page]

    page = page + 1
    offset = offset + 100 # limmitとあわせる
```

# （2018/7/29：追記）カスタムフィールドの要素を追加
何も加工しないと、カスタム項目が辞書型で1項目にまとめられてしまうため、CSVエクスポートしたほうが綺麗に抽出できることになってしまいます。それを解消するため、中の要素を順番に取り出し、チケットの要素の後ろに追加するようにします。

```python:解説

    # チケットの数だけ繰り返す
    for i in range(len(json_dict[page]["issues"])):
        try:
            # カスタムフィールドの数だけ繰り返す
            for j in range(len(json_dict[page]["issues"][i]["custom_fields"])):
                custom_field_name = "カスタム" + str(j)
                custom_field_value = "カスタム" + str(j) + "バリュー"
                json_dict[page]["issues"][i][custom_field_name] = json_dict[page]["issues"][i]["custom_fields"][j]["name"]
                json_dict[page]["issues"][i][custom_field_value] = json_dict[page]["issues"][i]["custom_fields"][j]["value"]

        except KeyError:
            # カスタム項目がなかったら
            print("無いよ")
```


# CSV出力
あとは、最終的に出来上がったリストを、pandasで、たった2行で、いい感じにCSV出力します。

```python:解説
 # CSV出力
df = pd.io.json.json_normalize(data = json_dict["issues"])
df.to_csv(path_or_buf = "redmine.csv",index=None)
```

スクリプトは以上になります。
~~カスタム項目がある場合、辞書形式でネストされてしまっているため、もうひと工夫入りそうなのですが、スキルがなくて断念しました。もし、カスタム項目をいい感じに出力できる方法をご存知の方がいらっしゃいましたら、コメントいただけると幸いです。~~

Python Redmineを使えば、きっともう少し綺麗にかけるような気はしていますが、不勉強のため、見送ります。

Python Redmineを使いたい方は、こちらが参考になりました。↓
[Python Redmineを使用してRedmineを操作する](https://qiita.com/mima_ita/items/1a939db423d8ee295c85)