Dangerプラグインを作ろう
Danger
最近流行りつつある? Danger です。 Pull Request に対して色々チェックできるようになります。
先月末にポツポツと紹介記事が出ました。
- cookpadさんの記事
- Recruit Jobsさんの記事
- Node版のDangerJSは こちらの記事 が詳しいです。
Dangerとても便利です。 他のプロジェクトでも使えそうなルールなどはプラグインにして使い回ししたいですね。 なのでプラグインを作ってみます。
プラグイン作成も公式ページで詳しく乗ってます。 http://danger.systems/guides/creating_your_first_plugin.html
Dangerのインストール
$ gem install danger
プラグインの初期化
プラグイン名にハイフン(-)は推奨されていません。 単語はアンダースコア(_)で区切りましょう。
$ danger plugins create <plugin_name>
上記コマンドを実行すると、 git config からユーザ名とメールアドレスを取得してよしなに初期化してくれます。
danger-plugin_name/ ├── Gemfile ├── Guardfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── danger-plugin_name.gemspec ├── lib │ ├── danger_plugin.rb │ ├── danger_plugin_name.rb │ └── plugin_name │ ├── gem_version.rb │ └── plugin.rb └── spec ├── plugin_name_spec.rb └── spec_helper.rb 3 directories, 12 files
作成されたディレクトリへ移動します。
danger-<plugin_name>
というディレクトリが作成されています。
$ cd danger-plugin_name
テストなどに必要なGemをインストールしておきます。
$ bundle install --path vendor/bundle
また、テストを実行する際にリポジトリの upstream の情報が必要になります。リポジトリを作成して upstream を登録しておきます。
$ git remote add origin <上流のリポジトリURL> $ git push -u origin master
メソッドを作る
簡単なプラグインを作る場合は lib/<plugin_name>/plugin.rb
を変更するだけでできます。
say
というメソッドを追加してみます。
lib/<plugin_name>/plugin.rb
diff --git a/lib/plugin_name/plugin.rb b/lib/plugin_name/plugin.rb index eeda801..cea9600 100644 --- a/lib/plugin_name/plugin.rb +++ b/lib/plugin_name/plugin.rb @@ -29,5 +29,12 @@ module Danger def warn_on_mondays warn 'Trying to merge code on a Monday' if Date.today.wday == 1 end + + # A method that messages 'Hello Danger.' + # @return [Array<String>] + # + def say + message 'Hello Danger.' + end end end
テストを書く
プラグインを作ったらテストをかきましょう。
spec/<plugin_name>_spec.rb
diff --git a/spec/plugin_name_spec.rb b/spec/plugin_name_spec.rb index 484958f..a3ec8ad 100644 --- a/spec/plugin_name_spec.rb +++ b/spec/plugin_name_spec.rb @@ -36,6 +36,11 @@ module Danger expect(@dangerfile.status_report[:warnings]).to eq([]) end + it "Messages" do + @my_plugin.say + + expect(@dangerfile.status_report[:messages]).to eq(["Hello Danger."]) + end end end end
テストを書いたら実行します。 以下のコマンドで rspec と RuboCop が実行されます。 RuboCopでは色々指摘されると思うので必要あれば修正してください。
$ bundle exec rake spec
.... Finished in 0.06292 seconds (files took 0.4549 seconds to load) 4 examples, 0 failures Running RuboCop... Inspecting 6 files ...CCC Offenses: lib/plugin_name/plugin.rb:20:1: C: Extra empty line detected at class body beginning. lib/plugin_name/plugin.rb:30:12: C: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. warn 'Trying to merge code on a Monday' if Date.today.wday == 1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lib/plugin_name/plugin.rb:37:15: C: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. message 'Hello Danger.' ^^^^^^^^^^^^^^^ spec/plugin_name_spec.rb:42:1: C: Tab detected. expect(@dangerfile.status_report[:messages]).to eq(["Hello Danger."]) ^^ spec/plugin_name_spec.rb:42:3: C: Inconsistent indentation detected. expect(@dangerfile.status_report[:messages]).to eq(["Hello Danger."]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ spec/spec_helper.rb:12:23: C: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. if `git remote -v` == '' ^^ 6 files inspected, 6 offenses detected RuboCop failed!
動作確認したい
これがとてもめんどくさいです。 Pull Requestを用意する必要があります。 確認の場合、既にCloseされている Pull Request でも問題ありません。 個人で開発しているライブラリのリポジトリで確認してみました。
$ git clone https://github.com/duck8823/Slack-RTM-Bot.git $ cd Slack-RTM-Bot
Dangerとプラグインを使えるようにGemfileを用意してやります。
プラグインは :path
を指定することで作成途中のもので試すことができます。
Gemfile
source "https://rubygems.org" gem 'danger' gem 'danger-plugin_name', :path => 'path/to/danger-plugin_name'
bundleインストール
$ bundle install --path vendor/bundle
これで準備ができました。
続いて Dangerfile
を用意しましょう。
プロジェクト直下に置く必要があります。
Dangerfile
plugin_name.say
Dangerfile
ではプラグインのインスタンスが利用できます。
インスタンス名は以下の命名規則に従います。
http://danger.systems/guides/creating_your_first_plugin.html#tech-specs
確認は、
$ bundle exec danger local
で可能です。
また、
$ bundle exec danger pr https://github.com/duck8823/Slack-RTM-Bot/pull/20
のようにすることで特定の Pull Request に対して確認することも可能です。
local
または pr
で実行した場合、以下のような内容が表示されます。
Info: +------------------+----------------------------------------------------------------------------------------------+ | Danger v5.3.3 | | DSL Attributes | +------------------+----------------------------------------------------------------------------------------------+ | status_report | | | violation_report | | | --- | --- | | scm_provider | github | | diff | diff --git a/lib/Slack/RTM/Bot/Client.pm b/lib/Slack/RTM/Bot/Client.pm | | | index 9b86bc6..4c8ff0d 100644 | | | --- a/lib/Slack/RTM/Bot/Client.pm | | | +++ b/lib/Slack/RTM/Bot/Client.pm | | | @@ -248,7 +248,7 @@ sub _listen { | | | $channel = $self->find_channel_or_group_name($buffer_obj->{channel}); | $channel ||= $self->_refetch_channel_name($buffer_obj->{channel}); | $channel ||= $self->_refetch_group_name($buffer_obj->{channel}); | | - die "There are no channels or groups of such id: $buffer_obj->{user}" unless $user; | | + die "There are no channels or groups of such id: $buffer_obj->{channel}" unless $channel; | |RTM::Bot::Response->new( | | | @@ -273,4 +273,4 @@ ACTION: for my $action(@{$self->{actions}}){ | | | | | | -1; | | | \ No newline at end of file | | | +1; | | added_files | #<Danger::FileList:0x007fe123a9d678> | | deleted_files | #<Danger::FileList:0x007fe123a9cea8> | | modified_files | lib/Slack/RTM/Bot/Client.pm | | renamed_files | [] | | lines_of_code | 4 | | deletions | 2 | | insertions | 2 | | commits | b4e3b9fd228752e3c7fffd7c9cb5258959f281a2 | | api | Octokit::Client | | pr_json | [Skipped JSON] | | mr_json | [Skipped JSON] | | pr_diff | [Skipped Diff] | | review | #<Danger::RequestSources::GitHubSource::Review:0x007fe12398a498> | | pr_title | bugfix channel or group not found (was checking for user instead) | | pr_body | | | pr_author | dada | | pr_labels | [] | | branch_for_base | master | | branch_for_head | master | | base_commit | 947aeeaf5443494d3e7895292662b617b369bf05 | | head_commit | b4e3b9fd228752e3c7fffd7c9cb5258959f281a2 | | mr_title | bugfix channel or group not found (was checking for user instead) | | mr_body | | | mr_author | dada | | mr_labels | [] | | say | Violation Hello Danger. { file: , line: } | | my_attribute | | | warn_on_mondays | | | --- | --- | | SCM | Danger::GitRepo | | Source | Danger::LocalGitRepo | | Requests | Danger::RequestSources::GitHub | | Base Commit | commit 947aeeaf5443494d3e7895292662b617b369bf05 | | | Author: shunsuke maeda <duck8823@gmail.com> | | | Date: Sat Apr 8 12:30:31 2017 +0900 | | | | | | Checking in changes prior to tagging of version 1.04. | | | | | | Changelog diff is: | | | | | | diff --git a/Changes b/Changes | | | index 311b411..e8e2578 100644 | | | --- a/Changes | | | +++ b/Changes | | | @@ -2,6 +2,10 @@ Revision history for Perl extension Slack-RTM-Bot | | | | | | {{$NEXT}} | | | | | | +1.04 2017-04-08T03:30:26Z | | | + | | | + - Fix dying when response to new channel/group | | | + | | | 1.03 2017-04-05T23:11:07Z | | | | | | - Fix a bug that zombies spawn when stop_RTM | | Head Commit | commit b4e3b9fd228752e3c7fffd7c9cb5258959f281a2 | | | Author: dada <dada@perl.it> | | | Date: Fri May 19 18:07:20 2017 +0200 | | | | | | bugfix channel or group not found (was checking for user instead) | +------------------+----------------------------------------------------------------------------------------------+ Results: Messages: - [ ] Hello Danger. - [ ] Hello Danger.
Info:
ではDangerが取得した Git や GitHub などの情報を閲覧することができます。また、プラグイン内の 引数がないメソッドを自動的に実行し 、結果を表示してくれます。
Results:
では message
や fail
などの DSL を実行した結果を表示してくれます。
上記の例で Hello Danger.
が重複して表示されているのは、
- Dangerfileでの呼び出し
- Info: で表示するための呼び出し
で二回実行されたからです。
引数なしのメソッドでPull Requestをクローズするなどの処理を実装した場合、local または pr モードで意図しないメソッド呼び出しが起こる場合があるので気をつけましょう。
(記事を書いた時点でDangerのバージョンは 5.3.3
)
また、実行時に
Octokit::TooManyRequests: GET https://api.github.com/repos/duck8823/Slack-RTM-Bot/issues/20: 403 - API rate limit exceeded for
というようなエラーが出た場合は、
環境変数に DANGER_GITHUB_API_TOKEN
を設定してやることで回避できる場合があります。
利用するトークンは https://github.com/settings/tokens で作成することができます。
READMEの自動生成
Dangerは README を自動的に生成するコマンドも用意してくれています。
$ bundle exec danger plugins readme
### plugin_name This is your plugin class. Any attributes or methods you expose here will be available from within your Dangerfile. To be published on the Danger plugins site, you will need to have the public interface documented. Danger uses [YARD](http://yardoc.org/) for generating documentation from your plugin source, and you can verify by running `danger plugins lint` or `bundle exec rake spec`. You should replace these comments with a public description of your library. <blockquote>Ensure people are well warned about merging on Mondays <pre> my_plugin.warn_on_mondays</pre> </blockquote> #### Attributes `my_attribute` - An attribute that you can read/write from your Dangerfile #### Methods `warn_on_mondays` - A method that you can call from your Dangerfile `say` - A method that messages 'Hello Danger.'
plugins readme
コマンドは lib/<plugin_name>/plugin.rb
のドキュメント(YARD形式)を元にREADMEを作成します。
正しくドキュメントが記述されているかどうかは、
$ bundle exec danger plugins lint
で調べることができます。 例えば、追加したメソッドにドキュメントが存在しない場合には以下のようなエラーが出ます。
[!] Failed Errors - Description - say (method): - You should include a description for your method. - @see - https://github.com/dbgrandi/danger-prose/blob/v2.0.0/lib/danger_plugin.rb#L40#-L41 - /private/tmp/danger-plugin_name/lib/plugin_name/plugin.rb:33 Warnings - Return Type - say (method): - If the function has no useful return value, use ` @return [void]` - this will be ignored by documentation generators. - @see - https://github.com/dbgrandi/danger-prose/blob/v2.0.0/lib/danger_plugin.rb#L46 - /private/tmp/danger-plugin_name/lib/plugin_name/plugin.rb:33 Failing due to errors
記述に従ってドキュメントを整備しましょう。
公開しましょう
良いプラグインができたら公開しましょう。
公開前に、 danger-<plugin_name>.gemspec
を確認しましょう。
danger-<plugin_name>.gemspec
# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'plugin_name/gem_version.rb' Gem::Specification.new do |spec| spec.name = 'danger-plugin_name' spec.version = PluginName::VERSION spec.authors = ['shunsuke maeda'] spec.email = ['duck8823@gmail.com'] spec.description = %q{A short description of danger-plugin_name.} spec.summary = %q{A longer description of danger-plugin_name.} spec.homepage = 'https://github.com/duck8823/danger-plugin_name' spec.license = 'MIT' . . .
githubアカウント名と git config の user.name が異なる場合などは適宜変更してください。 spec.homepage
のアカウント名部分に user.name が使われるのでスペースがある場合などは gem に登録できません。
修正が完了したら
$ rake release
で RubyGems に登録することができます。
さらに Danger本家サイト にプラグインとして紹介してもらいましょう。 以下にプラグインを追加して Merge Request を出せば、光速でマージしてくれます。
https://gitlab.com/danger-systems/danger.systems/blob/master/plugins.json
その後、サイトはそのうち更新されます。
plugins
コマンドでも確認できます。
$ danger plugins Downloading Plugins list... Available Danger Plugins: -> danger-prose A danger plugin for working with bodies of markdown prose. - Gem: danger-prose - URL: https://github.com/dbgrandi/danger-prose -> danger-android_lint Lint files of a gradle based Android project. This is done using the Android's Lint tool. Results are passed out as tables in markdown. - Gem: danger-android_lint - URL: https://github.com/loadsmart/danger-android_lint ・ ・ ・
公開したプラグイン
僕が作ったプラグインも掲載されています。 http://danger.systems/plugins/slack.html
message や fail などの内容をSlackに通知するプラグインです。 DangerはGitHub上に HTML 形式でコメントしてくれるので、 GitHub の Slack 連携では HTML は表現されません。 対策としてHTMLコメントでそれぞれの数を表示してくれているのですが微妙な感じ。
プラグインでは内容も表示し、色によって error などわかるようにしました。
地味にチャンネルやメンバー一覧を取得するメソッドも用意しています。 サクッと指摘内容をSlackに通知したい場合は使ってみてください。 https://github.com/duck8823/danger-slack