Tracの複数プロジェクトの管理って皆さんどうしてます?
Trac導入前に、何年かSVNが運用されていました。そして、リポジトリはプロジェクトごとに分割していましたとさ。現在20ぐらいリポジトリがあったりしています。
サーバーが古くて、OSがMiracle3.0で、Tracとか入れられなくて悔しい思いを。
やっと新しいサーバーをGetしてリポジトリ移行して、それで後からTrac入れましたよ。やったー。やっぱりTracいいな。
けれどさ、なんかたくさんのTracプロジェクトがあって見通し悪いなぁ。
みんなはどうしているのだろう。ググる。
・・・ん。
TraMとか、便利そうなものがあるみたいですけど、プロジェクトのURLを開いても真っ白。
あらら。
うーん。とりあえず、TracのTimeLineのRSSをまとめて、時系列で見れるようにしておけば、直近の動きは、まあまあ見えるのかなぁ。個別のRSSだと全体のタイムラインの把握は無理だぁ。あのライブラリの修正がおわったらpom.xml書き換えようとか、そういうの把握したいなぁ。
あと、Basic認証かけてるので、それをかいくぐってRSSをまとめたい。それに、他の開発者にも集約RSSを見えるようにしておけば、各自が複数のフィード登録しなくても済むしいいな。
じゃあ、イントラで使える、RSSあぐりげーたーでBasic認証できそうなやつないかな。あれれぇ、、、探せなかった。
というわけで、作ってみました。
TracのタイムラインのRSSを各プロジェクトから取ってきて、それらを時系列に並べて集約したRSSをつくるだけのシンプルなものです。CentOS5のサーバー用に作りましたので、Cronで定期実行されるようにして運用しています。
環境
# wget http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-2.noarch.rpm # rpm -ivh epel-release-5-2.noarch.rpm # yum install rubygems
- gem install mechanizeとかしておく。
- Proxy設定が必要なら、環境変数http_proxyを設定。http://を省略したら駄目。
export http_proxy=http://proxy.example.com:8080
- apacheのDocumentRootが/var/www/html
- /var/www/html/tracfeeds/allfeeds.rdf が http://server_ip/tracfeeds/allfeeds.rdfとしてブラウザでアクセスできる
コード
#!/usr/bin/ruby require 'rubygems' require 'mechanize' require 'logger' require 'rss' UID = 'hoge' #Basic認証のUserID PASS = 'hoge' #Basic認証のPassword URLBASE = 'http://server_ip/trac' #tracのプロジェクト一覧のURL TRACHOME = '/var/www/html/trac' #tracのプロジェクトを保存した親ディレクトリ TIMELINERSS = 'timeline?milestone=on&ticket=on&ticket_details=on&changeset=on&max=50&daysback=90&format=rss' OUTDIR='/var/www/html/tracfeeds' AGGREGATED = 'allfeeds.rdf' dirs = `ls -1 #{TRACHOME}` projects = dirs.split("\n") feed_urls = {} #WWW::Mechanize でBasic認証+各プロジェクトのRSSを取得 agent = WWW::Mechanize.new projects.each { |proj| agent.auth(UID,PASS) agent.get("#{URLBASE}/#{proj}/login") feedurl = "#{URLBASE}/#{proj}/#{TIMELINERSS}" feed_urls.store(proj, feedurl) rss = agent.get(feedurl) rss.save_as("#{OUTDIR}/#{proj}_timeline.rdf") } #取得したRSSを読み込んで、Itemを抽出します。 allItems = [] Dir.foreach(OUTDIR) {|file| if ( file == "." || file == ".." || file == AGGREGATED) next end begin feed = RSS::Parser.parse(File.read("#{OUTDIR}/#{file}"),false) feed.items.each { |item| item.title = "#{feed.image.title}: #{item.title}" #feed.image.titleはリポジトリ名がセットされるようなので、集約RSSのタイトルの先頭に表示するリポジトリ名として流用しています。 allItems.push(item) } rescue end } #抽出したItemから集約したRSSを作ります。 channel_desc_links = [] feed_urls.each { |proj,feed| channel_desc_links.push("<a href=\"#{feed}\">#{proj}</a>") } aggregated = RSS::Maker.make("2.0") do |maker| maker.channel.title = "trac all timeline feeds" maker.channel.link = "http://172.24.112.50/trac" maker.channel.description = "Tracのタイムラインを集約したRSSです\n" + projects.join("\n") maker.image.title = "dev 50 trac timelines" maker.image.url = "http://172.24.112.50/common/trac_banner.png" maker.items.do_sort = true #更新順にソートする allItems.each { |add| maker.items.new_item { |new| new.link = add.link new.title = add.title new.date = add.date new.description = add.description } } end open("#{OUTDIR}/#{AGGREGATED}",'w') { |f| f.puts aggregated.to_s }
ちょっと運用してみたところ、まあまあ使えました。リポジトリをまたがって開発するなら便利かも。あと、上司に対してこんなに活動していますとアピールできたり。
根本的にリポジトリを整理できればいいのですけどね。