Python
Redmine

Python Redmineを使用してRedmineを操作する

More than 1 year has passed since last update.


Python Redmine

Python RedmineはRedmineと通信を行うPythonのライブラリである。

次のような特徴を有している。

・RedmineのAPI機能を100%サポート

 (プロジェクトすら作成できる)

・Python2.6~3.4対応

・ORMスタイルのPythonic APIを提供している。

 (Django ORMに影響を受けています)

・Apache2.0ライセンス

以下にその詳細が記述してある。

https://python-redmine.com/


インストール方法

pipまたはeasy_installを用いてインストールが可能である。

$ pip install python-redmine

または

$ easy_install python-redmine

Redmine側の設定として、「管理」→「設定」画面における認証タブで「REST APIによるWebサービスを有効にする」にチェックをいれておくこと。

redminepython.png


サンプル

以下にサンプルを記述する。

このサンプルはDebian上のPython2.7で確認している。


認証方法

ユーザ名とパスワードを指定してredmineに接続できる。

from redmine import Redmine

redmine = Redmine('http://localhost/redmine', username='admin', password='admin')

あるいは次のように、APIキーを用いて接続することも可能だ。

from redmine import Redmine

redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')


チケットの操作

チケットの操作については下記を参照

http://python-redmine.readthedocs.org/resources/issue.html


チケットの作成

redmine.issue.new()でチケットのオブジェクトを生成して、そこにプロパティを設定後、保存することでチケットの作成ができる。

# -*- coding: utf-8 -*-

import datetime
from redmine import Redmine
redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')
issue = redmine.issue.new()
issue.project_id = 'test'
issue.subject = 'サブジェクト'
issue.tracker_id = 1 #トラッカー
issue.description = 'チケットの内容をしめす。\n改行もできる。'
issue.status_id = 1 #ステータス
issue.priority_id = 1 #優先度
issue.assigned_to_id = 1 #担当者のID
issue.watcher_user_ids = [1,3] # ウォッチするユーザのID
issue.parent_issue_id = 12 # 親チケットのID
issue.start_date = datetime.date(2014, 1, 1) #開始日
issue.due_date = datetime.date(2014, 2, 1) #期日
issue.estimated_hours = 4 # 予想工数
issue.done_ratio = 40
issue.custom_fields = [{'id': 1, 'value': 'foo'}]
issue.uploads = [{'path': '/share/test.txt'}]
issue.save()


単一チケットの取得

redmine.issue.get()でチケットIDを指定する。もし存在しない場合、

redmine.exceptions.ResourceNotFoundError例外が発生する。

# -*- coding: utf-8 -*-

import datetime
from redmine import Redmine
from redmine.exceptions import ResourceNotFoundError

redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')
try:
issue = redmine.issue.get(50)
print (dir(issue))
print ('id:%d' % issue.id)
print ('project:%s' % issue.project.name)
print ('project_id:%d' % issue.project.id)
print ('subject:%s' % issue.subject)
print ('tracker:%s' % issue.tracker.name)
print ('tracker_id:%d' % issue.tracker.id)
print ('description:%s' % issue.description)
print ('status:%s' % issue.status.name)
print ('status:%d' % issue.status.id)
print ('author:%s' % issue.author.name)
print ('author_id:%d' % issue.author.id)
if hasattr(issue, 'assigned'):
print ('assigned:%s' % issue.assigned_to.name)
print ('assigned_id:%d' % issue.assigned_to.id)
print ('watcher--------')
for u in issue.watchers:
print (' %d:%s' % (u.id, u.name))
print ('作成日:%s' % issue.created_on)
print ('更新日:%s' % issue.updated_on)
if hasattr(issue, 'start_date'):
print ('start_date:%s' % issue.start_date)
if hasattr(issue, 'due_date'):
print ('issue_date:%s' % issue.due_date)
if hasattr(issue, 'issue.estimated_hours'):
print ('estimated_hours:%d' % issue.estimated_hours)
print ('作業時間:%d' % issue.spent_hours)
print ('作業時間の記録----------')
for t in issue.time_entries:
print(' ID:%d' % t.id)
print(' 活動:%s' % t.activity)
print(' コメント:%s' % str(t.comments))
print(' 作成日:%s' % t.created_on)
print(' 時間:%s' %t.hours)
print(' チケットID:%s' % t.issue)
print(' プロジェクトID:%s' % t.project)
print(' 日付:%s' % t.spent_on)
print(' 更新日:%s' % t.updated_on)
print(' user:%d %s' % (t.user.id,t.user.name))
print ('done_ratio:%d' % issue.done_ratio)
print ('priority:%s' % issue.priority.name)
print ('priority_id:%d' % issue.priority.id)
print ('custom_fields----')
for c in issue.custom_fields:
print (' %d:%s = %s' % (c.id, c.name, c.value))
print ('attachements---')
for f in issue.attachments:
print (' id:%d' % (f.id))
print (' author:%s' % (f.author))
print (' content_url:%s' % (f.content_url))
print (' created_on:%s' % (f.created_on))
print (' description:%s' % (f.description))
print (' filename:%s' % (f.filename))
print (' filesize:%d' % (f.filesize))
print (' ---------------')
print ('changeset---')
for c in issue.changesets:
#コミットログがディクショナリ型として格納
print (' %s' % c)
if hasattr(issue, 'parent'):
print ('parent:%s' % issue.parent)
print ('children----------')
for c in issue.children:
print (' %s:%s' % (c.id, c.subject))
print ('relation----------')
for r in issue.relations:
print (' %d:%d->%d(%s)' % (r.id, r.issue_id, r.issue_to_id, r.relation_type))
except (ResourceNotFoundError):
print ('Not found')

