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

  • 46
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

Python Redmine

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

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

・RedmineのAPI機能を100%サポート
 (プロジェクトすら作成できる)
・Python2.6~3.4対応
・ORMスタイルのPythonic APIを提供している。
 (Django ORMに影響を受けています)
・Apache2.0ライセンス

以下にその詳細が記述してある。
http://python-redmine.readthedocs.org/

インストール方法

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に自動コンバート
・作業時間を集計して、別のシステムに通知する。

以上