コードレビューの補助に、Dangerを導入しているチームも多いと思います。
プラグインも簡単に作れるので、半分覚え書きですが、解説したいと思います。
プロジェクトの生成
ローカルにdanger
が入っていない場合は、事前に入れておきます。
sudo gem install danger
最初に、テンプレートからプロジェクトを生成します。 命名は、snake caseのプラグインが多いようです。
わかりやすいように、sample_plugin
という名前で進めます。
danger plugins create sample_plugin
この場合、danger-sample_plugin
というディレクトリが生成されます。
ファイルの構成
基本的に触る部分は、プラグインのソース(lib
以下)とテストコード(spec
以下)です。
プラグインのソースはlib/sample_plugin/plugin.rb
が中心です。
Dangerfile
から触るプロパティなどは、ここに記述します。
テストコード(RSpec)はspec/sample_plugin_spec.rb
に記述していきます。
テストコードは書かなくても動作には問題ないですが、Dangerプラグインという性質上、ローカルでのデバッグがしづらいので、テストを書きながら開発するのを推奨します。
プラグイン本体の書き方
最初の状態ではこのようになっています。
module Danger class DangerHoge < Plugin attr_accessor :my_attribute def warn_on_mondays warn 'Trying to merge code on a Monday' if Date.today.wday == 1 end end end
attr_accessor
でmy_attribute
というアクセサが公開されています。
Dangerfile
から指定するプロパティはここで公開します。
メソッドはwarn_on_mondays
が公開されています。
Dangerfile
からは、
sample_plugin.my_attribute = ["hoge"] sample_plugin.warn_on_mondays
のように利用することが出来ます。
RSpecの書き方
spec/sample_plugin_spec.rb
は、最初はこのような内容です。
require File.expand_path("../spec_helper", __FILE__) module Danger describe Danger::DangerHoge do # ... describe "with Dangerfile" do before do # それぞれのテストケースの前に呼ばれる共通処理 @dangerfile = testing_dangerfile @my_plugin = @dangerfile.hoge end it "Warns on a monday" do # テストケース end end end end
it
ブロック一つひとつがテストケースにあたり、それぞれの実行前にbefore
ブロックに書かれた内容が実行されます。
各ケースは、よくある単純比較の場合は、expect(<実際の値>).to eq 期待値
のように書きます。
expect(@dangerfile.status_report[:messages]).to eq ["Hello hoge!"]
実際の例
試しに、ダンプされたファイル出力をパースして、その中から警告を抽出するプラグインを作ってみます。
分かりづらいかもしれませんが、ご容赦ください。
テストの記述
先にテストを書いておくTDD的な進め方をすると、検証が楽になります。
テスト対象のファイルを事前に書き出しておいて、specのbefore
でそれを読み込む処理を書きます。
静的ファイルは、spec/fixtures
に配置します。
describe "with Dangerfile" do # ... context "enable linker warnings" do before do @xcode_warnings.show_build_warnings = true @sample_plugin.analyze_file "spec/fixtures/log_with_4_errors" end end end
プラグインにshow_build_warnings
とanalyze_file
はまだ実装していませんが、TDDの考え方では最初に失敗するようなテストを記述するので、問題ありません。
テストケースを実装していきます。
今回は、「警告が4つ出ること」と、「メッセージが表示される」ことを期待する結果とします。
describe "with Dangerfile" do context "enable linker warnings" do before do @xcode_warnings.show_build_warnings = true @sample_plugin.analyze_file "spec/fixtures/log_with_4_errors" end it "warn 4 lines" do expect(@dangerfile.status_report[:warnings]).to eq [ "警告文1", "警告文2", "警告文3", "警告文4" ] end it "put a single message" do expect(@dangerfile.status_report[:messages]).to eq [ "メッセージ" ] end end end
それぞれ警告とメッセージは、@dangerfile.status_report[:warnings]
と@dangerfile.status_report[:messages]
に入ります。
これらのテストケースが通るように、プラグインの実装をします。
プラグインの実装
show_build_warnings
とanalyze_file
を実装していきます。
パーサーの実装は省略しますが、テキストをパースして警告を抽出するクラスです。
module Danger class SamplePlugin < Plugin attr_accessor :show_build_warnings # rubocop:disable Lint/DuplicateMethods def show_build_warnings @show_build_warnings.nil? ? true : @show_build_warnings end def analyze(log_text) parser = LogParser.new parser.show_build_warnings = show_build_warnings parsed = parser.parse_warnings(log_text) parsed.each do |warning| warn MessageFormatter.new.format(warning) # 警告文 end message "メッセージ" unless parsed.empty? end def analyze_file(file_path) File.open(file_path) do |f| analyze(f.read) end rescue Errno::ENOENT, Errno::EACCES => e puts "Couldn't open the file: #{e}" end end end
attr_accessor
でshow_build_warnings
を定義します。
def show_build_warnings @show_build_warnings.nil? ? true : @show_build_warnings end
とすることで、デフォルトでtrue
にすることが出来ます。
次にanalyze_file
(analyze
)の中でテキストをパースして、警告とメッセージを出す処理を書きます。
警告とメッセージの出し方はDangerfile
と同じで、warn
とmessage
です。
先程書いたテストに対して実際に、テストが通るかを、
bundle exec rake spec
で確認しながら実装を進めていきます。(bundlerも入れておいてください)
Travis CIの設定
.travis.yml
が若干古いので、更新が必要です。
一例ですがこんな感じです。
language: ruby cache: directories: - bundle rvm: - 2.3.1 - 2.4.5 - 2.5.3 branches: only: - master script: - bundle exec rake spec
gemspec
を書けばgemとして登録することも出来ます。