概要
GitHub上で「PRの変更内容に特定のキーワードが含まれていたら、変更された箇所にコメントをつける」
というのを調べてやり方がわかったのでメモとして書いていきます。
GitHubActionsやDanger Pluginについて知っているかたは、
「PRのコードにインラインコメントをつける」まで飛ばしてください。
DangerはPullRequestの内容を自動でチェックしてコメントをつけてくれるOSSです。
この記事はDangerのセットアップや基本的な使い方については記載はしていないので、「Dangerについて詳しく知りたい!」というかたは是非ほかのかたの記事を探してみてください。
サンプル
Rubyは不慣れなのであまり良いコードではないですが確認サンプルを作ってあります。
リポジトリ: https://github.com/rnishimu22001/DangerPlayground
動作のサンプルPR: https://github.com/rnishimu22001/DangerPlayground/pull/2
利用環境
「GitHub.com + GitHubActions + Danger」
DangerはRuby版です。
GitHubActionsの設定
こちらの記事を参考にさせていただきました
https://qiita.com/tarumzu/items/87e4d9801d0a413c80f1
PRを作成したときにGitHubActionsが実行されるように作っています。
# どのタイミングで実行するか?今回はPRがopenされたときにこのActionを実行させる。
on: pull_request
jobs:
build:
runs-on: ubuntu-latest
steps:
# Actionsで必要なセットアップをしていく
- uses: actions/checkout@v1
- name: Setup Ruby for use with actions
uses: actions/setup-ruby@v1.0.0
with:
version: '2.6'
- name: Install Danger
run: |
gem install bundler
bundle install
# Dangerの実行
- name: Run Danger
env:
# Dangerがコメントするために必要?
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: danger
Danger Pluginを作成する
Danger Pluginとしてclassを作成すればDangerの機能をあまり考ずに使えそうなので今回はDanger Pluginで作成しました。
# code_review.rbのファイル内
module Danger
class CodeReview < Plugin
def code_review
# コードチェックに関する実装を記述...
end
end
end
Dangerfileファイルへの記述はこんな感じです。
# importのパスは適宜変えてください。
danger.import_plugin("./code_review.rb")
code_review.code_review
変更されたファイルパスを取得する
リファレンスによるとgit.added_files
などで追加されたファイル、修正されたファイルのパスが取れます。
Paths for files that were added during the diff
added_files FileList
Paths for files that were removed during the diff
deleted_files FileList
Paths for files that changed during the diff
modified_files FileList
各ファイルを取得して変更されたファイルリストを作っていきます。
# gitモジュールから変更されたファイルパスを取得する
file_paths = git.modified_files + git.added_files
gitの変更情報を取得する
今回はあくまで動作確認のためなのでコード差分の情報を抜き出す簡易なものを作っていきます。
ライブラリとかあればそっちを使うほうが賢いです。
今回はDangerが提供してくれているdiff_for_file
を使って作っていきます。
1ファイルずつのdiffを見れるので制御がしやすいです。
Details for a specific file in this diff
diff_for_file Git::Diff::DiffFile
git diffの中身をパースする
ファイルの差分情報の
git.diff_for_file(変更のあったファイルパス).patch
を見てみると以下のようになります。
diff --git a/hello.rb b/hello.rb
index 15aaec7..2e57c3c 100644
--- a/hello.rb
+++ b/hello.rb
@@ -1 +1,2 @@
-puts "hello world"
+# TODO: 後で直す
+puts "hello world!!!"
余談ですがいつも見てるこのgit diff
のフォーマットはUnified Format
というらしいです。
https://www.gnu.org/software/diffutils/manual/html_node/Unified-Format.html
行の種類 | 対応しそうな正規表現 |
---|---|
ファイルの変更情報 | ^@@ |
追加された or 修正された行 | ^+ |
削除された or 修正前の行 | ^- |
以上の内容を元に愚直にパースして変更行の情報を抜き出していきます。
https://github.com/rnishimu22001/DangerPlayground/blob/master/code_review.rb#L26-L65
パースをする際に手こずったことですが、Danger
からPRにコメントをつける場合に削除された行につけれませんでした。
PRで削除された行は行としてカウントされないようなので気をつけてください。
削除行にコメントつける方法があれば教えて欲しいです
PRのコードにインラインコメントをつける
知らなかったんですがDangerを使う際によく使うwarn
やmessage
などには引数が追加できるようです
https://github.com/danger/danger/blob/master/lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb#L63
file_path
: コメントしたいファイルのパス
line
: コメントを残したい行
# 指定したファイルの行にコメントを残す
warn("コメントしたいメッセージ", file: "./hogehoge.rb", line: 1)
これを実際に実行をしてみてコメントをつけることができました
やりのこしたこと
以下のパターンだとクラッシュしてしまうので変更情報のバリデーションを追加する必要があります。
- 画像などの形式の違うファイル
- リネームのみで変更情報しかないファイル
ほかにも[git diffの中身をパースする](# git diffの中身をパースする)で記載したパターンだとObjective-Cのクラスメソッドも引っかかったりとたくさん穴がありそうなのでライブラリを使うのが良さそうです。
また、自前で作らなくてもキーワード検知のDanger Pluginは探せばありそうな気がしています。