ScrumもどきPlugin開発記その4
いやぁ。半年ぶりに開発再開です。オハズカシイったらありゃしない。
今後は弊社の有能中国人プログラマに手伝って貰うので、ガリガリ作っていくよ・・・多分^_^;;
前回迄でTracのPluginとして登録・動作させることは出来たので、今後は追加機能単位でピックアップしていくことにする。
概要
Pluginで管理するデータを保管する為に、Trac DBに独自テーブルを追加する。この辺もTimingAndEstimation pluginを参考にした。
テーブル構造は以下の通り
sprint_attrテーブル
基本情報。
milestone | マイルストーン名 |
---|---|
start_date | sprint開始日 |
end_date | sprint終了日 |
weekend | 週末 |
workhours | 1日の稼働時間 |
sprint_workdayテーブル
週末だけど稼働する日。
milestone | マイルストーン名 |
---|---|
a_date | 日付 |
sprintはmilestoneで管理しようと思っているので、マイルストーン名が主キーになっている。これ、イマイチだなー。ADMINでマイルストーン名変更されたらどうしようかな。milestoneテーブル自体がマイルストーン名を主キーにしているのが元凶なんだけども。サロゲートキーがあれば良かったのに。
日付は全部intね。UNIX秒。Tracの基本DB構造もそうなってるので。
sprint_attr.weekendは、どの曜日を週末(非稼働日)としてあつかうかをビットマスクとして持つ。右端1〜7bitが月曜〜日曜。これはpython datetimeオブジェクトのweekdayメソッドと合わせている。ちょっとトリッキーだけど、↓みたいなカンジで判定する。
#today(datetime型)が週末かどうか weekend & (1 << today.weekday())
実装
pluginをインストールまたはアップグレードした際に行う処理なので、IEnvironmentSetupParticipantを実装したクラスinitenv.pyに追加することにする。(参照:Trac Scrumもどきプラグイン開発記 - ほげにっき)
initenv.py(一部)
def __init__(self): self.db_version_key = 'TracScrumHalf_Db_Version' self.db_version = 1 self.db_installed_version = None # Initialise database schema version tracking. self.db_installed_version = self.get_system_value(self.db_version_key) def get_system_value(self, key): db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT value FROM system WHERE name='%s'" % key) rows = cursor.fetchall() if len(rows) == 1 : cursor.close() return int(rows[0][0]) else : version_value = 0 cursor.execute("INSERT INTO system (name,value) VALUES('%s', '%s')" %(key, version_value)) cursor.close() db.commit() db.close() return version_value
まんまTimingAndEstimation pluginを参考にさせてもらいました。
systemテーブルにDBバージョン番号を保存しておくことで、pluginを動的にアップグレードできる様にする。重要なのは↓の属性。
self.db_version_key = 'TracScrumHalf_Db_Version' self.db_version = 1 self.db_installed_version = None
db_version_key | systemテーブルに保存する為のキー |
---|---|
db_version | 当DBバージョン |
db_installed_version | インストール済plugin DBバージョン |
まずdb_installed_versionをsystemテーブルより取り出す。systemテーブルに存在しない場合は0とする。db_installed_version < db_versionの場合にDBをupgradeし、db_versionを保存する(後述)。
initenv.py(一部)
def upgrade_environment(self, db): (中略) if self.system_needs_upgrade(): self.do_db_upgrade(db) print "Done Upgrading" def do_db_upgrade(self, db): #get a database connection if we don't already have one if not db: db = self.env.get_db_cnx() cursor = db.cursor() # version 0 create tables: sprint_attr, sprint_holiday, sprint_workday if self.db_installed_version < 1: # create table 'sprint_attr' sqlSprintAttr = """ CREATE TABLE sprint_attr ( milestone text, start_date int, end_date int, weekend int, workhours int, UNIQUE (milestone) ); """ cursor.execute(sqlSprintAttr) # create table 'sprint_holiday' sqlSprintHoliday = """ CREATE TABLE sprint_holiday ( milestone text, a_date int, UNIQUE (milestone, a_date) ); """ cursor.execute(sqlSprintHoliday) # create table 'sprint_workday' sqlSprintWorkday = """ CREATE TABLE sprint_workday ( milestone text, a_date int, UNIQUE (milestone, a_date) ); """ cursor.execute(sqlSprintWorkday) # update the version, the db_version will be increased cursor.execute("UPDATE system SET value='%s' WHERE name='%s'" % (self.db_version, self.db_version_key)) self.db_installed_version = self.db_version cursor.close() #db.commit()
これで必要なテーブルをCREATEして、当DBバージョンを保存している。最後のcommitがコメントになっているのは、Tracのupgrade_environmentメソッドに以下コメントが書かれていた為。
Implementations of this method should not commit any database
http://trac.edgewall.org/browser/trunk/trac/env.py
transactions. This is done implicitly after all participants have
performed the upgrades they need without an error being raised.
timingandestimation pluginはcommitしている様に見えるがbugか?まあエラーが起きなければ問題はないのだろうけど。
あとはenvironment_needs_upgradeメソッドに、DBアップグレードが必要かどうかの判定を追加。
initenv.py(一部)
def environment_needs_upgrade(self, db): return self.ticket_fields_need_upgrade() or self.system_needs_upgrade() def system_needs_upgrade(self): return self.db_installed_version < self.db_version
いじょ!!
冗長な部分が増えてきたのでソース全文はのっけません。ある程度カタチになったらsubversionリポジトリを公開しますm(_ _)m