Backlog API を使って Backlog に課題を大量登録してみた

2022.03.29

こんにちは、リサリサです。

Backlog に大量の課題を一括登録したので記事にしてみます。

やりたいこと

Backlog に大量の課題を一括追加したい。100個くらい……

issue.csv に追加したい内容の一覧を作れば、それを一括で課題登録できるようにしてみました。

Backlog は登録の際、選択肢の項目を全て ID で登録しないといけません。優先度なら、でななく2など。それを考えながら一覧を作成すると面倒なので、から2への変換をした上で、一括登録できるようにしました。issue.csv には、と記載して大丈夫です。(そのために事前に get_id_list.py で id_list.json を作成しています。こちらは初回と、カテゴリ追加などあった際に実行して頂ければ OK です。)

やってみた

実行環境

Python 3.8.0

準備① APIキーの発行

Backlogの認証は、APIキーを利用する場合とOAuthを利用する場合の2通りがあります。今回はAPIキーを用いてAPIの操作を行います。

APIキーは、[個人設定]->[API]から、「登録」ボタンを押すことで発行できます。発行後は、下の画面にAPIキーが表示されるので、これを用いてAPIの操作を行います。

hog

準備② スペースキー、プロジェクトIDを取得

スペースキー

バックログのサブドメインに使われているものです。

xxx.backlog.jp

プロジェクトID

プロジェクトキーかと思いきや、ちょっと違って自動採番の数字になります。

「プロジェクト設定」のURLを見ると記載があります。

https://xxx.backlog.jp/EditProject.action?project.id=1234567890

準備③ IDリストを取得

Backlog API から課題を登録する場合、画面から登録できる「優先度」、「カテゴリー」、「担当者」など、全て ID で登録する必要があります。

それぞれ頑張ると「プロジェクト設定」などからも取得できるのですが、なかなか大変だったので、API でまとめて取得してみました。以下のpythonを実行すると、同ディレクトリに id_list.jsonが作成され、そこに各ID情報が出力されます。

APIキー、スペースキー、プロジェクトIDには、準備①②で取得したキーを記載してください。

get_id_list.py

import requests
import csv
import json

API_KEY = 'APIキー'
SPACE_KEY = 'スペースキー'
PROJECT_ID = 'プロジェクトID'

BASE_URL = f"https://{SPACE_KEY}.backlog.jp/api/v2"

def get_id(url):
    params = {
        'apiKey': API_KEY,
    }

    r = requests.get(url, params=params)
    r.raise_for_status()
    return json.loads(r.text)

# csvのタイトル
output = {}

print('・issueTypeId(課題の種別のID)用')
#  種別一覧の取得
#  https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-type-list/#
#  /api/v2/projects/:projectIdOrKey/issueTypes 
datas = get_id(f"{BASE_URL}/projects/{PROJECT_ID}/issueTypes")
output['issueTypeId'] = {}
for data in datas:
    output['issueTypeId'][data['name']] = data['id']
    print(f"{data['id']}:{data['name']}")

print('・assigneeId(課題の担当者のID)用')
#  プロジェクトユーザー一覧の取得
#  https://developer.nulab.com/ja/docs/backlog/api/2/get-project-user-list/#
#  /api/v2/projects/:projectIdOrKey/users
datas = get_id(f"{BASE_URL}/projects/{PROJECT_ID}/users")
output['assigneeId'] = {}
for data in datas:
    output['assigneeId'][data['name']] = data['id']
    print(f"{data['id']}:{data['name']}")

print('・categoryId(課題のカテゴリーのID)用')
#  カテゴリー一覧の取得
#  https://developer.nulab.com/ja/docs/backlog/api/2/get-category-list/#
#  /api/v2/projects/:projectIdOrKey/categories 
datas = get_id(f"{BASE_URL}/projects/{PROJECT_ID}/categories")
output['categoryId[]'] = {}
for data in datas:
    output['categoryId[]'][data['name']] = data['id']
    print(f"{data['id']}:{data['name']}")

print('・versionId(課題の発生バージョンのID)、milestoneId(課題のマイルストーンのID)用')
#  バージョン(マイルストーン)一覧の取得
#  https://developer.nulab.com/ja/docs/backlog/api/2/get-version-milestone-list/#
#  /api/v2/projects/:projectIdOrKey/versions
datas = get_id(f"{BASE_URL}/projects/{PROJECT_ID}/versions")
output['versionId'] = {}
output['milestoneId'] = {}
for data in datas:
    output['versionId'][data['name']] = data['id']
    output['milestoneId'][data['name']] = data['id']
    print(f"{data['id']}:{data['name']}")

print('・priorityId(課題の優先度のID)用')
#  優先度一覧の取得
#  https://developer.nulab.com/ja/docs/backlog/api/2/get-priority-list/#
#  /api/v2/priorities 
datas = get_id(f"{BASE_URL}/priorities")
output['priorityId'] = {}
for data in datas:
    output['priorityId'][data['name']] = data['id']
    print(f"{data['id']}:{data['name']}")

