diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-27 21:09:41 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-27 21:09:41 +0300 |
commit | f569792df8a25caa1bed9c448c8c4c3f837f5164 (patch) | |
tree | 8c2ed7dae5ba132a97c0321a7649174e5832d637 /rubocop/cop | |
parent | c2908ec6a0d7b62996cdb8da0350705bdad691bf (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'rubocop/cop')
-rw-r--r-- | rubocop/cop/api/grape_api_instance.rb | 42 | ||||
-rw-r--r-- | rubocop/cop/api/grape_array_missing_coerce.rb | 83 | ||||
-rw-r--r-- | rubocop/cop/gitlab/json.rb | 36 |
3 files changed, 161 insertions, 0 deletions
diff --git a/rubocop/cop/api/grape_api_instance.rb b/rubocop/cop/api/grape_api_instance.rb new file mode 100644 index 00000000000..de11b9ef3f6 --- /dev/null +++ b/rubocop/cop/api/grape_api_instance.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module API + class GrapeAPIInstance < RuboCop::Cop::Cop + # This cop checks that APIs subclass Grape::API::Instance with Grape v1.3+. + # + # @example + # + # # bad + # module API + # class Projects < Grape::API + # end + # end + # + # # good + # module API + # class Projects < Grape::API::Instance + # end + # end + MSG = 'Inherit from Grape::API::Instance instead of Grape::API. ' \ + 'For more details check the https://gitlab.com/gitlab-org/gitlab/-/issues/215230.' + + def_node_matcher :grape_api_definition, <<~PATTERN + (class + (const _ _) + (const + (const nil? :Grape) :API) + ... + ) + PATTERN + + def on_class(node) + grape_api_definition(node) do + add_offense(node.children[1]) + end + end + end + end + end +end diff --git a/rubocop/cop/api/grape_array_missing_coerce.rb b/rubocop/cop/api/grape_array_missing_coerce.rb new file mode 100644 index 00000000000..3d7a6a72d81 --- /dev/null +++ b/rubocop/cop/api/grape_array_missing_coerce.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module API + class GrapeArrayMissingCoerce < RuboCop::Cop::Cop + # This cop checks that Grape API parameters using an Array type + # implement a coerce_with method: + # + # https://github.com/ruby-grape/grape/blob/master/UPGRADING.md#ensure-that-array-types-have-explicit-coercions + # + # @example + # + # # bad + # requires :values, type: Array[String] + # + # # good + # requires :values, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce + # + # end + MSG = 'This Grape parameter defines an Array but is missing a coerce_with definition. ' \ + 'For more details, see https://github.com/ruby-grape/grape/blob/master/UPGRADING.md#ensure-that-array-types-have-explicit-coercions' + + def_node_matcher :grape_api_instance?, <<~PATTERN + (class + (const _ _) + (const + (const + (const nil? :Grape) :API) :Instance) + ... + ) + PATTERN + + def_node_matcher :grape_api_param_block?, <<~PATTERN + (send _ {:requires :optional} + (sym _) + $_) + PATTERN + + def_node_matcher :grape_type_def?, <<~PATTERN + (sym :type) + PATTERN + + def_node_matcher :grape_array_type?, <<~PATTERN + (send + (const nil? :Array) :[] + (const nil? _)) + PATTERN + + def_node_matcher :grape_coerce_with?, <<~PATTERN + (sym :coerce_with) + PATTERN + + def on_class(node) + @grape_api ||= grape_api_instance?(node) + end + + def on_send(node) + return unless @grape_api + + match = grape_api_param_block?(node) + + return unless match.is_a?(RuboCop::AST::HashNode) + + is_array_type = false + has_coerce_method = false + + match.each_pair do |first, second| + has_coerce_method ||= grape_coerce_with?(first) + + if grape_type_def?(first) && grape_array_type?(second) + is_array_type = true + end + end + + if is_array_type && !has_coerce_method + add_offense(node) + end + end + end + end + end +end diff --git a/rubocop/cop/gitlab/json.rb b/rubocop/cop/gitlab/json.rb new file mode 100644 index 00000000000..8c9027223aa --- /dev/null +++ b/rubocop/cop/gitlab/json.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Gitlab + class Json < RuboCop::Cop::Cop + MSG_SEND = <<~EOL.freeze + Avoid calling `JSON` directly. Instead, use the `Gitlab::Json` + wrapper. This allows us to alter the JSON parser being used. + EOL + + def_node_matcher :json_node?, <<~PATTERN + (send (const nil? :JSON)...) + PATTERN + + def on_send(node) + add_offense(node, location: :expression, message: MSG_SEND) if json_node?(node) + end + + def autocorrect(node) + autocorrect_json_node(node) + end + + def autocorrect_json_node(node) + _, method_name, *arg_nodes = *node + + replacement = "Gitlab::Json.#{method_name}(#{arg_nodes.map(&:source).join(', ')})" + + lambda do |corrector| + corrector.replace(node.source_range, replacement) + end + end + end + end + end +end |