forked from rubocop/rubocop
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolve: rubocop#10570. This cop requires/forbids version specifications or a commit reference for gem dependency in gemspec. ## example ```ruby # EnforcedStyle: required (default) # bad Gem::Specification.new do |spec| spec.add_dependency 'rubocop' end # good Gem::Specification.new do |spec| spec.add_dependency 'rubocop', '~> 1.28' end ``` ```ruby # EnforcedStyle: forbidden # bad Gem::Specification.new do |spec| spec.add_dependency 'rubocop', '~> 1.28' end # good Gem::Specification.new do |spec| spec.add_dependency 'rubocop' end ```
- Loading branch information
Showing
7 changed files
with
878 additions
and
1 deletion.
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
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 @@ | ||
* [#10570](https://github.com/rubocop/rubocop/issues/10570): Add new `Gemspec/DependencyVersion` cop. ([@nobuyo][]) |
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,156 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Gemspec | ||
# Enforce that gem dependency version specifications or a commit reference (branch, | ||
# ref, or tag) are either required or forbidden. | ||
# | ||
# @example EnforcedStyle: required (default) | ||
# | ||
# # bad | ||
# Gem::Specification.new do |spec| | ||
# spec.add_dependency 'parser' | ||
# end | ||
# | ||
# # bad | ||
# Gem::Specification.new do |spec| | ||
# spec.add_development_dependency 'parser' | ||
# end | ||
# | ||
# # good | ||
# Gem::Specification.new do |spec| | ||
# spec.add_dependency 'parser', '>= 2.3.3.1', '< 3.0' | ||
# end | ||
# | ||
# # good | ||
# Gem::Specification.new do |spec| | ||
# spec.add_development_dependency 'parser', '>= 2.3.3.1', '< 3.0' | ||
# end | ||
# | ||
# @example EnforcedStyle: forbidden | ||
# | ||
# # bad | ||
# Gem::Specification.new do |spec| | ||
# spec.add_dependency 'parser', '>= 2.3.3.1', '< 3.0' | ||
# end | ||
# | ||
# # bad | ||
# Gem::Specification.new do |spec| | ||
# spec.add_development_dependency 'parser', '>= 2.3.3.1', '< 3.0' | ||
# end | ||
# | ||
# # good | ||
# Gem::Specification.new do |spec| | ||
# spec.add_dependency 'parser' | ||
# end | ||
# | ||
# # good | ||
# Gem::Specification.new do |spec| | ||
# spec.add_development_dependency 'parser' | ||
# end | ||
# | ||
class DependencyVersion < Base | ||
include ConfigurableEnforcedStyle | ||
include GemspecHelp | ||
|
||
REQUIRED_MSG = 'Dependency version specification is required.' | ||
FORBIDDEN_MSG = 'Dependency version specification is forbidden.' | ||
VERSION_SPECIFICATION_REGEX = /^\s*[~<>=]*\s*[0-9.]+/.freeze | ||
|
||
# @!method add_dependency_method_declarations(node) | ||
def_node_search :add_dependency_method_declarations, <<~PATTERN | ||
(send | ||
(lvar #match_block_variable_name?) #add_dependency_method? ...) | ||
PATTERN | ||
|
||
# @!method includes_version_specification?(node) | ||
def_node_matcher :includes_version_specification?, <<~PATTERN | ||
(send _ #add_dependency_method? <(str #version_specification?) ...>) | ||
PATTERN | ||
|
||
# @!method includes_commit_reference?(node) | ||
def_node_matcher :includes_commit_reference?, <<~PATTERN | ||
(send _ #add_dependency_method? <(hash <(pair (sym {:branch :ref :tag}) (str _)) ...>) ...>) | ||
PATTERN | ||
|
||
def on_new_investigation | ||
return if processed_source.blank? | ||
|
||
add_dependency_method_nodes.each do |node| | ||
next if allowed_gem?(node) | ||
|
||
if offense?(node) | ||
add_offense(node) | ||
opposite_style_detected | ||
else | ||
correct_style_detected | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def allowed_gem?(node) | ||
allowed_gems.include?(node.first_argument.value) | ||
end | ||
|
||
def allowed_gems | ||
Array(cop_config['AllowedGems']) | ||
end | ||
|
||
def message(range) | ||
gem_specification = range.source | ||
|
||
if required_style? | ||
format(REQUIRED_MSG, gem_specification: gem_specification) | ||
elsif forbidden_style? | ||
format(FORBIDDEN_MSG, gem_specification: gem_specification) | ||
end | ||
end | ||
|
||
def match_block_variable_name?(receiver_name) | ||
gem_specification(processed_source.ast) do |block_variable_name| | ||
return block_variable_name == receiver_name | ||
end | ||
end | ||
|
||
def add_dependency_method?(method_name) | ||
method_name.to_s.end_with?('_dependency') | ||
end | ||
|
||
def add_dependency_method_nodes | ||
add_dependency_method_declarations(processed_source.ast) | ||
end | ||
|
||
def offense?(node) | ||
required_offense?(node) || forbidden_offense?(node) | ||
end | ||
|
||
def required_offense?(node) | ||
return unless required_style? | ||
|
||
!includes_version_specification?(node) && !includes_commit_reference?(node) | ||
end | ||
|
||
def forbidden_offense?(node) | ||
return unless forbidden_style? | ||
|
||
includes_version_specification?(node) || includes_commit_reference?(node) | ||
end | ||
|
||
def forbidden_style? | ||
style == :forbidden | ||
end | ||
|
||
def required_style? | ||
style == :required | ||
end | ||
|
||
def version_specification?(expression) | ||
expression.match?(VERSION_SPECIFICATION_REGEX) | ||
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
Oops, something went wrong.