Hatena::ブログ(Diary)

さり海馬 このページをアンテナに追加 RSSフィード

2009-04-10

こいつ、動くぞ…

というわけで、これまでアレコレやってきたチケット自動生成スクリプトはあらかた完成しました。今までは csvインポート機能経由だったので人手が要ったけど、そこはxml-rpc使って全部オンラインでやるようにしたので完全無人化です。やたー。

OralceDB →(sql/cx_Oracle)→ 今回のスクリプト ⇔(xml-rpc/xmlrpclib*1 )⇔ Trac

技術的な面は解決したので、あとは部門の要件管理Trac 導入を認めさせるという政治的な闘争へとシフトするじゃよ。なんかそっちの方が前途多難だなぁ。だがあの邪悪Excel*2で要件管理するのはもう嫌なのじゃよ。

*1:正確にはpython付属のxmlrpclibではなく、プロキシ超えても大丈夫なこちらのスクリプトを使わせてもらいました→ http://python.matrix.jp/web/xmlrpc_client.html

*2:どうしてお年寄りたちってあんなにExcelが好きなんだろう。マジでわかんない。

Fighter-KOUFighter-KOU 2009/04/10 18:03 > …ううう、どんどん iPhone が欲しくなってきた(笑)。
いっそ、auの月額プランをミニマムにして、解約可能になるまで塩漬けするというのはどうか。
当然、その分のお小遣いは持ち出しにはなるが、精神的な平穏は迎えられると思うぞ。

でびぃでびぃ 2009/04/11 08:04 >どうしてお年寄りたちってあんなにExcelが好きなんだろう。マジでわかんない。

・・・「お年寄り」に自分ははいってないのね。
といいながら、現場で「ごみマスタ多いし意味不明多いから整理しようよ」「全部やるの面倒だから使ってるのだけにしません?」という馬力のない若者見て「この若年寄め」と思ってるじじぃが通りますよ。
でもちょっと刺激されたし、知っておくほうがよさそうな状況もあるのでwin-socketとかsoapくらい四十の手習いで勉強してみようかな

びじうびじう 2009/04/12 04:04 >Fighter-KOU
 その見解には賛成するけど、iPhoneを手に入れることで、「思ったほど使い勝手が良くない」みたいな感じで失う心の平穏も計算に入れるべきじゃないかと(笑)。

 俺から見れば、夏に出る第三世代を待って買える、というのは羨ましくもあるよ。それが無料になるかどうかはともかく・・・ってか、そこで初期投資が最低1万円になっちゃったら同じことか・・・。

びじうびじう 2009/04/12 04:06  あ、書き忘れた。
 ダーウィンの話は、なんか本当に、「人間っていいよね」的な香りがしていいねぇ。

thalionthalion 2009/04/13 12:23 いらっしゃいませ。お返事が遅れてすみません。

>Fighter-KOU
それはそれでアリだな。ちょっと考えてみます。

>でびぃ
当然入りません(キリッ:AA略)。普段から年寄り年寄り言っていると本当に年寄りになってしまいそうで(笑)。

>びじう
そう、今度出るのが確定な新型がね、目の前をちらちらしてるのよ。

あとダーウィン、なんかこーニンマリするよね。

2009-04-08

メモ:xml-rpc の ticket.getTicketFields()で得られるリスト

ticket.getTicketFields() で得られるのは、辞書を要素として持つリスト

  • [ {"type":"text", "name":"summary", ... }, {...}, .... ]

一つの辞書が一つの属性記述している。対応関係は以下のとおり:

tracとりうる値typenamelabelcustomorderoptionsvalueoptional
テキスト*1一行の文字列"text"属性文字列題名文字列True/なし*2表示順序/なし*3なしなしなし
テキストエリア複数行の文字列"textarea"
チェックボックスTrue/False"checkbox"初期値
プルダウン選択型文字列optionsの中から一つ、もしくはヌル"select"選択対象リスト初期値True/なし*4
ラジオボタン文字列optionsの中から一つ、もしくはヌル"radio"選択対象リスト初期値True/なし*5

基本的に文字列String 型だが、多バイトコード文字列unicode 型。

*1:日付情報もこの型を使う。表現形式は"YYYY/MM/DD"

*2カスタム属性ならTrue、そうでないならこのキーワード自体なし

*3カスタム属性ならその表示順序を示す数値、そうでないならこのキーワード自体なし

*4:選択必須ならTrue、そうでないならこのキーワード自体なし

*5:選択必須ならTrue、そうでないならこのキーワード自体なし

2009-03-31

xml-rpc で trac につないでみた

とりあえずはライブラリリファレンスにあるxmlrpclibを使ってみる。

必要な手順

  1. trac管理メニューから、xml-rpcアクセスするアカウントに XML_RPC 権限を与える
  2. リモートクライアントからアクセスする

