はじめに
個人開発でRubyを使って開発しています。
静的解析にはもちろんrubocopを使っているのですが、ローカルで実行するのみでした。
この作業をCIでも実行したいと思い、個人で触ったことのなかったGitHub ActionsとRun rubocop with reviewdogを使ってみることにしました。
GitHub Actionsとは
公式からの説明は以下のとおりです。
GitHub Actions は、ソフトウェア開発ライフサイクル内のタスクを自動化するのに役立ちます。 GitHub Actions はイベント駆動型で、指定されたイベントが発生した後に一連のコマンドを実行できます。 たとえば、誰かがリポジトリのプルリクエストを作成するたびに、ソフトウェアテストスクリプトを実行するコマンドを自動的に実行できます。
ざっとまとめると、GitHubに備わっているIssueやPull Requestなどの機能をトリガーにして、ビルド、テスト、デプロイなどを実行できるツールとなります。
Run rubocop with reviewdog
GitHub Actionsでは、アクションとしてRun rubocop with reviewdogが提供されています。
これは、Pull Requestが作成されたときに以下2つを実行してくれるアクションです。
今回、このアクションを使って静的解析とレビューを行うようにしました。
Run rubocop with reviewdogを使ったGitHub Actionsのyamlは以下のとおりです。
name: Static Analysis
on: pull_request
jobs:
rubocop:
name: Run rubocop
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: rubocop
uses: reviewdog/action-rubocop@v1
with:
rubocop_version: 0.93.0
github_token: ${{ secrets.GITHUB_TOKEN }}
rubocop_flags: --config backend/.rubocop.yml backend/
rubocop_extensions: meowcop
reporter: github-pr-check
Run rubocop with reviewdogにはオプションが指定可能です。
ここで指定したオプションの一部について説明します。
なお、オプション一覧については、Run rubocop with reviewdogのREADMEを確認してください。
-
rubocop_flags
rubocopを実行する際の引数を指定できます。
ここでは.rubocop.ymlの指定と、rubocopを実行する場所を指定しています。 -
rubocop_extensions
rubocopのエクステンションをバージョンの指定と一緒に指定できます。デフォルトではrubocop-rails
、rubocop-performance
、rubocop-rspec
、rubocop-i18n
、rubocop-rake
の最新バージョンが入るようです。
ここではもともと指定せずに実行していましたが、後述するact実行時に、meowcopがないと怒られていたので、ここで指定しています。 -
reporter
reviewdogのオプションであるreporterを使えます。デフォルトではgithub-pr-checkを使用します。
act
yamlを作成していくにあたり動作確認と修正を繰り返す必要があります。
GitHub上で確認する方法は、毎回commit、pushしなければならずフィードバックに時間がかかります。
そのためローカルで実行できるツールはないかと探したところ、actがありました。
actはGitHub Actionsをローカルで実行できるGolangのツールです。
README通り、brewでインストールします。
$ brew install act
実行方法は、プロジェクトの.githubフォルダーがあるディレクトリで、actを実行するだけです。
$ act
actはデフォルトで、pushイベントがあるワークフローを実行します。
特定のイベントを実行したい場合は、引数にそのイベント名をセットすることで実行できます。
例: Pull Requestイベントのワークフローを実行したい場合
$ act pull_request
またローカルでのGitHub Runnerは、ワークフローのruns-onのイメージに対して、act上でイメージが決まっています。
現在はruns-onがubuntu-latest
、ubuntu-18.04
の場合はnode:12.6-buster-slim
、ubuntu-16.04
の場合はnode:12.6-stretch-slim
のイメージが使用されます。(なお、runs-onがwindowsやmacosに対しては、actはサポートしていないようです。)
GitHub Runnerのイメージを指定する場合は、-P runs-onのイメージ名=actでサポートしているイメージ名
としてください。
$ act -P ubuntu-latest=nektos/act-environments-ubuntu:18.04
今回は、ワークフローのイメージとactで実行するイメージを合わせたかったので、イベント名(pull_request)とイメージを指定し、実行しました。
$ act pull_request -P ubuntu-latest=nektos/act-environments-ubuntu:18.04
act実行時のエラー
actを実行するとBroken pipe @ io_writev - <STDOUT>
といったエラーが出てしまいました。
$ act pull_request -P ubuntu-latest=nektos/act-environments-ubuntu:18.04
[Static Analysis/Run rubocop] 🚀 Start image=nektos/act-environments-ubuntu:18.04
[Static Analysis/Run rubocop] 🐳 docker run image=nektos/act-environments-ubuntu:18.04 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Static Analysis/Run rubocop] 🐳 docker cp src=/Users/masatoyamashita/Data/GitHub/WeatherReport/. dst=/github/workspace
[Static Analysis/Run rubocop] ⭐ Run actions/checkout@v2
[Static Analysis/Run rubocop] ✅ Success - actions/checkout@v2
[Static Analysis/Run rubocop] ⭐ Run rubocop
[Static Analysis/Run rubocop] ☁ git clone 'https://github.com/reviewdog/action-rubocop' # ref=v1
[Static Analysis/Run rubocop] 🐳 docker build -t act-reviewdog-action-rubocop-v1:latest /Users/masatoyamashita/.cache/act/reviewdog-action-rubocop@v1
[Static Analysis/Run rubocop] 🐳 docker run image=act-reviewdog-action-rubocop-v1:latest entrypoint=[] cmd=["" "0.93.0" "meowcop" "--config backend/.rubocop.yml backend/" "rubocop" "error" "github-pr-check" "added" "false" "" "."]
| Fetching regexp_parser-1.8.2.gem
| Fetching ast-2.4.1.gem
| Fetching parser-2.7.2.0.gem
| Fetching rainbow-3.0.0.gem
| Fetching rubocop-0.93.0.gem
| Fetching parallel-1.19.2.gem
| Fetching ruby-progressbar-1.10.1.gem
| Fetching unicode-display_width-1.7.0.gem
| Fetching rubocop-ast-0.8.0.gem
| Successfully installed parallel-1.19.2
| Successfully installed ast-2.4.1
| Successfully installed parser-2.7.2.0
| Successfully installed rainbow-3.0.0
| Successfully installed regexp_parser-1.8.2
| Successfully installed rubocop-ast-0.8.0
| Successfully installed ruby-progressbar-1.10.1
| Successfully installed unicode-display_width-1.7.0
| Successfully installed rubocop-0.93.0
| 9 gems installed
| Fetching meowcop-2.15.0.gem
| Successfully installed meowcop-2.15.0
| 1 gem installed
| reviewdog: this is not PullRequest build.
| Broken pipe @ io_writev - <STDOUT>
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/clang_style_formatter.rb:47:in `write'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/clang_style_formatter.rb:47:in `puts'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/clang_style_formatter.rb:47:in `report_line'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/clang_style_formatter.rb:30:in `report_offense'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/clang_style_formatter.rb:12:in `block in report_file'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/clang_style_formatter.rb:12:in `each'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/clang_style_formatter.rb:12:in `report_file'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/progress_formatter.rb:42:in `block in finished'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/progress_formatter.rb:41:in `each'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/progress_formatter.rb:41:in `finished'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/formatter_set.rb:33:in `block (3 levels) in <class:FormatterSet>'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/formatter_set.rb:33:in `each'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/formatter/formatter_set.rb:33:in `block (2 levels) in <class:FormatterSet>'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/runner.rb:95:in `inspect_files'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/runner.rb:47:in `run'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/cli/command/execute_runner.rb:25:in `execute_runner'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/cli/command/execute_runner.rb:17:in `run'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/cli/command.rb:11:in `run'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/cli/environment.rb:18:in `run'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/cli.rb:65:in `run_command'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/cli.rb:72:in `execute_runners'
| /usr/local/bundle/gems/rubocop-0.93.0/lib/rubocop/cli.rb:41:in `run'
| /usr/local/bundle/gems/rubocop-0.93.0/exe/rubocop:13:in `block in <top (required)>'
| /usr/local/lib/ruby/2.6.0/benchmark.rb:308:in `realtime'
| /usr/local/bundle/gems/rubocop-0.93.0/exe/rubocop:12:in `<top (required)>'
| /usr/local/bundle/bin/rubocop:23:in `load'
| /usr/local/bundle/bin/rubocop:23:in `<main>'
[Static Analysis/Run rubocop] ✅ Success - rubocop
Broken pipeについて調べると、長過ぎる出力が問題のようでした。
ログの流れから、rubocopによる指摘が多すぎるからB roken pipe
が起きているのではないかと仮定し、rubocop単体で出力される指摘を1つずつ修正していきました。
再度actを実行したところ、無事成功しました。
$ act pull_request -P ubuntu-latest=nektos/act-environments-ubuntu:18.04
[Static Analysis/Run rubocop] 🚀 Start image=nektos/act-environments-ubuntu:18.04
[Static Analysis/Run rubocop] 🐳 docker run image=nektos/act-environments-ubuntu:18.04 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Static Analysis/Run rubocop] 🐳 docker cp src=/Users/masatoyamashita/Data/GitHub/WeatherReport/. dst=/github/workspace
[Static Analysis/Run rubocop] ⭐ Run actions/checkout@v2
[Static Analysis/Run rubocop] ✅ Success - actions/checkout@v2
[Static Analysis/Run rubocop] ⭐ Run rubocop
[Static Analysis/Run rubocop] ☁ git clone 'https://github.com/reviewdog/action-rubocop' # ref=v1
[Static Analysis/Run rubocop] 🐳 docker build -t act-reviewdog-action-rubocop-v1:latest /Users/masatoyamashita/.cache/act/reviewdog-action-rubocop@v1
[Static Analysis/Run rubocop] 🐳 docker run image=act-reviewdog-action-rubocop-v1:latest entrypoint=[] cmd=["" "0.93.0" "meowcop" "--config backend/.rubocop.yml backend/" "rubocop" "error" "github-pr-check" "added" "false" "" "."]
| Fetching parallel-1.19.2.gem
| Fetching ast-2.4.1.gem
| Fetching parser-2.7.2.0.gem
| Fetching rainbow-3.0.0.gem
| Fetching regexp_parser-1.8.2.gem
| Fetching rubocop-ast-0.8.0.gem
| Fetching ruby-progressbar-1.10.1.gem
| Fetching unicode-display_width-1.7.0.gem
| Fetching rubocop-0.93.0.gem
| Successfully installed parallel-1.19.2
| Successfully installed ast-2.4.1
| Successfully installed parser-2.7.2.0
| Successfully installed rainbow-3.0.0
| Successfully installed regexp_parser-1.8.2
| Successfully installed rubocop-ast-0.8.0
| Successfully installed ruby-progressbar-1.10.1
| Successfully installed unicode-display_width-1.7.0
| Successfully installed rubocop-0.93.0
| 9 gems installed
| Fetching meowcop-2.15.0.gem
| Successfully installed meowcop-2.15.0
| 1 gem installed
| reviewdog: this is not PullRequest build.
[Static Analysis/Run rubocop] ✅ Success - rubocop
GitHub上で確認
actによるローカルの確認が終わったのでpushし、GitHub上でGitHub Actionsを走らせたところ、無事成功しました。
終わりに
GitHub Actions上でreviewdog/action-rubocopを実行しました。
またローカルで実行するためにactを利用しました。
人の手を使わず自動で静的解析を行ってくれてありがたいですね。
こういった自動化はどんどん進めていきたいです。