Commit 60049140 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '216271-follow-up-from-modify-existing-out-of-runner-minutes-banner' into 'master'

Add Rubocop to alert on empty lines between shared example blocks

Closes #216271

See merge request gitlab-org/gitlab!30864
parents 508fb8fa 68028d85
...@@ -208,6 +208,17 @@ Naming/RescuedExceptionsVariableName: ...@@ -208,6 +208,17 @@ Naming/RescuedExceptionsVariableName:
RSpec/ContextWording: RSpec/ContextWording:
Enabled: false Enabled: false
RSpec/EmptyLineAfterSharedExample:
Exclude:
- 'ee/spec/mailers/notify_spec.rb'
- 'ee/spec/services/quick_actions/interpret_service_spec.rb'
- 'spec/controllers/repositories/git_http_controller_spec.rb'
- 'spec/finders/projects/serverless/functions_finder_spec.rb'
- 'spec/lib/gitlab/hook_data/issuable_builder_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
- 'spec/models/event_spec.rb'
- 'spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb'
# Offense count: 879 # Offense count: 879
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
......
# frozen_string_literal: true
require 'rubocop/rspec/final_end_location'
require 'rubocop/rspec/blank_line_separation'
require 'rubocop/rspec/language'
module RuboCop
module Cop
module RSpec
# Checks if there is an empty line after shared example blocks.
#
# @example
# # bad
# RSpec.describe Foo do
# it_behaves_like 'do this first'
# it_behaves_like 'does this' do
# end
# it_behaves_like 'does that' do
# end
# it_behaves_like 'do some more'
# end
#
# # good
# RSpec.describe Foo do
# it_behaves_like 'do this first'
# it_behaves_like 'does this' do
# end
#
# it_behaves_like 'does that' do
# end
#
# it_behaves_like 'do some more'
# end
#
# # fair - it's ok to have non-separated without blocks
# RSpec.describe Foo do
# it_behaves_like 'do this first'
# it_behaves_like 'does this'
# end
#
class EmptyLineAfterSharedExample < RuboCop::Cop::Cop
include RuboCop::RSpec::BlankLineSeparation
include RuboCop::RSpec::Language
MSG = 'Add an empty line after `%<example>s` block.'
def_node_matcher :shared_examples,
(SharedGroups::ALL + Includes::ALL).block_pattern
def on_block(node)
shared_examples(node) do
break if last_child?(node)
missing_separating_line(node) do |location|
add_offense(node,
location: location,
message: format(MSG, example: node.method_name))
end
end
end
end
end
end
end
...@@ -70,6 +70,7 @@ describe Notify do ...@@ -70,6 +70,7 @@ describe Notify do
it_behaves_like 'an email starting a new thread with reply-by-email enabled' do it_behaves_like 'an email starting a new thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -116,6 +117,7 @@ describe Notify do ...@@ -116,6 +117,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -155,6 +157,7 @@ describe Notify do ...@@ -155,6 +157,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'a user cannot unsubscribe through footer link' it_behaves_like 'a user cannot unsubscribe through footer link'
it_behaves_like 'an email with a labels subscriptions link in its footer' it_behaves_like 'an email with a labels subscriptions link in its footer'
...@@ -200,6 +203,7 @@ describe Notify do ...@@ -200,6 +203,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -214,6 +218,7 @@ describe Notify do ...@@ -214,6 +218,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -248,6 +253,7 @@ describe Notify do ...@@ -248,6 +253,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
...@@ -300,6 +306,7 @@ describe Notify do ...@@ -300,6 +306,7 @@ describe Notify do
it_behaves_like 'an email starting a new thread with reply-by-email enabled' do it_behaves_like 'an email starting a new thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -344,6 +351,7 @@ describe Notify do ...@@ -344,6 +351,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like "an unsubscribeable thread" it_behaves_like "an unsubscribeable thread"
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -409,6 +417,7 @@ describe Notify do ...@@ -409,6 +417,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'a user cannot unsubscribe through footer link' it_behaves_like 'a user cannot unsubscribe through footer link'
it_behaves_like 'an email with a labels subscriptions link in its footer' it_behaves_like 'an email with a labels subscriptions link in its footer'
...@@ -436,6 +445,7 @@ describe Notify do ...@@ -436,6 +445,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -466,6 +476,7 @@ describe Notify do ...@@ -466,6 +476,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -502,6 +513,7 @@ describe Notify do ...@@ -502,6 +513,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -533,6 +545,7 @@ describe Notify do ...@@ -533,6 +545,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -694,6 +707,7 @@ describe Notify do ...@@ -694,6 +707,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { project_snippet } let(:model) { project_snippet }
end end
it_behaves_like 'a user cannot unsubscribe through footer link' it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has the correct subject' do it 'has the correct subject' do
...@@ -936,6 +950,7 @@ describe Notify do ...@@ -936,6 +950,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { commit } let(:model) { commit }
end end
it_behaves_like 'it should show Gmail Actions View Commit link' it_behaves_like 'it should show Gmail Actions View Commit link'
it_behaves_like 'a user cannot unsubscribe through footer link' it_behaves_like 'a user cannot unsubscribe through footer link'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -962,6 +977,7 @@ describe Notify do ...@@ -962,6 +977,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -988,6 +1004,7 @@ describe Notify do ...@@ -988,6 +1004,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -1060,6 +1077,7 @@ describe Notify do ...@@ -1060,6 +1077,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { commit } let(:model) { commit }
end end
it_behaves_like 'it should show Gmail Actions View Commit link' it_behaves_like 'it should show Gmail Actions View Commit link'
it_behaves_like 'a user cannot unsubscribe through footer link' it_behaves_like 'a user cannot unsubscribe through footer link'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -1092,6 +1110,7 @@ describe Notify do ...@@ -1092,6 +1110,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request } let(:model) { merge_request }
end end
it_behaves_like 'it should show Gmail Actions View Merge request link' it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
...@@ -1124,6 +1143,7 @@ describe Notify do ...@@ -1124,6 +1143,7 @@ describe Notify do
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue } let(:model) { issue }
end end
it_behaves_like 'it should show Gmail Actions View Issue link' it_behaves_like 'it should show Gmail Actions View Issue link'
it_behaves_like 'an unsubscribeable thread' it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled' it_behaves_like 'appearance header and footer enabled'
......
# frozen_string_literal: true
require 'spec_helper'
require_relative '../../../../rubocop/cop/rspec/empty_line_after_shared_example'
describe RuboCop::Cop::RSpec::EmptyLineAfterSharedExample do
subject(:cop) { described_class.new }
it 'flags a missing empty line after `it_behaves_like` block' do
expect_offense(<<-RUBY)
RSpec.describe Foo do
it_behaves_like 'does this' do
end
^^^ Add an empty line after `it_behaves_like` block.
it_behaves_like 'does that' do
end
end
RUBY
expect_correction(<<-RUBY)
RSpec.describe Foo do
it_behaves_like 'does this' do
end
it_behaves_like 'does that' do
end
end
RUBY
end
it 'ignores one-line shared examples before shared example blocks' do
expect_no_offenses(<<-RUBY)
RSpec.describe Foo do
it_behaves_like 'does this'
it_behaves_like 'does that' do
end
end
RUBY
end
it 'flags a missing empty line after `shared_examples`' do
expect_offense(<<-RUBY)
RSpec.context 'foo' do
shared_examples do
end
^^^ Add an empty line after `shared_examples` block.
shared_examples 'something gets done' do
end
end
RUBY
expect_correction(<<-RUBY)
RSpec.context 'foo' do
shared_examples do
end
shared_examples 'something gets done' do
end
end
RUBY
end
it 'ignores consecutive one-liners' do
expect_no_offenses(<<-RUBY)
RSpec.describe Foo do
it_behaves_like 'do this'
it_behaves_like 'do that'
end
RUBY
end
it 'flags mixed one-line and multi-line shared examples' do
expect_offense(<<-RUBY)
RSpec.context 'foo' do
it_behaves_like 'do this'
it_behaves_like 'do that'
it_behaves_like 'does this' do
end
^^^ Add an empty line after `it_behaves_like` block.
it_behaves_like 'do this'
it_behaves_like 'do that'
end
RUBY
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment