RuboCop in the pipeline

The first run

RuboCop is the Ruby linter: it reads the style guide and points at code that will annoy the next reader. The first run on the course project is the normal first run on any project: it fails.

Install the tool

gem install rubocop

13 gems installed

Run it in the project folder

rubocop

Inspecting 4 files
CCCC

4 files inspected, 26 offenses detected, 25 offenses autocorrectable

Four letters, one per file: C means offences, a dot means clean. All 26 are style, none is a bug, and 25 of them RuboCop can fix by itself. The cops behind them:

The pipeline task from lesson 54 now stops at the lint step:

bundle exec rake lint

rake aborted!
Command failed with status (1): [rubocop]

That is the gate working. A pipeline must not go green on a project with 26 offences, so the next four sections make the run clean before the lint task joins the pipeline.

Put RuboCop in the Gemfile

The command above worked because this image has RuboCop installed globally. The project does not know about it: with the local bundle from the previous lesson, rubocop would not be found at all. A tool that the pipeline runs belongs in the Gemfile, and it belongs in a group the test image can leave out:

source "https://rubygems.org" gem "minitest", "~> 5.20" gem "minitest-reporters", "~> 1.6" gem "rake", "~> 13.0" group :development do gem "rubocop", require: false end

require: false matters: Bundler then installs the gem without loading it at boot, which keeps the test run free of a tool that nobody needs while tests run. The development group matters more: the test image in two lessons (Ruby in Docker images) installs the bundle without it, so RuboCop and its dependencies never enter the image.

The config file

Two of the offences are decisions, not mistakes: this course uses double quotes and does not want a frozen-string comment in every file. Write the decisions down in .rubocop.yml; the rest of the file switches off two cops that do not fit a teaching project.

AllCops: TargetRubyVersion: 3.4 NewCops: enable SuggestExtensions: false Style/StringLiterals: EnforcedStyle: double_quotes Style/StringLiteralsInInterpolation: EnforcedStyle: double_quotes Style/FrozenStringLiteralComment: Enabled: false Style/Documentation: Enabled: false Metrics/MethodLength: Max: 15

TargetRubyVersion tells the parser which syntax to accept. NewCops: enable turns on checks added in newer releases so the editor and the pipeline agree, and SuggestExtensions: false silences the tip about extensions for a project that does not use Rails. The last three blocks are the project's own choices, written where the next reader can see them.

Fix the code

One offence is neither style nor preference: the empty string in the interpolation. The list method builds the same string in a clearer way with a conditional expression, and the Rakefile uses the symbol array form:

def list @items.each_with_index.map do |item, index| "#{index + 1}. #{item[:title]}#{" (done)" if item[:done]}" end end

desc "Run the whole pipeline" task ci: %i[test lint]

The tests still pass after the edit: the string is identical for a done and an undone item, and the expression says what the ternary said with less punctuation.

The clean run

Lint alone

bundle exec rubocop

Inspecting 4 files
....

4 files inspected, no offenses detected

The pipeline task

bundle exec rake ci

Run options: --seed 40531 # Running: ... Finished in 0.001516s, 1979.0916 runs/s, 2638.7887 assertions/s. 3 runs, 4 assertions, 0 failures, 0 errors, 0 skips rubocop Inspecting 4 files .... 4 files inspected, no offenses detected

The test task runs first, the lint task second, and Rake stops at the first failure. The two clean outputs above are the whole pipeline: tests and style, one command.

What to watch for

Turn the linter on in the pipeline only after the project is clean. rubocop --auto-correct fixes most style offences in one pass; read the diff before committing it, because a whitespace fix can hide a behaviour change in a long line.

Keep the config in the repository and pin the gem. A new RuboCop release adds cops, and NewCops: enable makes that intentional: the pipeline goes red, a person reads the new rule and either fixes the code or writes the exception down.

Next: Test reports a pipeline can read

Article author: Arthur Isaev