# customField_{id}(カスタム属性の値)用
#  カスタム属性一覧の取得
#  https://developer.nulab.com/ja/docs/backlog/api/2/get-custom-field-list/#
#  /api/v2/projects/:projectIdOrKey/customFields 
datas = get_id(f"{BASE_URL}/projects/{PROJECT_ID}/customFields")
for data in datas:
    print(f"・customField_{data['id']}({data['name']})用")
    output[f"customField_{data['id']}"] = {}
    for item in data['items']:
        output[f"customField_{data['id']}"][item['name']] = item['id']
        print(f"{item['id']}:{item['name']}")

with open('id_list.json', 'w') as f:
    f.write(json.dumps(output, indent=4, ensure_ascii=False))

id_list.json は以下のようになっています。

id_list.json

{
    "issueTypeId": {
        "Parent Issue": 1074831859,
        "event": 1074838719,
        "Task": 1074821804,
        "Bug": 1074821803,
        "Request": 1074821805,
        "Other": 1074821806
    },
    "assigneeId": {
        "田中": 1074281901,
        "木村": 1074201141,
        "佐藤": 1074121619
    },
    "categoryId[]": {
        "外部設計": 1074361053,
        "内部設計": 1074365061,
        "プロジェクト管理": 1074371210
    },
    "versionId": {
        "第1フェーズ": 1074285907,
        "第2フェーズ": 1074285906
    },
    "milestoneId": {
        "第1フェーズ": 1074285907,
        "第2フェーズ": 1074285906
    },
    "priorityId": {
        "高": 2,
        "中": 3,
        "低": 4
    },
    "customField_1073851824": {
        "xxxxx": 1,
        "yyyyy": 1
    }
}

追加したい課題一覧を作成

Excelやスプレッドシートで一覧を作り、csvに変換します。

項目は以下のパラメーターから必要なものを使ってください。issueTypeId(課題種別),priorityId(優先度),summary(件名)以外の項目であれば、空欄があっても大丈夫ですし、列自体なくても大丈夫です。日付は「yyyy-mm-dd」で記載ください。※複数指定は対応してません。

課題の追加

項目名も選択肢(特に担当者名など)も、機械的にIDに変換して、APIを叩いているだけですので、一言一句間違わずに入力してください…

スプレッドシートの場合は、ファイル⇒ダウンロード⇒csvからcsvに変換できます。

issue.csv

issueTypeId,parentIssueId,priorityId,summary,description,assigneeId,startDate,dueDate,categoryId[],customField_1073853234
Parent Issue,PROJECT-1,中,xxxxの設計,xxxxの設計についての詳細,田中,2022-03-29,2022-04-09,内部設計,xxxxxx
Parent Issue,PROJECT-1,中,yyyyの設計,yyyyの設計についての詳細,佐藤,,,内部設計,xxxxxx

id_list.json と同じディレクトリに issue.csv という名前で保存してください。

登録する

id_list.json 、issue.csv と同じディレクトリで実行すると、Backlog に課題登録できます。※バリデーションチェック等していないので、項目名に間違いがあったりするとエラーで落ちます。

APIキー、スペースキー、プロジェクトIDには、準備①②で取得したキーを記載してください。

create_issue.py

import requests
import csv
import json

API_KEY = 'APIキー'
SPACE_KEY = 'スペースキー'
PROJECT_ID = 'プロジェクトID'
BASE_URL = f"https://{SPACE_KEY}.backlog.jp/api/v2"

def add_issue(payload):
    url = f"{BASE_URL}/issues"
    payload['projectId'] = PROJECT_ID

    params = {
        'apiKey': API_KEY,
    }

    r = requests.post(url, params=params, data=payload)
    r.raise_for_status()
    return r

def get_issue_id(issue_key):
    url = f"{BASE_URL}/issues/{issue_key}"

    params = {
        'apiKey': API_KEY,
    }

    r = requests.get(url, params=params, data=payload)
    r.raise_for_status()
    print('get_issue')
    return json.loads(r.text)["id"]

# idリストを取得
with open('id_list.json') as f:
    id_list = json.load(f)

# 親課題登録用のidリスト
issue_id_list = {}

with open('issue.csv') as f:
    reader = csv.DictReader(f)
    for r in reader:
        payload = {}
        print(r)
        # 選択肢⇒idへ変換
        for k, v in r.items():
            # 親課題だけidを取得するためにget issueが必要
            if k == 'parentIssueId':
                if not v in issue_id_list:
                    issue_id_list[v] = get_issue_id(v)
                payload[k] = issue_id_list[v]
            else:
                if v:
                    if k in id_list:
                        payload[k] = id_list[k][v]
                    else:
                        payload[k] = v
        print(payload)

        # 課題登録
        add_issue(payload)

画面から追加したのと同じように、課題の追加ができました。

最後に

大量の課題追加が必要な誰かのお役に立てれば幸いです。

参考

Backlog APIを使ってBacklogに課題を登録する | DevelopersIO