Backlog の予定時間を集計する
nulab Backlog で 課題の予定時間を合計するためのスクリプトを作りました。 担当者別、ステータス別、カテゴリ別に集計します。 少しコードを変えれば、実績時間なども集計できます。参考になれば幸いです。
やりたかったこと
目的
- Backlog のひとつのプロジェクト全体で、予定工数を人別に、ステータス別、カテゴリ別に集計したかった。
条件
- LLで素早く作りたい。 結構いろんな開発を同時進行で行なっているためIDEをもうひとつ立ち上げる気はない。
実現方法
- jupyter notebook を使う。(コードは jupyter notebook でなくても動くし、結果も取得可能)
- 課題のデータはとりあえず全部取得して、その後の処理は Python の pandas を使う。 Pivot Table つくれるのできっと楽。
環境
- Python 3.9.0
- pandas 1.1.5
- numpy 1.19.4
コード
改善点はいろいろあるけども、とりあえず動くものを作った。
まずはデータを取得する。
import json
import pandas as pd
import urllib
class BacklogUrl:
base = 'https://xxxxxx.backlog.xxx'
key = '__API_KEY___'
def __init__(self, path, param = {}):
self.path = path
self.param = param
def to_str(self):
text = BacklogUrl.base + self.path
i = 0
for k, v in self.param.items():
if i == 0:
text += '?'
else:
text += '&'
text += f'{k}={v}'
i += 1
if len(self.param) == 0:
text += '?'
else:
text += '&'
text += f'apiKey={BacklogUrl.key}'
i += 1
return text
def get(self):
try:
url = self.to_str()
print(url)
result = urllib.request.urlopen(url).read()
print(result)
return json.loads(result)
except e:
print(e.message)
raise e
class Backlog:
def get_project(key):
return Project(BacklogUrl(f'/api/v2/projects/{key}').get()['id'])
class Project:
def __init__(self, id):
self.id = id
def get_issues(self):
count = self.get_issue_count()
max_itr = (count + 99) // 100
list = []
for i in range(max_itr):
list += BacklogUrl(
f'/api/v2/issues',
{
'projectId[]': self.id, 'sort': 'created', 'count': 100, 'offset': i * 100
}
).get()
return list
def get_issue_count(self):
return BacklogUrl(f'/api/v2/issues/count', {'projectId[]': self.id}).get()['count']
# プロジェクトのキーを引数にする
project = Backlog.get_project('ABCDE')
issues = project.get_issues()
Backlog サーバへはもうアクセスしない。
DataFrame を作る。
df = pd.DataFrame(issues)
DataFrame から集計対象データを抽出する。 子課題のみ対象とする。 (これは運用によっていろいろ条件があると思う。)
childIssues = df[~df['parentIssueId'].isnull()]
カテゴリ名、担当者名、ステータス名が dict になっており 集計できないので、 集計のキーにするカラムを新しく作る。 名前は、 category1, assignee1, status1 とした。
childIssues.loc[:, 'category1'] = childIssues.category.map(lambda x: x[0]['name'])
childIssues.loc[:, 'assignee1'] = childIssues.assignee.map(lambda x: x['name'] if x is not None else None)
childIssues.loc[:, 'status1'] = childIssues.status.map(lambda x: x['name'])
Pivot Table を作成する。
import numpy as np
table = pd.pivot_table(
childIssues,
index='category1', columns=['assignee1', 'status1'], values=['estimatedHours'],
aggfunc=np.sum, margins=True, fill_value=0
)
jupyter notebook であれば、 table
を実行すればテーブルが表示される。
jupyter notebook を使っていない場合は to_csv, to_clipboard などを使うとCSVに変換したり、コピーしたりできる。
table
estimatedHours は時間単位なのでこれを日付単位にしたければ 8 で割って表示する。(1日8時間稼働できると仮定した場合。)
table / 8.0