Как запустить Rubocop только для измененных файлов в запросе pull?

Я создал spec/lint/rubocop_spec.rb, который запускает проверку стиля Rubocop для файлов, измененных между текущей веткой и мастером. Это работает, когда я тестирую локально, но не когда тест запускается на сервере сборки Circle.ci. Я подозреваю, что это потому, что загружается только соответствующая ветка, поэтому она не находит различий между мастером. Есть ли лучший способ, чем git co master && git pull origin master? Могу ли я запросить Github API, чтобы получить список измененных файлов?

require 'spec_helper'

describe 'Check that the files we have changed have correct syntax' do
  before do
    current_sha = `git rev-parse --verify HEAD`.strip!
    files = `git diff master #{current_sha} --name-only | grep .rb`
    files.tr!("\n", ' ')
    @report = 'nada'
    if files.present?
      puts "Changed files: #{files}"

      @report = `rubocop #{files}`
      puts "Report: #{@report}"
    end
  end

  it { @report.match('Offenses').should_not be true }
end

8 ответов

Решение

Я исправил это, запросив api.github.com. Это запустит rubocop для всех файлов, которые были изменены между current_sha и главной веткой.

require 'spec_helper'

describe 'Check that the files we have changed have correct syntax' do
  before do
    current_sha = `git rev-parse --verify HEAD`.strip!
    token = 'YOUR GITHUB TOKEN'
    url = 'https://api.github.com/repos/orwapp/orwapp/compare/' \
          "master...#{current_sha}?access_token=#{token}"
    files = `curl -i #{url} | grep filename | cut -f2 -d: | grep \.rb | tr '"', '\ '`
    files.tr!("\n", ' ')
    @report = 'nada'
    if files.present?
      puts "Changed files: #{files}"

      @report = `rubocop #{files}`
      puts "Report: #{@report}"
    end
  end

  it { expect(@report.match('Offenses')).to be_falsey }
end

Вам не нужно использовать github api или даже ruby ​​(если вы не хотите обернуть ответы), вы можете просто запустить:

git fetch && git diff-tree -r --no-commit-id --name-only master@\{u\} head | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs rubocop

см. http://www.red56.uk/2017/03/26/running-rubocop-on-changed-files/ для более подробного описания этого

Я нашел https://github.com/m4i/rubocop-git который работает очень хорошо. Однако он работает на вашем git diff (опционально с --cached), поэтому он не позволяет сравнивать ветки.

Одно более простое решение:

      git diff origin/master --name-only | xargs rubocop --force-exclusion

Объяснение: я редкоmasterобновляется локально, но делаетgit fetchобновления, поэтому я хочу отличаться от этого. Я не могу получить другие предлагаемые решения с помощьюdiff-treeиorigin/masterработать.

У меня недостаточно высокой репутации, чтобы прокомментировать ответ, поэтому я публикую ответ, чтобы добавить уточнение, которое я нашел полезным:

git fetch && git diff-tree -r --no-commit-id --name-only master@\{u\} HEAD | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs bundle exec rubocop --force-exclusion

Добавление --force-exclusion заставляет RuboCop уважать объявления Exclude в своем файле конфигурации (здесь используется значение по умолчанию ./.rubocop.yml). У вас есть причина для этих заявлений, верно?!;)

Вот еще одна альтернатива, которая сравнивает текущую ветку с origin/master (должен работать с любым хостингом репо - только что попробовал на circleci с репозиторием Bitbucket). Он также проходит .rubocop.yml опция файла конфигурации (вы можете удалить эту часть, если она вам не нужна).

require 'spec_helper'

RSpec.describe 'Check that the files we have changed have correct syntax' do
  before do
    current_sha = 'origin/master..HEAD'
    @files = `git diff-tree --no-commit-id --name-only -r #{current_sha} | grep .rb`
    @files.tr!("\n", ' ')
  end

  it 'runs rubocop on changed ruby files' do
    if @files.empty?
      puts "Linting not performed. No ruby files changed."
    else
      puts "Running rubocop for changed files: #{@files}"
      result = system "bundle exec rubocop --config .rubocop.yml --fail-level warn #{@files}"
      expect(result).to be(true)
    end
  end
end

Оригинальная суть здесь: https://gist.github.com/djburdick/5104d15f612c15dde65f

Вы можете использовать https://github.com/AtakamaLLC/lint-diffs.

Он работает с любым языком в вашем репо, помимо ruby ​​(даже со сценариями bash и файлами README), и работает с любым типом системы управления версиями, а не только с git.

Таким образом, вы можете везде использовать один и тот же инструмент.

Вы должны включить расширение rubocop в своей конфигурации.

Возможно, вы могли бы использовать функцию динамической настройки CircleCI .

Существует специальное руководство о том, как выполнять определенные рабочие процессы или шаги в зависимости от того, какие файлы были изменены ( https://circleci.com/docs/using-dynamic-configuration/#execute-specific-workflows-or-steps-based-on ). -какие-файлы-модифицируются ).

Другие вопросы по тегам