-
-
Save djburdick/5104d15f612c15dde65f to your computer and use it in GitHub Desktop.
# 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/**/*" | |
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
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
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
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
CircleCI already detects rspec. Rather than running it from within rspec, just tell them you want it run as an additional test command.
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 dorspec spec/
and run everything in one shot).