forked from rubocop/rubocop
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Fix rubocop#9580] Add New Cop to Enforce Bundler Gem filename
Add a new cop which enforces which bundler gem filename to use. By default, enforces Gemfile and its related Gemfile.lock file. Alternatively, setting RequiresGemfile to false enforces gems.rb and its related gems.locked file.
- Loading branch information
1 parent
ed7aa5c
commit 96cb9c5
Showing
5 changed files
with
183 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* [#9580](https://github.com/rubocop/rubocop/issues/9580): Add a new cop that enforces which bundler gem file to use. ([@gregfletch][]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Bundler | ||
# This cop verifies that a project contains Gemfile or gems.rb file and correct | ||
# associated lock file based on the configuration. | ||
# | ||
# @example RequiresGemfile: true (default) | ||
# # bad | ||
# Project contains gems.rb and gems.locked files | ||
# | ||
# # bad | ||
# Project contains Gemfile and gems.locked file | ||
# | ||
# # good | ||
# Project contains Gemfile and Gemfile.lock | ||
# | ||
# @example RequiresGemfile: false | ||
# # bad | ||
# Project contains Gemfile and Gemfile.lock files | ||
# | ||
# # bad | ||
# Project contains gems.rb and Gemfile.lock file | ||
# | ||
# # good | ||
# Project contains gems.rb and gems.locked files | ||
class GemFilename < Base | ||
include RangeHelp | ||
|
||
MSG_GEMFILE_REQUIRED = 'gems.rb file was found but Gemfile is required.' | ||
MSG_GEMS_RB_REQUIRED = 'Gemfile was found but gems.rb file is required.' | ||
MSG_GEMFILE_MISMATCHED = 'Expected a Gemfile.lock with Gemfile but found gems.locked file.' | ||
MSG_GEMS_RB_MISMATCHED = 'Expected a gems.locked file with gems.rb but found Gemfile.lock.' | ||
GEMFILE_REQUIRED_CONFIG = 'RequiresGemfile' | ||
GEMFILE_FILES = %w[Gemfile Gemfile.lock].freeze | ||
GEMS_RB_FILES = %w[gems.rb gems.locked].freeze | ||
|
||
def on_new_investigation | ||
file_path = processed_source.file_path | ||
return if expected_gemfile?(file_path) | ||
|
||
register_offense(processed_source, file_path) | ||
end | ||
|
||
private | ||
|
||
def register_offense(processed_source, file_path) | ||
register_gemfile_offense(processed_source, file_path) if gemfile_required? | ||
register_gems_rb_offense(processed_source, file_path) unless gemfile_required? | ||
end | ||
|
||
def register_gemfile_offense(processed_source, file_path) | ||
message = case file_path | ||
when 'gems.rb' | ||
MSG_GEMFILE_REQUIRED | ||
when 'gems.locked' | ||
MSG_GEMFILE_MISMATCHED | ||
end | ||
|
||
return if message.nil? | ||
|
||
add_offense(source_range(processed_source.buffer, 1, 0), message: message) | ||
end | ||
|
||
def register_gems_rb_offense(processed_source, file_path) | ||
message = case file_path | ||
when 'Gemfile' | ||
MSG_GEMS_RB_REQUIRED | ||
when 'Gemfile.lock' | ||
MSG_GEMS_RB_MISMATCHED | ||
end | ||
|
||
return if message.nil? | ||
|
||
add_offense(source_range(processed_source.buffer, 1, 0), message: message) | ||
end | ||
|
||
def expected_gemfile?(file_path) | ||
(gemfile_required? && GEMFILE_FILES.include?(file_path)) || | ||
(!gemfile_required? && GEMS_RB_FILES.include?(file_path)) | ||
end | ||
|
||
def gemfile_required? | ||
cop_config[GEMFILE_REQUIRED_CONFIG] | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Bundler::GemFilename, :config do | ||
shared_examples_for 'invalid gem file' do |message| | ||
it 'registers an offense' do | ||
offenses = _investigate(cop, processed_source) | ||
|
||
expect(offenses.size).to eq(1) | ||
expect(offenses.first.message).to eq(message) | ||
end | ||
end | ||
|
||
shared_examples_for 'valid gem file' do | ||
it 'does not register an offense' do | ||
offenses = _investigate(cop, processed_source) | ||
|
||
expect(offenses.size).to eq(0) | ||
end | ||
end | ||
|
||
context 'with default configuration' do | ||
let(:source) { 'print 1' } | ||
let(:processed_source) { parse_source(source) } | ||
|
||
before { allow(processed_source.buffer).to receive(:name).and_return(filename) } | ||
|
||
context 'with gems.rb file path' do | ||
let(:filename) { 'gems.rb' } | ||
|
||
include_examples 'invalid gem file', 'gems.rb file was found but Gemfile is required.' | ||
end | ||
|
||
context 'with gems.locked file path' do | ||
let(:filename) { 'gems.locked' } | ||
|
||
include_examples 'invalid gem file', | ||
'Expected a Gemfile.lock with Gemfile but found gems.locked file.' | ||
end | ||
|
||
context 'with Gemfile file path' do | ||
let(:filename) { 'Gemfile' } | ||
|
||
include_examples 'valid gem file' | ||
end | ||
|
||
context 'with Gemfile.lock file path' do | ||
let(:filename) { 'Gemfile.lock' } | ||
|
||
include_examples 'valid gem file' | ||
end | ||
end | ||
|
||
context 'with RequiresGemfile set to false' do | ||
let(:source) { 'print 1' } | ||
let(:processed_source) { parse_source(source) } | ||
let(:cop_config) { { 'RequiresGemfile' => false } } | ||
|
||
before { allow(processed_source.buffer).to receive(:name).and_return(filename) } | ||
|
||
context 'with Gemfile file path' do | ||
let(:filename) { 'Gemfile' } | ||
|
||
include_examples 'invalid gem file', 'Gemfile was found but gems.rb file is required.' | ||
end | ||
|
||
context 'with Gemfile.lock file path' do | ||
let(:filename) { 'Gemfile.lock' } | ||
|
||
include_examples 'invalid gem file', | ||
'Expected a gems.locked file with gems.rb but found Gemfile.lock.' | ||
end | ||
|
||
context 'with gems.rb file path' do | ||
let(:filename) { 'gems.rb' } | ||
|
||
include_examples 'valid gem file' | ||
end | ||
|
||
context 'with gems.locked file path' do | ||
let(:filename) { 'gems.locked' } | ||
|
||
include_examples 'valid gem file' | ||
end | ||
end | ||
end |