設定したら、公開されているAPI名前を取得する listMethods() というやつを呼んでみる。

import xmlrpclib

server = xmlrpclib.ServerProxy(
    "http://ユーザー名:パスワード@サーバーのアドレス:tracのポート番号/trac/プロジェクト名/login/xmlrpc")

apilist = server.system.listMethods()

for item in apilist:
  print item

結果:「ProtocolError: <ProtocolError for :ユーザー名:パスワード@サーバーのアドレス:tracのポート番号/trac/プロジェクト名/login/xmlrpc: 401 Authorization Required>」

…なんだか認証ダメだと言っているようだ。

いろいろとごにょごにょしていると、どうもこの xmlrpclib は proxy 経由でのアクセスに対応できていないっぽい。さすがに自分では書けないなー。

一縷の望みを求めてグーグル先生におすがりしていると、まさにそのものズバリコードを公開されている方が。

標準のxmlrpclibがシンプル過ぎて繋げないサーバーがあるので、 もう少しがんばって繋ぎに行くXML-RPCクライアントラッパーを作成しました。

XML-RPCクライアントヘルパー

…神だ。早速パクって参考にさせていただいて、やってみる。

import xml_rpc

url = 'http://ユーザー名:パスワード@サーバーのアドレス:tracのポート番号/trac/プロジェクト名/login/xmlrpc'
user, password = 'ユーザー名','パスワード'
server = xml_rpc.XmlRpcServer(url, user, password)
print server.system.listMethods()

['system.multicall', 'system.listMethods', 'system.methodHelp', 'system.methodSignature', 'system.getAPIVersion', 'ticket.query', 'ticket.getRecentChanges', 'ticket.getAvailableActions', 'ticket.get', 'ticket.create', 'ticket.update', 'ticket.delete', 'ticket.changeLog', 'ticket.listAttachments', 'ticket.getAttachment', 'ticket.putAttachment', 'ticket.deleteAttachment', 'ticket.getTicketFields', 'ticket.component.getAll', 'ticket.component.get', 'ticket.component.delete', 'ticket.component.create', 'ticket.component.update', 'ticket.version.getAll', 'ticket.version.get', 'ticket.version.delete', 'ticket.version.create', 'ticket.version.update', 'ticket.milestone.getAll', 'ticket.milestone.get', 'ticket.milestone.delete', 'ticket.milestone.create', 'ticket.milestone.update', 'ticket.type.getAll', 'ticket.type.get', 'ticket.type.delete', 'ticket.type.create', 'ticket.type.update', 'ticket.status.getAll', 'ticket.status.get', 'ticket.status.delete', 'ticket.status.create', 'ticket.status.update', 'ticket.resolution.getAll', 'ticket.resolution.get', 'ticket.resolution.delete', 'ticket.resolution.create', 'ticket.resolution.update', 'ticket.priority.getAll', 'ticket.priority.get', 'ticket.priority.delete', 'ticket.priority.create', 'ticket.priority.update', 'ticket.severity.getAll', 'ticket.severity.get', 'ticket.severity.delete', 'ticket.severity.create', 'ticket.severity.update', 'wiki.getRecentChanges', 'wiki.getRPCVersionSupported', 'wiki.getPage', 'wiki.getPageVersion', 'wiki.getPageHTML', 'wiki.getPageHTMLVersion', 'wiki.getAllPages', 'wiki.getPageInfo', 'wiki.getPageInfoVersion', 'wiki.putPage', 'wiki.listAttachments', 'wiki.getAttachment', 'wiki.putAttachment', 'wiki.putAttachmentEx', 'wiki.deletePage', 'wiki.deleteAttachment', 'wiki.listLinks', 'wiki.wikiToHtml', 'search.getSearchFilters', 'search.performSearch']

キタ━━━(゚∀゚)━( ゚∀)━( ゚)━( )━(゚ )━(∀゚ )━(゚∀゚)━━━!!!!!

2009-03-23

そのセミコロンは必要ない

cx_Oracle でクエリを投げるとき、SQL文末の";"は必要ない。セミコロンは SQL Plus の拡張文法だから。

…こんなことで一時間もつぶした…orz。

参考:http://logbookx.blogspot.com/2008/03/ora-00911.html

trac.db の中のテーブルを JOIN してみる

こんどは会社のSQLサーバーじゃなくて、trac の sqlite3 のデータの中身を解析することにしました。んでメモ

trac.db の中にはいろいろテーブルが入っている*1けれども、実際にチケットに直接関係しているのは ticket と ticket_custom だけ。

ticketは id を主キーとして、type, component, summary, …というように、各属性が並んでいる*2 *3

