summaryrefslogtreecommitdiff
path: root/rubocop
diff options
context:
space:
mode:
Diffstat (limited to 'rubocop')
-rw-r--r--rubocop/cop/usage_data/histogram_with_large_table.rb58
-rw-r--r--rubocop/cop/usage_data/instrumentation_superclass.rb63
-rw-r--r--rubocop/rubocop-usage-data.yml66
3 files changed, 187 insertions, 0 deletions
diff --git a/rubocop/cop/usage_data/histogram_with_large_table.rb b/rubocop/cop/usage_data/histogram_with_large_table.rb
new file mode 100644
index 00000000000..961773df55c
--- /dev/null
+++ b/rubocop/cop/usage_data/histogram_with_large_table.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module UsageData
+ # This cop checks that histogram method is not used in usage_data.rb files
+ # for models representing large tables, as defined by migration helpers.
+ #
+ # @example
+ #
+ # # bad
+ # histogram(Issue, buckets: 1..100)
+ # histogram(User.active, buckets: 1..100)
+ class HistogramWithLargeTable < RuboCop::Cop::Cop
+ MSG = 'Avoid histogram method on %{model_name}'
+
+ # Match one level const as Issue, Gitlab
+ def_node_matcher :one_level_node, <<~PATTERN
+ (send nil? :histogram
+ `(const {nil? cbase} $_)
+ ...)
+ PATTERN
+
+ # Match two level const as ::Clusters::Cluster, ::Ci::Pipeline
+ def_node_matcher :two_level_node, <<~PATTERN
+ (send nil? :histogram
+ `(const
+ (const {nil? cbase} $_)
+ $_)
+ ...)
+ PATTERN
+
+ def on_send(node)
+ one_level_matches = one_level_node(node)
+ two_level_matches = two_level_node(node)
+
+ return unless Array(one_level_matches).any? || Array(two_level_matches).any?
+
+ class_name = two_level_matches ? two_level_matches.join('::').to_sym : one_level_matches
+
+ if large_table?(class_name)
+ add_offense(node, location: :expression, message: format(MSG, model_name: class_name))
+ end
+ end
+
+ private
+
+ def large_table?(model)
+ high_traffic_models.include?(model.to_s)
+ end
+
+ def high_traffic_models
+ cop_config['HighTrafficModels'] || []
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/usage_data/instrumentation_superclass.rb b/rubocop/cop/usage_data/instrumentation_superclass.rb
new file mode 100644
index 00000000000..2ff2ed47a23
--- /dev/null
+++ b/rubocop/cop/usage_data/instrumentation_superclass.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module UsageData
+ # This cop checks that metric instrumentation classes subclass one of the allowed base classes.
+ #
+ # @example
+ #
+ # # good
+ # class CountIssues < DatabaseMetric
+ # # ...
+ # end
+ #
+ # # bad
+ # class CountIssues < BaseMetric
+ # # ...
+ # end
+ class InstrumentationSuperclass < RuboCop::Cop::Cop
+ MSG = "Instrumentation classes should subclass one of the following: %{allowed_classes}."
+
+ BASE_PATTERN = "(const nil? !#allowed_class?)"
+
+ def_node_matcher :class_definition, <<~PATTERN
+ (class (const _ !#allowed_class?) #{BASE_PATTERN} ...)
+ PATTERN
+
+ def_node_matcher :class_new_definition, <<~PATTERN
+ [!^(casgn {nil? cbase} #allowed_class? ...)
+ !^^(casgn {nil? cbase} #allowed_class? (block ...))
+ (send (const {nil? cbase} :Class) :new #{BASE_PATTERN})]
+ PATTERN
+
+ def on_class(node)
+ class_definition(node) do
+ register_offense(node.children[1])
+ end
+ end
+
+ def on_send(node)
+ class_new_definition(node) do
+ register_offense(node.children.last)
+ end
+ end
+
+ private
+
+ def allowed_class?(class_name)
+ allowed_classes.include?(class_name)
+ end
+
+ def allowed_classes
+ cop_config['AllowedClasses'] || []
+ end
+
+ def register_offense(offense_node)
+ message = format(MSG, allowed_classes: allowed_classes.join(', '))
+ add_offense(offense_node, message: message)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop-usage-data.yml b/rubocop/rubocop-usage-data.yml
index a03f21e491a..2da7b056c2e 100644
--- a/rubocop/rubocop-usage-data.yml
+++ b/rubocop/rubocop-usage-data.yml
@@ -39,6 +39,64 @@ UsageData/LargeTable:
- :arel_table
- :minimum
- :maximum
+UsageData/HistogramWithLargeTable:
+ Enabled: true
+ Include:
+ - 'lib/gitlab/usage_data.rb'
+ - 'ee/lib/ee/gitlab/usage_data.rb'
+ HighTrafficModels: &high_traffic_models # models for all high traffic tables in Migration/UpdateLargeTable
+ - 'AuditEvent'
+ - 'Ci::BuildTraceSection'
+ - 'CommitStatus'
+ - 'Ci::Processable'
+ - 'Ci::Bridge'
+ - 'Ci::Build'
+ - 'GenericCommitStatus'
+ - 'Ci::BuildMetadata'
+ - 'Ci::JobArtifact'
+ - 'Ci::PipelineVariable'
+ - 'Ci::Pipeline'
+ - 'Ci::Stage'
+ - 'Deployment'
+ - 'Event'
+ - 'PushEvent'
+ - 'Issue'
+ - 'MergeRequestDiffCommit'
+ - 'MergeRequestDiffFile'
+ - 'MergeRequestDiff'
+ - 'MergeRequest::Metrics'
+ - 'MergeRequest'
+ - 'NamespaceSetting'
+ - 'Namespace'
+ - 'Group'
+ - 'NoteDiffFile'
+ - 'Note'
+ - 'DiffNote'
+ - 'DiscussionNote'
+ - 'SyntheticNote'
+ - 'LabelNote'
+ - 'MilestoneNote'
+ - 'StateNote'
+ - 'LegacyDiffNote'
+ - 'ProjectAuthorization'
+ - 'Project'
+ - 'ProjectCiCdSetting'
+ - 'ProjectSetting'
+ - 'ProjectFeature'
+ - 'ProtectedBranch'
+ - 'ExportedProtectedBranch'
+ - 'PushEventPayload'
+ - 'ResourceLabelEvent'
+ - 'Route'
+ - 'SentNotification'
+ - 'SystemNoteMetadata'
+ - 'ActsAsTaggableOn::Tagging'
+ - 'Todo'
+ - 'User'
+ - 'UserPreference'
+ - 'UserDetail'
+ - 'Vulnerabilities::Finding'
+ - 'WebHookLog'
UsageData/DistinctCountByLargeForeignKey:
Enabled: true
Include:
@@ -57,3 +115,11 @@ UsageData/DistinctCountByLargeForeignKey:
- 'user_id'
- 'resource_owner_id'
- 'requirement_id'
+UsageData/InstrumentationSuperclass:
+ Enabled: true
+ Include:
+ - 'lib/gitlab/usage/metrics/instrumentations/**/*.rb'
+ AllowedClasses:
+ - :DatabaseMetric
+ - :GenericMetric
+ - :RedisHLLMetric