diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-20 03:12:57 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-20 03:12:57 +0300 |
commit | 8277a5b4ba05fe11174397c689c66cef5c06fc38 (patch) | |
tree | c4abbec1509476efbb14c040045ca163042de3bf /tooling | |
parent | f46a8dbf1a0999e27dfeddd258096ef97def8d64 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'tooling')
-rw-r--r-- | tooling/danger/specs.rb | 88 | ||||
-rw-r--r-- | tooling/danger/specs/feature_category_suggestion.rb | 42 | ||||
-rw-r--r-- | tooling/danger/specs/match_with_array_suggestion.rb | 17 | ||||
-rw-r--r-- | tooling/danger/specs/project_factory_suggestion.rb | 38 | ||||
-rw-r--r-- | tooling/danger/suggestion.rb | 39 |
5 files changed, 144 insertions, 80 deletions
diff --git a/tooling/danger/specs.rb b/tooling/danger/specs.rb index 5359e71f8cc..68cab141656 100644 --- a/tooling/danger/specs.rb +++ b/tooling/danger/specs.rb @@ -1,55 +1,19 @@ # frozen_string_literal: true -require_relative 'suggestor' +Dir[File.expand_path('specs/*_suggestion.rb', __dir__)].each { |file| require file } module Tooling module Danger module Specs - include ::Tooling::Danger::Suggestor - SPEC_FILES_REGEX = 'spec/' EE_PREFIX = 'ee/' - PROJECT_FACTORIES = %w[ - :project - :project_empty_repo - :forked_project_with_submodules - :project_with_design + SUGGESTIONS = [ + FeatureCategorySuggestion, + MatchWithArraySuggestion, + ProjectFactorySuggestion ].freeze - PROJECT_FACTORY_REGEX = / - ^\+? # Start of the line, which may or may not have a `+` - (?<head>\s*) # 0-many leading whitespace captured in a group named head - let!? # Literal `let` which may or may not end in `!` - (?<tail> # capture group named tail - \([^)]+\) # Two parenthesis with any non-parenthesis characters between them - \s*\{\s* # Opening curly brace surrounded by 0-many whitespace characters - create\( # literal - (?:#{PROJECT_FACTORIES.join('|')}) # Any of the project factory names - \W # Non-word character, avoid matching factories like :project_authorization - ) # end capture group named tail - /x.freeze - - PROJECT_FACTORY_REPLACEMENT = '\k<head>let_it_be\k<tail>' - PROJECT_FACTORY_SUGGESTION = <<~SUGGEST_COMMENT - Project creations are very slow. Use `let_it_be`, `build` or `build_stubbed` if possible. - See [testing best practices](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#optimize-factory-usage) - for background information and alternative options. - SUGGEST_COMMENT - - MATCH_WITH_ARRAY_REGEX = /(?<to>to\(?\s*)(?<matcher>match|eq)(?<expectation>[( ]?\[(?=.*,)[^\]]+)/.freeze - MATCH_WITH_ARRAY_REPLACEMENT = '\k<to>match_array\k<expectation>' - MATCH_WITH_ARRAY_SUGGESTION = <<~SUGGEST_COMMENT - If order of the result is not important, please consider using `match_array` to avoid flakiness. - SUGGEST_COMMENT - - RSPEC_TOP_LEVEL_DESCRIBE_REGEX = /^\+.?RSpec\.describe(.+)/.freeze - FEATURE_CATEGORY_SUGGESTION = <<~SUGGESTION_MARKDOWN - Consider adding `feature_category: <feature_category_name>` for this example if it is not set already. - See [testing best practices](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#feature-category-metadata). - SUGGESTION_MARKDOWN - FEATURE_CATEGORY_KEYWORD = 'feature_category' - def changed_specs_files(ee: :include) changed_files = helper.all_changed_files folder_prefix = @@ -65,45 +29,9 @@ module Tooling changed_files.grep(%r{\A#{folder_prefix}#{SPEC_FILES_REGEX}}) end - def add_suggestions_for_match_with_array(filename) - add_suggestion( - filename: filename, - regex: MATCH_WITH_ARRAY_REGEX, - replacement: MATCH_WITH_ARRAY_REPLACEMENT, - comment_text: MATCH_WITH_ARRAY_SUGGESTION - ) - end - - def add_suggestions_for_project_factory_usage(filename) - add_suggestion( - filename: filename, - regex: PROJECT_FACTORY_REGEX, - replacement: PROJECT_FACTORY_REPLACEMENT, - comment_text: PROJECT_FACTORY_SUGGESTION - ) - end - - def add_suggestions_for_feature_category(filename) - file_lines = project_helper.file_lines(filename) - changed_lines = helper.changed_lines(filename) - - changed_lines.each_with_index do |changed_line, i| - next unless changed_line =~ RSPEC_TOP_LEVEL_DESCRIBE_REGEX - - line_number = file_lines.find_index(changed_line.delete_prefix('+')) - next unless line_number - - # Get the top level RSpec.describe line and the next 5 lines - lines_to_check = file_lines[line_number, 5] - # Remove all the lines after the first one that ends in `do` - last_line_number_of_describe_declaration = lines_to_check.index { |line| line.end_with?(' do') } - lines_to_check = lines_to_check[0..last_line_number_of_describe_declaration] - - next if lines_to_check.any? { |line| line.include?(FEATURE_CATEGORY_KEYWORD) } - - suggested_line = file_lines[line_number] - - markdown(comment(FEATURE_CATEGORY_SUGGESTION, suggested_line), file: filename, line: line_number.succ) + def add_suggestions_for(filename) + SUGGESTIONS.each do |suggestion| + suggestion.new(filename, context: self).suggest end end end diff --git a/tooling/danger/specs/feature_category_suggestion.rb b/tooling/danger/specs/feature_category_suggestion.rb new file mode 100644 index 00000000000..5acf73c8956 --- /dev/null +++ b/tooling/danger/specs/feature_category_suggestion.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require_relative '../suggestion' + +module Tooling + module Danger + module Specs + class FeatureCategorySuggestion < Suggestion + RSPEC_TOP_LEVEL_DESCRIBE_REGEX = /^\+.?RSpec\.describe(.+)/ + SUGGESTION = <<~SUGGESTION_MARKDOWN + Consider adding `feature_category: <feature_category_name>` for this example if it is not set already. + See [testing best practices](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#feature-category-metadata). + SUGGESTION_MARKDOWN + FEATURE_CATEGORY_KEYWORD = 'feature_category' + + def suggest + file_lines = project_helper.file_lines(filename) + changed_lines = helper.changed_lines(filename) + + changed_lines.each do |changed_line| + next unless changed_line =~ RSPEC_TOP_LEVEL_DESCRIBE_REGEX + + line_number = file_lines.find_index(changed_line.delete_prefix('+')) + next unless line_number + + # Get the top level RSpec.describe line and the next 5 lines + lines_to_check = file_lines[line_number, 5] + # Remove all the lines after the first one that ends in `do` + last_line_number_of_describe_declaration = lines_to_check.index { |line| line.end_with?(' do') } + lines_to_check = lines_to_check[0..last_line_number_of_describe_declaration] + + next if lines_to_check.any? { |line| line.include?(FEATURE_CATEGORY_KEYWORD) } + + suggested_line = file_lines[line_number] + + markdown(comment(SUGGESTION, suggested_line), file: filename, line: line_number.succ) + end + end + end + end + end +end diff --git a/tooling/danger/specs/match_with_array_suggestion.rb b/tooling/danger/specs/match_with_array_suggestion.rb new file mode 100644 index 00000000000..eb0f7a1a832 --- /dev/null +++ b/tooling/danger/specs/match_with_array_suggestion.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require_relative '../suggestion' + +module Tooling + module Danger + module Specs + class MatchWithArraySuggestion < Suggestion + MATCH = /(?<to>to\(?\s*)(?<matcher>match|eq)(?<expectation>[( ]?\[(?=.*,)[^\]]+)/ + REPLACEMENT = '\k<to>match_array\k<expectation>' + SUGGESTION = <<~SUGGEST_COMMENT + If order of the result is not important, please consider using `match_array` to avoid flakiness. + SUGGEST_COMMENT + end + end + end +end diff --git a/tooling/danger/specs/project_factory_suggestion.rb b/tooling/danger/specs/project_factory_suggestion.rb new file mode 100644 index 00000000000..4e5a70ac8e5 --- /dev/null +++ b/tooling/danger/specs/project_factory_suggestion.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require_relative '../suggestion' + +module Tooling + module Danger + module Specs + class ProjectFactorySuggestion < Suggestion + PROJECT_FACTORIES = %w[ + :project + :project_empty_repo + :forked_project_with_submodules + :project_with_design + ].freeze + + MATCH = / + ^\+? # Start of the line, which may or may not have a `+` + (?<head>\s*) # 0-many leading whitespace captured in a group named head + let!? # Literal `let` which may or may not end in `!` + (?<tail> # capture group named tail + \([^)]+\) # Two parenthesis with any non-parenthesis characters between them + \s*\{\s* # Opening curly brace surrounded by 0-many whitespace characters + create\( # literal + (?:#{PROJECT_FACTORIES.join('|')}) # Any of the project factory names + \W # Non-word character, avoid matching factories like :project_badge + ) # end capture group named tail + /x + + REPLACEMENT = '\k<head>let_it_be\k<tail>' + SUGGESTION = <<~SUGGEST_COMMENT + Project creations are very slow. Use `let_it_be`, `build` or `build_stubbed` if possible. + See [testing best practices](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#optimize-factory-usage) + for background information and alternative options. + SUGGEST_COMMENT + end + end + end +end diff --git a/tooling/danger/suggestion.rb b/tooling/danger/suggestion.rb new file mode 100644 index 00000000000..da3c6b0e76f --- /dev/null +++ b/tooling/danger/suggestion.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'forwardable' +require_relative 'suggestor' + +module Tooling + module Danger + # A basic suggestion. + # + # A subclass needs to define the following constants: + # * MATCH (Regexp) - A Regexp to match file lines + # * REPLACEMENT (String) - A suggestion replacement text + # * SUGGESTION (String) - A suggestion text + # + # @see Suggestor + class Suggestion + extend Forwardable + include ::Tooling::Danger::Suggestor + + def_delegators :@context, :helper, :project_helper, :markdown + + attr_reader :filename + + def initialize(filename, context:) + @filename = filename + @context = context + end + + def suggest + add_suggestion( + filename: filename, + regex: self.class::MATCH, + replacement: self.class::REPLACEMENT, + comment_text: self.class::SUGGESTION + ) + end + end + end +end |