入力が省略されている項目は、プロパティ自体が存在していない。

そのため、hasattrで存在チェックをしなければならない。

watchersや担当者、作成者のユーザ情報には必要最小限のものしか入っていない。login名などを取得したい場合は次のようにユーザIDからユーザの詳細を取得すること。

user = redmine.user.get(u.id)


すべてのチケットを取得

redmine.issue.all()で取得することができる。

省略可能なパラメータとして、以下のものがある。

sort (string) :並び順

limit (integer) :取得数の上限

offset (integer):取得開始位置

# -*- coding: utf-8 -*-

import datetime
from redmine import Redmine

redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')
issues = redmine.issue.all(sort='category:desc')
for issue in issues:
print ('%d:%s' % (issue.id, issue.subject))


特定の条件のチケットの取得

redmine.issue.filterを用いて特定の条件のチケットを抽出できる。

以下は、担当者が自分のチケットを抽出している。

# -*- coding: utf-8 -*-

import datetime
from redmine import Redmine

redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')
issues = redmine.issue.filter(assigned_to_id='me')
for issue in issues:
print ('%d:%s' % (issue.id, issue.subject))

query_id を用いれば、登録済みのクエリーで検索も行える。


チケットの更新

redmine.issue.getで取得したチケットは変更して保存することが可能である。

以下の例はチケットのステータスを変更している例である。

# -*- coding: utf-8 -*-

import datetime
from redmine import Redmine

redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')
issue = redmine.issue.get(51)
issue.status_id = 2
issue.save()


作業時間の操作

作業時間の操作については下記を参照

http://python-redmine.readthedocs.org/resources/time_entry.html


作業時間の取得

以下は作業時間を列挙する例である。

# -*- coding: utf-8 -*-

import datetime
from redmine import Redmine

redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')
time_entries = redmine.time_entry.all()
for t in time_entries:
print(' ID:%d' % t.id)
print(' 活動:%s' % t.activity)
print(' コメント:%s' % str(t.comments))
print(' 作成日:%s' % t.created_on)
print(' 時間:%s' %t.hours)
print(' チケットID:%s' % t.issue)
print(' プロジェクトID:%s' % t.project)
print(' 日付:%s' % t.spent_on)
print(' 更新日:%s' % t.updated_on)
print(' user:%d %s' % (t.user.id,t.user.name))


作業時間の記録

作業時間を記録する例を以下に示す。

# -*- coding: utf-8 -*-

import datetime
from redmine import Redmine

redmine = Redmine('http://localhost/redmine', key='e4a413a3b7a3c238102b7393c035bbc5f5eb6409')
time_entry = redmine.time_entry.new()
time_entry.issue_id = 51
time_entry.spent_on = datetime.date(2014, 1, 14)
time_entry.hours = 3
time_entry.activity_id = 4
time_entry.comments = 'hello'
time_entry.save()


まとめ

今回は提供されているAPIの一部しか検証していないが、Web画面で行える操作は網羅できていることが確認できた。

Python Redmineを用いることでPythonでRedmineを自由に操作できることが期待できる。

そのことは、以下のことを実現できると期待できる。

・自動テスト失敗時にプログラムからチケットを発行する。

・Excelに記述された設計書をWikiに自動コンバート

・作業時間を集計して、別のシステムに通知する。

以上