• redmineの プラグインを 2.0用に移行する

    Redmineによるタスクマネジメント実践技法

    redmine 2.0がリリースされて一ヶ月ちょい。
    新featureが出てくる前に自作のプラグインも移行しておかないとなーと思いつつ放置してたんだけど、やっと手をつけた。

    以下のURLを参考にした。

    Redmine 2.0.xにプラグインを移植する
    Redmine2.0へのプラグインのマイグレーションについて


    自分のところでひっかかったこと。

    • RAILS_ROOTが使えない
       → Rails.root
    • RAILS_DEFAULT_LOGGERが使えない
       →Rails.logger
    • RAILS_ROOT/vendor/plugin/が変更された
       →RAILS_ROOT/plugin/
    • routesの定義の仕方
       →ActionController::Routing::Routes.draw からRedmineApp::Application.routes.drawに
      RedmineApp::Application.routes.draw do
        match 'projects/:project_id/wiki/:id/graphviz', :to => 'wiki_graphviz#graphviz'
      end
      
    • テンプレートのファイル名が変わった
       →*.rhtml から *.html.erbに
    • テスト用webサーバ他のコマンドが変わった
       →./script/sever から ./script/rails server に
       →./script/runner から ./script/rails runner に
    • ActionController::Base.cache_configured? がprivateになった
       →意図が違うが ActionController::Base.perform_caching で代替


    ここからはredmine 2.0への移行じゃなくて、ruby 1.8から1.9に変えたことでひっかかったこと。

    • String#eachがなくなった
       →String#each_line とか
    • proc+ブロックで得たProcオブジェクトのブロック内でreturnしたら呼び出し元メソッドがreturnした
      これを知らなくてすごく悩んだ。
      Redmineのviewフック内でコントローラにrender_to_stringをsendしている。
      テンプレート内でクロージャ(proc由来のProcオブジェクト)を使ってtrue/falseを返しているつもりだったのだけど、viewフックメソッドからtrueが返る状態になってしまった。
      lambdaに変更した。


    それぞれremdine-2.0ブランチ
    https://github.com/tckz/redmine-wiki_graphviz_plugin
    https://github.com/tckz/redmine_wiki_preview_ext
    https://github.com/tckz/redmine_wiki_astah


    でも、redmine 2.0系のfeatureが増えてくるまでは、運用環境は1.4系のままかな。

  • redmineの wikiのプレビュー表示を移動可能にする

    ss.png redmineの wikiマクロで graphviz その4で編集中の内容で画像を描画できるようになった。
    だけど、プレビュー表示領域は編集領域の下方にあるため、dotをちょっと直して→画像確認→ちょっと直す、ということを繰り返そうと思うと都度上下に行ったり来たりしないといけないので面倒。

    プレビュー領域をドラッグして見やすい位置に移動したい。右側とか。

    ということで、wikiページ編集のプレビュー表示をドラッグ可能にするwiki_preview_extプラグイン
    https://github.com/tckz/redmine_wiki_preview_ext


    viewのフックを使って所定のコントローラ×アクションの場合に、javascriptコードを差し込んでドラッグ可能にする。
        class ViewListener < Redmine::Hook::ViewListener
    def view_layouts_base_body_bottom(context)
    context[:controller].send(:render_to_string,
    :template => 'wiki_preview_ext/body_bottom',
    :layout => false,
    :locals => {:context => context})
    end
    end
    redmine 1.3はscript.aculo.usを使っているのでこれをそのまま使わせてもらい、Draggableでdiv#previewをまるごと移動できるようにした。
        new Draggable(preview, {scroll: window});
    preview.setStyle({cursor: "move"});
    ノブを付けたかったけど、プレビュー機能がdiv配下をAjax.Updaterで更新しているのと、当該要素周辺の構造は変えないようにしたかったのでdiv全体にDraggable適用した。

    wikにオートプレビュー機能を追加するプラグインは既にあって、編集と同時にプレビュー更新することができる。
    既存のオートプレビュープラグインと併用するか、wiki_preview_extプラグインのオートプレビュー機能をプラグイン設定画面で有効にする。


  • redmineの wikiマクロで graphviz その4

    その3」を書いたのが3年以上前なのか。
    redmineのwikiにgraphvizを使った画像を埋め込めるようにするマクロ。
    https://github.com/tckz/redmine-wiki_graphviz_plugin

    graphviz_meマクロは、このマクロが埋め込まれているwikiページ全体をdotとみなして画像描画する。
    wiki編集中のプレビューの際に、wikiマクロに渡ってくるモデル(WIkiContent)が保存済のもののため、今現在編集している内容で描画できていなかった。(一旦保存する必要があった)
    よくよく考えてみれば、wikiマクロが呼び出されたときのselfがviewを指しているのでリクエストのパラメータも取得できるのだった。
    マクロの挙動がformの構造に依存するのはイヤだと思いつつも、保存しないでプレビューできたほうがマシか。

    編集中テキストのプレビューの場合は画像をdataスキームでimg@srcに直接入れちゃうことにした。

    <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg・・・TkSuQmCC">
    古いブラウザだと表示できないけど。
    画像部分の通信サイズが大きくなるけどレスポンス一回で画像もHTMLも返せると、取得した編集中テキストをまるごと受け取って画像を返すactionを新設しなくていい。


    環境:
    CentOS 6.2 x64
    ruby-1.8.7-p352
    mysql-server-5.1.61
    graphviz-2.26.0
    redmine-1.3.0
     

  • redmine 1.3.0にしたら wiki絡みの展開順が変わってた

    自作のwikiマクロの引数で、wikiリンクと同じ記法でリポジトリ上のリソースを指定させている。
    {{macro(source:path/to/file)}}
    
    redmine 1.3.0からwikiリンクとマクロの展開順が変わり、先にwikiリンクが処理されるようになったみたい。
    冒頭のマクロ引数に対してHTMLリンクに展開済の文字列(HTML)が渡ってくるようになった。

      Redmine::WikiFormatting::Macros.register do
        desc '略'
        macro :some_macro do |wiki_content_obj, args|
        end
    end
    1.2.xの場合、args[0]に「source:path/to/file」
    1.3.0の場合、args[0]に「<a href="https://passing.breeze.cc/mt/projects/sample/repository/entry/path/to/file" class="source">source:path/to/file</a>」
    という文字列が渡ってくる。

    「!」をつけると展開抑止になるので当面これで回避。
    {{macro(!source:path/to/file)}}
    

    あるいは引数の受け取り方を変えて
    {{macro(param=source:path/to/file)}}
    
    とすればHTMLリンクに展開されず引数を受け取れる。


  • jenkinsの DRY pluginで CPD

    jenkinsを使って継続的インテグレーションを行なっている。
    数年前はCruiseControl .NETを使っていたのだけど、hudsonを試したときユーザフレンドリーさに打たれて乗り換えた)

    以前からmakeなどで1手順ビルドできる仕組みを作ることにはこだわりがあった。
    たけど、単にビルドの1手順化だけでなく、
    •  複数の環境でビルドしたものを統合(CIサーバに集約)
    •  リポジトリのコミットとビルドを結びつけ(さらにITSのチケットに結びつく)
    •  複数の環境で自動テスト実行、その結果とビルドの結びつけ
    •  ビルドのログやテストのログなど記録をとる(確認したいときにすぐ辿れる)
    継続的インテグレーション入門 開発プロセスを自動化する47の作法
    ということを手間なく繰り返し可能とする仕組みには大きな意味があると思う。

    SCM、自動テスト、ITSそれぞれ単独でも役立つけど、
    ビルドとこれらを結びつけられるCIの存在は大きい。


    で、そのビルドと結びついた記録を取りたいものの1つがコードメトリクス。
    気にしている指標はいくつかあるけど、コードクローンについて。

    コードクローンの検出にCPD(PMD)を使っている。
    CPDのレポートxmlをjenkinsのDRY Pluginに食わせるだけ。ビルドごとの静的解析の結果をとりまとめてくれるプラグインでトレンドを見ることができる。
    正直に言えばjenkinsのビュー内でコードクローン部分そのものを見るのはあまり意味が無いというかかえって見づらいと思っている。eclipseにPMDプラグインをインストールしてクローン部分にアクセスする方が便利。
    あくまでjenkins上では時系列(ビルド)でコードクローンの増減を概観したい。


    ここの環境ではjenkinsのmasterをlinux上で動かしている。
    CPDの実行はWindowsスレーブ上で行なっている。
    入力はSJIS(MS932)でエンコードされたjavaソース。
    jenkinsのslave配下でjavaモジュールのビルドをantで行う。同様にantでCPDのレポートを作成している。

    PMDのlib下jarをCLASSPATHに指定してantタスクを定義
        <path id="cp.cpd">
            <fileset dir="${pmd.lib}">
                <include name="*.jar"/>
            </fileset>
        </path>
    
        <taskdef name="cpd" classpathref="cp.cpd" classname="net.sourceforge.pmd.cpd.CPDTask" />

    cpdタスクを実行
        
    <cpd encoding="Windows-31J" minimumTokenCount="100" format="xml" language="java" outputFile="${reports.cpd}/cpd.xml"> <fileset dir="${src.dir}"> <include name="**/*.java"/> </fileset> </cpd>

    で、後はjenkinsのワークスペースに出力されたxmlのpathをDry Pluginの入力に設定するだけ。


    当初、cpdタスクの入力エンコーディングを"MS932"にしていた。出力XMLのxml宣言にあるencodingも"MS932"になるのだけどこのままDry Pluginに読み込ませようとするとエラーになってしまう。
    Dry Pluginのソースをgithubからcloneして、自動テストの入力xmlのencodingをMS932に書き換えて実行したらスタックトレースに
    「Invalid encoding name "MS932".」と出ていた。
    org.apache.xerces.*が使われるから?


    環境:

    Windows 7 x64
     JDK6 u26 x86
     ant-1.8.2
    CentOS 5.6 x64
     JDK u26 x64
     ant-1.8.1