自己紹介
サトウリョウスケ
-
株式会社フィードフォース(Feedforce Inc.)
- ソーシャルPLUS
- バックエンド開発
- 開発リーダー
プログラム歴
- 16 ~ 25 歳: C / C++
- 25 ~ 29 歳: C#, Oracle, Java, COBOL
- 29 ~ 34 歳: Ruby on Rails, MySQL, TypeScript
今日のお題
RubocopChallenger について紹介させて下さい
RubocopChallenger とは
動作
CircleCI と組み合わせて、以下のフローを週 3 回(火・水・木)夜間バッチで実行する。
- プロダクトの .rubocop_todo.yml を読み込む
- 自動修復可能なルールを 1 つ取り出す
- 自動修復を実行
- Pull Request を作成 ← クリック
Circle CI で使う場合
.circleci/config.yml
の書き方例
jobs:
rubocop_challenge:
docker:
- image: circleci/ruby:2.6-node-browsers
working_directory: ~/repo
steps:
- checkout
- run:
name: Rubocop Challenge
command: |
bundle install
bundle exec rubocop_challenger go \
--email=challenger@example.com \
--name='rubocop challenger' \
--template='.circleci/rubocop_challenge_template.md.erb' \
--labels='rubocop challenge' 'in progress'
workflows:
version: 2
challenge:
triggers:
- schedule:
cron: "30 23 * * 1,2,3" # 8:30am every Tuesday, Wednsday and Thursday (JST)
filters:
branches:
only:
- master
jobs:
- rubocop_challenge
何が嬉しいの
- 古いプロダクトには違反した書き方がたくさんある
- 弊社では 2012 年ローンチのプロダクトに 2017/02 にようやく RuboCop を導入した
- 最初から RuboCop 使ってるプロダクトだと大丈夫だけど
- 一気に自動修復するとぶっ壊れる可能性がある
- 毎日 1 つずつ修復してくれるから確認しやすい
RubocopChallenger の功績
.rubocop_todo.yml の変化
今後の予想
順調に行けば 6 月までに片付く
ちなみに導入前の様子
RubocopChallenger の中身
動作 (再掲)
以下のフローを週 3 回(火・水・木)夜間バッチで実行する。
- プロジェクトの .rubocop_todo.yml を読み込む
- 自動修復可能なルールを 1 つ取り出す
- 自動修復を実行
- Pull Request を作成
最初のスクリプトバージョン
# Commits on Sep 11, 2018
AUTO_CORRECTABLE = /# Offense count: (\d+)\n# Cop supports --auto-correct\./
def empty_line?(prev_char, char)
prev_char == "\n" && char == "\n"
end
def extract_rule_title(string)
string =~ /^([^# ].+):$/
Regexp.last_match(1)
end
def extract_auto_correcable_rule
buff = ''
char = ''
result = []
file = open '.rubocop_todo.yml'
loop do
prev_char = char
char = file.getc
break if char.nil? # EOF
buff << char
next unless empty_line?(prev_char, char)
if buff =~ AUTO_CORRECTABLE
title = extract_rule_title(buff)
result << [Regexp.last_match(1).to_i, buff.dup, title]
end
buff = ''
end
result.sort_by! { |r| r[0] }
end
result = extract_auto_correcable_rule
target_rule =
if ARGV[0] == 'min'
result.first
else
result.last
end
puts target_rule[2]
current_data = File.read('.rubocop_todo.yml')
File.write('.rubocop_todo.yml', current_data.sub(target_rule[1], ''))
ちなみに今のバージョンはもっとスマートです
現在のバージョン
def extract_rubocop_rules
File
.read(rubocop_todo_file_path) # .rubocop_todo.yml を読み込む
.split(/\n{2,}/) # 2つ以上連続する改行で区切って配列にする
.map! { |content| Rule.new(content) } # Rule クラスで初期化
.reject! { |rule| invalid?(rule) } # 扱えないルールを除外する
.sort! # Offense Count でソートする
end
.rubocop_todo.yml の一部
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Layout/SpaceBeforeFirstArg:
Exclude:
- 'spec/models/short_uri_spec.rb'
# Offense count: 6
# Cop supports --auto-correct.
Layout/SpaceInsideArrayPercentLiteral:
Exclude:
- 'lib/extra/crawler/html_document.rb'
- 'spec/models/csv_manager/user_list_spec.rb'
今後やりたいこと
-
Auto-correct 出来なかった場合に ignore リストにルールを追加する- v1.2.0 で対応済み
-
--safe-auto-correct
のサポート - PrCreater を別 gem として切り出す
- GitHub App に対応する
Auto-correct 出来なかった場合に ignore リストにルールを追加する
RuboCop の中には、完全に auto-correct に対応していないルールがある。
# Style/Semicolon の例
# 行末に ; が存在する場合以外は auto-correct できない
puts 'hoge'; # => auto-correct される
puts 'fuga'; puts 'piyo' # => auto-correct されない
こういう場合は ignore リストに Style/Semicolon
を追加して、次回以降は対象にしないように したい。
▶︎ v1.2.0
で対応しました
--safe-auto-correct
のサポート
コマンドオプションに追加したい。
つっつきボイス:「たまたまRubocopの話題が続きました」「Rubocopにこういうオプションがあるのね↓」「安全でないcopがあるという話を追ってるようです」
# 同記事より # 安全なcopだけを実行 $ rubocop --safe # 安全なオートコレクトだけを実行 $ rubocop --safe-auto-correct # 安全なcopだけを実行してから安全なオートコレクトだけを実行 $ rubocop --safe --safe-auto-correct
PrCreater を別 gem として切り出す
RubocopChallenger 内部で使っている GitHub に Pull Request を作成する class が割と便利なので gem にしたい。
ENV['GITHUB_ACCESS_TOKEN'] = "xxx"
pr_creater = PrCreater.new(branch: "update/v#{version}")
pr_creater.commit 'Update version' do
File.write('lib/rubocop_challenger/version.rb', <<~VERSION)
# frozen_string_literal: true
module RubocopChallenger
VERSION = '#{version}'
end
VERSION
end
pr_creater.commit 'Run $ bundle update' do
`bundle update`
end
pr_creater.create_pr(title: "Update v#{version}", body: '', base: 'master')
GitHub App に対応する
- 一言で言うと Renovate みたいな GitHub App にしたい
- Gemfile に追加したり .circleci/config.yml を編集する必要がなくなる
会社のブログ
まだ .rubocop_todo.yml で消耗してるの? - Feedforce Developer Blog