Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'rubocop/cop/gitlab/feature_available_usage.rb')
-rw-r--r--rubocop/cop/gitlab/feature_available_usage.rb99
1 files changed, 99 insertions, 0 deletions
diff --git a/rubocop/cop/gitlab/feature_available_usage.rb b/rubocop/cop/gitlab/feature_available_usage.rb
new file mode 100644
index 00000000000..b50bdd8ca43
--- /dev/null
+++ b/rubocop/cop/gitlab/feature_available_usage.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module Gitlab
+ # Cop that checks for correct calling of #feature_available?
+ class FeatureAvailableUsage < RuboCop::Cop::Cop
+ OBSERVED_METHOD = :feature_available?
+ LICENSED_FEATURE_LITERAL_ARG_MSG = '`feature_available?` should not be called for features that can be licensed (`%s` given), use `licensed_feature_available?(feature)` instead.'
+ LICENSED_FEATURE_DYNAMIC_ARG_MSG = "`feature_available?` should not be called for features that can be licensed (`%s` isn't a literal so we cannot say if it's legit or not), using `licensed_feature_available?(feature)` may be more appropriate."
+ NOT_ENOUGH_ARGS_MSG = '`feature_available?` should be called with two arguments: `feature` and `user`.'
+ FEATURES = %i[
+ issues
+ forking
+ merge_requests
+ wiki
+ snippets
+ builds
+ repository
+ pages
+ metrics_dashboard
+ analytics
+ operations
+ security_and_compliance
+ container_registry
+ ].freeze
+ EE_FEATURES = %i[requirements].freeze
+ ALL_FEATURES = (FEATURES + EE_FEATURES).freeze
+ SPECIAL_CLASS = %w[License].freeze
+
+ def on_send(node)
+ return unless method_name(node) == OBSERVED_METHOD
+ return if caller_is_special_case?(node)
+ return if feature_name(node).nil?
+ return if ALL_FEATURES.include?(feature_name(node)) && args_count(node) == 2
+
+ if !ALL_FEATURES.include?(feature_name(node))
+ add_offense(node, location: :expression, message: licensed_feature_message(node))
+ elsif args_count(node) < 2
+ add_offense(node, location: :expression, message: NOT_ENOUGH_ARGS_MSG)
+ end
+ end
+
+ def licensed_feature_message(node)
+ message_template = dynamic_feature?(node) ? LICENSED_FEATURE_DYNAMIC_ARG_MSG : LICENSED_FEATURE_LITERAL_ARG_MSG
+
+ message_template % feature_arg_name(node)
+ end
+
+ private
+
+ def method_name(node)
+ node.children[1]
+ end
+
+ def class_caller(node)
+ node.children[0]&.const_name.to_s
+ end
+
+ def caller_is_special_case?(node)
+ SPECIAL_CLASS.include?(class_caller(node))
+ end
+
+ def feature_arg(node)
+ node.children[2]
+ end
+
+ def dynamic_feature?(node)
+ feature = feature_arg(node)
+ return false unless feature
+
+ !feature.literal?
+ end
+
+ def feature_name(node)
+ feature = feature_arg(node)
+ return unless feature
+ return feature.children.compact.join('.') if dynamic_feature?(node)
+ return feature.value if feature.respond_to?(:value)
+
+ feature.type
+ end
+
+ def feature_arg_name(node)
+ feature = feature_arg(node)
+ return unless feature
+ return feature.children.compact.join('.') if dynamic_feature?(node)
+ return feature.children[0].inspect if feature.literal?
+
+ feature.type
+ end
+
+ def args_count(node)
+ node.children[2..].size
+ end
+ end
+ end
+ end
+end