idtype.....statussummarydescription
1仕様変更.....newほげほげの仕様変更の件このままだとダメになるぞ
2仕様変更.....newほげほげの仕様変更の件2このままだとダメになるぞ2

ticket_custom はカスタム属性とその値のリストで、中身はこんな感じ

ticketnamevalue
1due_assign2009/3/10
1complete2009/3/15
1optionD
2due_assign2009/3/22
2complete2009/3/28
2optionX

こいつらをjoinして普通にtracで見える形にするには、こういう感じでクエリ組むといいと思う

SELECT
  id
  ,type
  ,summary
  ,a.value AS 'DUE_ASSIGN'
  ,c.value AS 'COMPLETE'
  ,op.value AS 'OPTION'
FROM
  ticket t
    JOIN ticket_custom f ON f.ticket = t.id AND a.name = 'due_assign'
    JOIN ticket_custom b ON b.ticket = t.id AND c.name = 'complete'
    JOIN ticket_custom op ON op.ticket = t.id AND op.name = 'option'
WHERE
 t.type = '仕様変更'
 ORDER BY t.value
;

出てくる結果はこんな感じ

idtype.....statussummarydescriptionDUE_ASSIGNCOMPLETEOPTION
1仕様変更.....newほげほげの仕様変更の件このままだとダメになるぞ2009/3/102009/3/15D
2仕様変更.....newほげほげの仕様変更の件2このままだとダメになるぞ22009/3/222009/3/28X

SQL初めてだったんですんげー悩みましたが、最終的にtracが吐き出すDEBUGログを眺めていて、同じテーブルを別のテーブルとして複数JOINしていいってことに気づいて解決しました。ログの中にはクエリがそのまま出力されてんのね。

*1:sqlite3 trac.db してから .tables すれば見られる

*2:ちなみにテーブルの中身をを確認するときは、.explain ON して、人間が理解しやすい出力にしとくと吉

*3:あと、確認するときは間違ってテーブルを破壊することのないように、trac.db をコピーして、コピーした方を使うことを強くお勧めしときます

MIZOMIZOMIZOMIZO 2009/03/23 22:34 単に「チケットをみる(report)」で、レポートの登録でやると、簡単に確認できますよ。

thalionthalion 2009/03/24 10:21 いらっしゃいませ

>MIZOMIZO
コメントありがとうございます。tracの環境下でやるならそれがいちばん簡単ですよね。実はこれ、会社の要件管理サーバー(Oracle)のデータを日々自動的に直接tracに取り込もうというプロジェクトの一環でして、pythonのスクリプトで直接 sqlite3 の db を触る必要があって、いろいろ勉強しているところなんです。

そうか、MIZOMIZOさんに聞くって手があったなぁ…。

2009-03-19

trac の csv チケット生成を python でやってみた

やったこと:

  1. 会社の要件管理DB(OralceDB)から自分関係ある新規の仕様変更要求をフィルタリングして、csvファイルに落とす
  2. 自作のスクリプトで、この中からリリース対象機種とそのブランチに合わせて1対Nの関係tracチケットCSV形式で生成する
    • このとき、既存のチケットとかぶらないようにダブりチェックを行いながら生成)
    • チケットファイルは utf-8、DBのファイルは sjis なので、codecs とか使って相互に変換しながら作業
  3. 生成されたチケットcsvファイルを tracインポート機能を使って取り込む
  4. ウマー。

python初めて一ヶ月の割りには頑張ったよ、俺。

今後の野望:

  • 1 の自動化。python + cx_Oracle 使えばできるはず。とりあえずは cx_Oracle のインスコ完了。import cx_Oracle しても怒られなかったので吉*1。あとは SQL の勉強だだだだだー (〓ω〓.)@ *2
  • 3 の自動化。こっちは xml_rpc 使ってできそう。

参考にしたページ:

今後参考にする予定のページ:

追伸。外部認証してるとどーもうまくログインできないっぽいから、データベース認証を使うのが吉だと思った。よくわからんけど。

*1:このためだけに Oracle Client のバージョンを 9i に上げた

*2:いやな汗を流しながら

でびぃでびぃ 2009/03/20 08:33 SQL自体は簡単だが、そいつでいかすwhere句を書くのがむずかしいよね・・・(PL/SQLのことをいってるなら話は別)

thalionthalion 2009/03/23 14:37 いらっしゃいませ。

>でびぃ
確かにおっしゃるとおり。SQL自体は単純だけど、抽出部分をどう条件付けるかにかなりのノウハウが。さらに言うと、アクセスしようとしてる要件管理データのテーブルの構成がやや変態的というか屋上屋を重ねた構造というか、要するにアレなので、さらに WHERE 句を書くのが面倒になっていることがわかりました。いやぁ、歴史の重みを感じるなぁ(苦笑)。