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:
- Style/StringLiterals: the course writes double quotes, the default wants single.
- Style/StringLiteralsInInterpolation: the same question inside #{...}.
- Style/SymbolArray: on task ci: [:test, :lint], which wants %i[test lint].
- Style/Documentation: on class Todo, which has no comment above it.
- Style/EmptyStringInsideInterpolation: on #{item[:done] ? " (done)" : ""}, where the empty string branch can be written as a conditional expression.
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