Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new Gemspec/DateAssignment cop #9496

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/new_add_new_gemspec_date_assignment_cop.md
@@ -0,0 +1 @@
* [#9496](https://github.com/rubocop-hq/rubocop/pull/9496): Add new `Gemspec/DateAssignment` cop. ([@koic][])
7 changes: 7 additions & 0 deletions config/default.yml
Expand Up @@ -203,6 +203,13 @@ Bundler/OrderedGems:

#################### Gemspec ###############################

Gemspec/DateAssignment:
Description: 'Checks that `date =` is not used in gemspec file, it is set automatically when the gem is packaged.'
Enabled: pending
VersionAdded: '<<next>>'
Include:
- '**/*.gemspec'
Comment on lines +210 to +211
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will include gemspecs in vendored gems, which may have the date set but be out of the control of the developer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. However this setting is the same as other Gemspec department's cops. These cops hasn't received feedback on that issue, so I think we see reactions with this setting.


Gemspec/DuplicatedAssignment:
Description: 'An attribute assignment method calls should be listed only once in a gemspec.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -152,6 +152,7 @@
require_relative 'rubocop/cop/bundler/insecure_protocol_source'
require_relative 'rubocop/cop/bundler/ordered_gems'

require_relative 'rubocop/cop/gemspec/date_assignment'
require_relative 'rubocop/cop/gemspec/duplicated_assignment'
require_relative 'rubocop/cop/gemspec/ordered_dependencies'
require_relative 'rubocop/cop/gemspec/required_ruby_version'
Expand Down
56 changes: 56 additions & 0 deletions lib/rubocop/cop/gemspec/date_assignment.rb
@@ -0,0 +1,56 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Gemspec
# This cop checks that `date =` is not used in gemspec file.
# It is set automatically when the gem is packaged.
#
# @example
#
# # bad
# Gem::Specification.new do |spec|
# s.name = 'your_cool_gem_name'
# spec.date = Time.now.strftime('%Y-%m-%d')
# end
#
# # good
# Gem::Specification.new do |spec|
# s.name = 'your_cool_gem_name'
# end
#
class DateAssignment < Base
include RangeHelp
extend AutoCorrector

MSG = 'Do not use `date =` in gemspec, it is set automatically when the gem is packaged.'

def_node_matcher :gem_specification, <<~PATTERN
(block
(send
(const
(const {cbase nil?} :Gem) :Specification) :new)
...)
PATTERN

def on_block(block_node)
return unless gem_specification(block_node)

block_parameter = block_node.arguments.first.source

date_assignment = block_node.descendants.detect do |node|
node.send_type? && node.receiver&.source == block_parameter && node.method?(:date=)
end

return unless date_assignment

add_offense(date_assignment) do |corrector|
range = range_by_whole_lines(date_assignment.source_range, include_final_newline: true)

corrector.remove(range)
end
end
end
end
end
end
2 changes: 2 additions & 0 deletions spec/rubocop/cli/cli_options_spec.rb
Expand Up @@ -541,6 +541,8 @@ class SomeCop < Cop
Enabled: false
Layout:
Enabled: false
Gemspec:
Enabled: false

Style/SomeCop:
Description: Something
Expand Down
53 changes: 53 additions & 0 deletions spec/rubocop/cop/gemspec/date_assignment_spec.rb
@@ -0,0 +1,53 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Gemspec::DateAssignment, :config do
it 'registers and corrects an offense when using `s.date =`' do
expect_offense(<<~RUBY)
Gem::Specification.new do |s|
s.name = 'your_cool_gem_name'
s.date = Time.now.strftime('%Y-%m-%d')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `date =` in gemspec, it is set automatically when the gem is packaged.
s.bindir = 'exe'
end
RUBY

expect_correction(<<~RUBY)
Gem::Specification.new do |s|
s.name = 'your_cool_gem_name'
s.bindir = 'exe'
end
RUBY
end

it 'registers and corrects an offense when using `spec.date =`' do
expect_offense(<<~RUBY)
Gem::Specification.new do |spec|
spec.name = 'your_cool_gem_name'
spec.date = Time.now.strftime('%Y-%m-%d')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `date =` in gemspec, it is set automatically when the gem is packaged.
spec.bindir = 'exe'
end
RUBY

expect_correction(<<~RUBY)
Gem::Specification.new do |spec|
spec.name = 'your_cool_gem_name'
spec.bindir = 'exe'
end
RUBY
end

it 'does not register an offense when using `s.date =` outside `Gem::Specification.new`' do
expect_no_offenses(<<~RUBY)
s.date = Time.now.strftime('%Y-%m-%d')
RUBY
end

it 'does not register an offense when using `date =` and receiver is not `Gem::Specification.new` block variable' do
expect_no_offenses(<<~RUBY)
Gem::Specification.new do |spec|
s.date = Time.now.strftime('%Y-%m-%d')
end
RUBY
end
end