Skip to content

Instantly share code, notes, and snippets.

@djburdick
Created November 11, 2014 20:18
Show Gist options
  • Save djburdick/5104d15f612c15dde65f to your computer and use it in GitHub Desktop.
Save djburdick/5104d15f612c15dde65f to your computer and use it in GitHub Desktop.
Run rubocop with circleci
# In spec_helper.rb
RSpec.configure do |config|
....
rubocop_output = `rubocop`
print rubocop_output
fail "RuboCop Errors" unless rubocop_output.match(/files inspected, no offenses detected/)
end
# In .rubocop.yml
# Make sure to exclude unused dirs or it'll run 10,000+ files in circleci
AllCops:
Exclude:
- "db/**/*"
- "tmp/**/*"
- "vendor/**/*"
- "bin/**/*"
- "log/**/*"
@kylev
Copy link

kylev commented Feb 18, 2015

CircleCI already detects rspec. Rather than running it from within rspec, just tell them you want it run as an additional test command.

test:
  post:
    - bundle exec rubocop

Your method does a full rubocop run from within the configuration step of any and every rspec run. That's both conceptually unexpected (test inside configure?) and likely to annoy developers (just running one test always also runs rubocop?).

Another approach you might consider is to create a spec/lint/rubocop_spec.rb which runs it and asserts successful completion. That turns Rubocop runs into a test (rather than stuffing into configure steps), but doesn't rely on a developer knowing that CircleCI will be running additional commands (they can do rspec spec/ and run everything in one shot).

@stabenfeldt
Copy link

spec/lint/rubocop_spec.rb was a good idea.
I created mine so it only checks the files that has been changed:

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", ' ')
    puts "Change files: #{files}"

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

  it { @report.match('Offenses').should be false }
end

@nicobrenner
Copy link

Thank you @stabenfeldt for the excellent snippet. Below is an adaptation that compares the current branch with origin/master to avoid running into issues if the master branch is not present in the test environment.

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

@apotema
Copy link

apotema commented Aug 2, 2018

This version worked better for me.

require "spec_helper"

RSpec.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 = `rubocop #{files}`
    puts "Report: #{@report}"
  end

  it { expect(@report.match("Offenses")).to be_nil, "Rubocop offenses found.\n#{@report}" }
end

@xhocquet
Copy link

I spent a while getting this to my liking. I thought that linting did not belong inside RSpec. By splitting it out, one is able to identify that the linter specifically failed via CircleCI steps, as well as leveraging parallelism without having to spin up RSpec for all linters.

I was inspired by this article http://takemikami.com/2018/01/30/RubocopPullRequestCI.html, though I had to make significant changes in syntax to make it work on CircleCI 2.0

Take a look! https://gist.github.com/xhocquet/4e07f430efd186ab69828961bdd7b7a3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment