プロジェクトの親子関係を保持するための実装
ここからは、サンプルとして筆者が作成した、Redmineの情報を集約し表示するツールのコードを見ながら、プロジェクトの親子関係を保持する方法を紹介します。
なお、この記事ページに表示するのは、説明に必要なサンプルコードの一部です。サンプルコード全体は、GitHubから入手できます。
ProjectNodeクラス
まず、プロジェクト自身の情報とサブプロジェクトとの関係を保持する必要があります。
プロジェクトの情報を保持するクラス ProjectNode の定義は次のようになります。
class ProjectNode(object):
def __init__(self, project):
self.project = project
self.children = []
self.has_parent = hasattr(project, u'parent')
def add_child(self, child):
self.children.append(child)
def trace(self, family=None):
family = [] if family is None else family
family.append(self.project.name)
self.execute(family)
if len(self.children) > 0:
for child in self.children:
child.trace(family)
family.pop()
def execute(self, family=None):
print("%s has %d children" % ('/'.join(family), len(self.children)))
__init__ メソッドでは、projectインスタンスと、サブプロジェクト (子) を保持するための配列をそれぞれ初期化しています。また、自分に親がいるかどうかをチェックし、フラグhas_parentに保持します。
trace メソッドは、親プロジェクトから自プロジェクトに至るプロジェクト名のリストを格納した family 配列に再帰的にアクセスしています。
execute メソッドは、親を含めたプロジェクト名とサブプロジェクト数を表示するアクションを実施します。
プロジェクトツリーの構築
Redmine上では、プロジェクトの親子関係を後から変更することもできるため、親子の順序は保証されません。そこで、いったん全プロジェクトを読み出した後に、親子関係を整理することにしました。次のコードでは、プロジェクトIDをキーにしてプロジェクト情報の実体を保持する ProjectNode オブジェクトを紐付けるマップ project_map を構築しています。
redmine = Redmine('http://redmine-server/', key='API_KEY')
projects = redmine.project.all()
project_map = {}
for project in projects:
project_map[project.id] = ProjectNode(project)
これで、すべてのプロジェクト情報をプログラム上に持つことができるので、次のようにして、このマップを元に親子関係を整理し、登録していきます。
project_root = []
for node in project_map.values():
if node.has_parent:
parent_id = node.project.parent.id
project_map[parent_id].add_child(node)
else:
project_root.append(node)
以上で project_root リストに、一番上位の階層のプロジェクトが登録された状態になりました。
プロジェクトツリーの探索
プロジェクトツリーをたどる(探索する)コードは次のとおりです。
for node in project_root:
node.trace()
なお、Remine上のプロジェクト構造は次の図のようになっています。
そのためコードの出力は、次のようにとなります。
ビジネス has 2 children ビジネス/執筆 has 1 children ビジネス/執筆/CodeZine 執筆 has 0 children ビジネス/開発案件 has 0 children ホーム has 0 children サークル活動 has 0 children
説明は割愛しますが、チケットについても同様の方法で親子関係を表せます。
出力フォーマッタ
さて、Redmine 上のデータを取得して、親子関係を整理し、簡単な出力ができるところまでたどり着きました。次は、取得したプロジェクトやチケットの情報を表示する処理です。
Webブラウザで見られるよう、データをHTMLとして整形できると良さそうです。Pythonには様々なテンプレートエンジンがありますが、GitHubで配布しているサンプルコートでは、Jinja2を選択しました。興味のある方はダウンロードしてソースコードをご覧ください。
まとめ
ここまで、実装例も混ぜながら、RedmineのREST APIの使い方、取得したデータ構造、親子関係の扱い方を紹介してきました。
紹介したのは基本的な部分(REST APIによる情報の取得)だけでしたが、これをベースにアイデア次第でいろいろ機能を追加・拡張できると思います。例えば、次のようなものを検知して出力に反映することができます。
- 期日が近づいている、もしくは過ぎてしまったチケット
- 担当者が指定されていないチケット
- 更新が滞っているチケット
また、今回は、プロジェクト単位でチケットを整理しましたが、担当者ごとのチケットを出力することも可能です。皆さんもいろいろ考えて実装してみてください。
次回もテーマはREST APIで情報を登録する技術です。例として、運用管理ツール「Zabbix」からのアラートをもとにRedmineのチケットを起票する方法を紹介する予定です。お楽しみに。
