LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

まだ .rubocop_todo.yml で消耗してるの?

Posted at
1 / 28

自己紹介

サトウリョウスケ

プログラム歴

  • 16 ~ 25 歳: C / C++
  • 25 ~ 29 歳: C#, Oracle, Java, COBOL
  • 29 ~ 34 歳: Ruby on Rails, MySQL, TypeScript

今日のお題


RubocopChallenger について紹介させて下さい :bow:


RubocopChallenger とは


動作 :robot:

CircleCI と組み合わせて、以下のフローを週 3 回(火・水・木)夜間バッチで実行する。

  1. :page_facing_up: プロダクトの .rubocop_todo.yml を読み込む
  2. :outbox_tray: 自動修復可能なルールを 1 つ取り出す
  3. :wrench: 自動修復を実行
  4. :envelope: Pull Request を作成 ← クリック

FireShot Capture 001 - Style_ParallelAssignment-20190321083055 by social-plus-devel · Pull R_ - github.com.png


FireShot Capture 002 - Style_ParallelAssignment-20190321083055 by social-plus-devel · Pull R_ - github.com.png


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

何が嬉しいの :information_desk_person:

  • 古いプロダクトには違反した書き方がたくさんある :confounded:
    • 弊社では 2012 年ローンチのプロダクトに 2017/02 にようやく RuboCop を導入した :cop_tone3:
    • 最初から RuboCop 使ってるプロダクトだと大丈夫だけど :upside_down:
  • 一気に自動修復するとぶっ壊れる可能性がある :skull_crossbones: :skull_crossbones: :skull_crossbones:
    • 毎日 1 つずつ修復してくれるから確認しやすい :pill: :sparkles:

RubocopChallenger の功績 :moyai:


.rubocop_todo.yml の変化 :chart_with_downwards_trend:

chart (1).png


今後の予想 :chart_with_downwards_trend:

順調に行けば 6 月までに片付く :sparkles: :hugging: :sparkles:

chart (2).png


ちなみに導入前の様子 :chart_with_upwards_trend:

chart.png


RubocopChallenger の中身 :police_car:


動作 (再掲) :robot:

以下のフローを週 3 回(火・水・木)夜間バッチで実行する。

  1. :page_facing_up: プロジェクトの .rubocop_todo.yml を読み込む
  2. :outbox_tray: 自動修復可能なルールを 1 つ取り出す
  3. :wrench: 自動修復を実行
  4. :envelope: Pull Request を作成

最初のスクリプトバージョン :nerd:

# 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], ''))

:weary:


ちなみに今のバージョンはもっとスマートです :cop_tone1: :sparkles:


現在のバージョン :surfer:

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

:point_down: .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'

今後やりたいこと :map:

  • Auto-correct 出来なかった場合に ignore リストにルールを追加する
    • v1.2.0 で対応済み :white_check_mark:
  • :four_leaf_clover: --safe-auto-correct のサポート
  • :comet: PrCreater を別 gem として切り出す
  • :apple: GitHub App に対応する

:levitate: 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 で対応しました :white_check_mark:


スクリーンショット 2019-03-26 2.50.42.png


:four_leaf_clover: --safe-auto-correct のサポート

コマンドオプションに追加したい。

つっつきボイス:「たまたまRubocopの話題が続きました」「Rubocopにこういうオプションがあるのね↓」「安全でないcopがあるという話を追ってるようです」

# 同記事より
# 安全なcopだけを実行
$ rubocop --safe

# 安全なオートコレクトだけを実行
$ rubocop --safe-auto-correct

# 安全なcopだけを実行してから安全なオートコレクトだけを実行
$ rubocop --safe --safe-auto-correct

週刊Railsウォッチ(20181112)より


:comet: 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')

:apple: GitHub App に対応する

  • 一言で言うと Renovate みたいな GitHub App にしたい
  • Gemfile に追加したり .circleci/config.yml を編集する必要がなくなる

会社のブログ

まだ .rubocop_todo.yml で消耗してるの? - Feedforce Developer Blog


おしまい :wave:

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up