diff options
Diffstat (limited to 'app/models/concerns')
-rw-r--r-- | app/models/concerns/analytics/cycle_analytics/stage.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/approvable_base.rb | 16 | ||||
-rw-r--r-- | app/models/concerns/avatarable.rb | 6 | ||||
-rw-r--r-- | app/models/concerns/bulk_insert_safe.rb | 8 | ||||
-rw-r--r-- | app/models/concerns/ci/contextable.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/ci/has_status.rb | 168 | ||||
-rw-r--r-- | app/models/concerns/ci/metadatable.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/deployment_platform.rb | 22 | ||||
-rw-r--r-- | app/models/concerns/has_repository.rb | 8 | ||||
-rw-r--r-- | app/models/concerns/has_status.rb | 166 | ||||
-rw-r--r-- | app/models/concerns/integration.rb | 14 | ||||
-rw-r--r-- | app/models/concerns/issuable.rb | 6 | ||||
-rw-r--r-- | app/models/concerns/noteable.rb | 4 | ||||
-rw-r--r-- | app/models/concerns/partitioned_table.rb | 21 | ||||
-rw-r--r-- | app/models/concerns/reactive_caching.rb | 8 | ||||
-rw-r--r-- | app/models/concerns/routable.rb | 9 | ||||
-rw-r--r-- | app/models/concerns/update_project_statistics.rb | 12 |
17 files changed, 279 insertions, 195 deletions
diff --git a/app/models/concerns/analytics/cycle_analytics/stage.rb b/app/models/concerns/analytics/cycle_analytics/stage.rb index 39e8408f794..f1c39dda49d 100644 --- a/app/models/concerns/analytics/cycle_analytics/stage.rb +++ b/app/models/concerns/analytics/cycle_analytics/stage.rb @@ -125,7 +125,7 @@ module Analytics def label_available_for_group?(label_id) LabelsFinder.new(nil, { group_id: group.id, include_ancestor_groups: true, only_group_labels: true }) .execute(skip_authorization: true) - .by_ids(label_id) + .id_in(label_id) .exists? end end diff --git a/app/models/concerns/approvable_base.rb b/app/models/concerns/approvable_base.rb new file mode 100644 index 00000000000..6323bd01c58 --- /dev/null +++ b/app/models/concerns/approvable_base.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module ApprovableBase + extend ActiveSupport::Concern + + included do + has_many :approvals, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent + has_many :approved_by_users, through: :approvals, source: :user + end + + def approved_by?(user) + return false unless user + + approved_by_users.include?(user) + end +end diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb index a98baeb0e3d..ac84ef94b1c 100644 --- a/app/models/concerns/avatarable.rb +++ b/app/models/concerns/avatarable.rb @@ -36,6 +36,12 @@ module Avatarable end end + class_methods do + def bot_avatar(image:) + Rails.root.join('app', 'assets', 'images', 'bot_avatars', image).open + end + end + def avatar_type unless self.avatar.image? errors.add :avatar, "file format is not supported. Please try one of the following supported formats: #{AvatarUploader::SAFE_IMAGE_EXT.join(', ')}" diff --git a/app/models/concerns/bulk_insert_safe.rb b/app/models/concerns/bulk_insert_safe.rb index e09f44e68dc..f9eb3fb875e 100644 --- a/app/models/concerns/bulk_insert_safe.rb +++ b/app/models/concerns/bulk_insert_safe.rb @@ -37,7 +37,7 @@ module BulkInsertSafe # These are the callbacks we think safe when used on models that are # written to the database in bulk - CALLBACK_NAME_WHITELIST = Set[ + ALLOWED_CALLBACKS = Set[ :initialize, :validate, :validation, @@ -179,16 +179,12 @@ module BulkInsertSafe end def _bulk_insert_callback_allowed?(name, args) - _bulk_insert_whitelisted?(name) || _bulk_insert_saved_from_belongs_to?(name, args) + ALLOWED_CALLBACKS.include?(name) || _bulk_insert_saved_from_belongs_to?(name, args) end # belongs_to associations will install a before_save hook during class loading def _bulk_insert_saved_from_belongs_to?(name, args) args.first == :before && args.second.to_s.start_with?('autosave_associated_records_for_') end - - def _bulk_insert_whitelisted?(name) - CALLBACK_NAME_WHITELIST.include?(name) - end end end diff --git a/app/models/concerns/ci/contextable.rb b/app/models/concerns/ci/contextable.rb index 7ea5382a4fa..10df5e1a8dc 100644 --- a/app/models/concerns/ci/contextable.rb +++ b/app/models/concerns/ci/contextable.rb @@ -84,8 +84,6 @@ module Ci end def secret_instance_variables - return [] unless ::Feature.enabled?(:ci_instance_level_variables, project, default_enabled: true) - project.ci_instance_variables_for(ref: git_ref) end diff --git a/app/models/concerns/ci/has_status.rb b/app/models/concerns/ci/has_status.rb new file mode 100644 index 00000000000..c52807ec501 --- /dev/null +++ b/app/models/concerns/ci/has_status.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +module Ci + module HasStatus + extend ActiveSupport::Concern + + DEFAULT_STATUS = 'created' + BLOCKED_STATUS = %w[manual scheduled].freeze + AVAILABLE_STATUSES = %w[created waiting_for_resource preparing pending running success failed canceled skipped manual scheduled].freeze + STARTED_STATUSES = %w[running success failed skipped manual scheduled].freeze + ACTIVE_STATUSES = %w[waiting_for_resource preparing pending running].freeze + COMPLETED_STATUSES = %w[success failed canceled skipped].freeze + ORDERED_STATUSES = %w[failed preparing pending running waiting_for_resource manual scheduled canceled success skipped created].freeze + PASSED_WITH_WARNINGS_STATUSES = %w[failed canceled].to_set.freeze + EXCLUDE_IGNORED_STATUSES = %w[manual failed canceled].to_set.freeze + STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3, + failed: 4, canceled: 5, skipped: 6, manual: 7, + scheduled: 8, preparing: 9, waiting_for_resource: 10 }.freeze + + UnknownStatusError = Class.new(StandardError) + + class_methods do + def legacy_status_sql + scope_relevant = respond_to?(:exclude_ignored) ? exclude_ignored : all + scope_warnings = respond_to?(:failed_but_allowed) ? failed_but_allowed : none + + builds = scope_relevant.select('count(*)').to_sql + created = scope_relevant.created.select('count(*)').to_sql + success = scope_relevant.success.select('count(*)').to_sql + manual = scope_relevant.manual.select('count(*)').to_sql + scheduled = scope_relevant.scheduled.select('count(*)').to_sql + preparing = scope_relevant.preparing.select('count(*)').to_sql + waiting_for_resource = scope_relevant.waiting_for_resource.select('count(*)').to_sql + pending = scope_relevant.pending.select('count(*)').to_sql + running = scope_relevant.running.select('count(*)').to_sql + skipped = scope_relevant.skipped.select('count(*)').to_sql + canceled = scope_relevant.canceled.select('count(*)').to_sql + warnings = scope_warnings.select('count(*) > 0').to_sql.presence || 'false' + + Arel.sql( + "(CASE + WHEN (#{builds})=(#{skipped}) AND (#{warnings}) THEN 'success' + WHEN (#{builds})=(#{skipped}) THEN 'skipped' + WHEN (#{builds})=(#{success}) THEN 'success' + WHEN (#{builds})=(#{created}) THEN 'created' + WHEN (#{builds})=(#{preparing}) THEN 'preparing' + WHEN (#{builds})=(#{success})+(#{skipped}) THEN 'success' + WHEN (#{builds})=(#{success})+(#{skipped})+(#{canceled}) THEN 'canceled' + WHEN (#{builds})=(#{created})+(#{skipped})+(#{pending}) THEN 'pending' + WHEN (#{running})+(#{pending})>0 THEN 'running' + WHEN (#{waiting_for_resource})>0 THEN 'waiting_for_resource' + WHEN (#{manual})>0 THEN 'manual' + WHEN (#{scheduled})>0 THEN 'scheduled' + WHEN (#{preparing})>0 THEN 'preparing' + WHEN (#{created})>0 THEN 'running' + ELSE 'failed' + END)" + ) + end + + def legacy_status + all.pluck(legacy_status_sql).first + end + + # This method should not be used. + # This method performs expensive calculation of status: + # 1. By plucking all related objects, + # 2. Or executes expensive SQL query + def slow_composite_status(project:) + if ::Gitlab::Ci::Features.composite_status?(project) + Gitlab::Ci::Status::Composite + .new(all, with_allow_failure: columns_hash.key?('allow_failure')) + .status + else + legacy_status + end + end + + def started_at + all.minimum(:started_at) + end + + def finished_at + all.maximum(:finished_at) + end + + def all_state_names + state_machines.values.flat_map(&:states).flat_map { |s| s.map(&:name) } + end + + def completed_statuses + COMPLETED_STATUSES.map(&:to_sym) + end + end + + included do + validates :status, inclusion: { in: AVAILABLE_STATUSES } + + state_machine :status, initial: :created do + state :created, value: 'created' + state :waiting_for_resource, value: 'waiting_for_resource' + state :preparing, value: 'preparing' + state :pending, value: 'pending' + state :running, value: 'running' + state :failed, value: 'failed' + state :success, value: 'success' + state :canceled, value: 'canceled' + state :skipped, value: 'skipped' + state :manual, value: 'manual' + state :scheduled, value: 'scheduled' + end + + scope :created, -> { with_status(:created) } + scope :waiting_for_resource, -> { with_status(:waiting_for_resource) } + scope :preparing, -> { with_status(:preparing) } + scope :relevant, -> { without_status(:created) } + scope :running, -> { with_status(:running) } + scope :pending, -> { with_status(:pending) } + scope :success, -> { with_status(:success) } + scope :failed, -> { with_status(:failed) } + scope :canceled, -> { with_status(:canceled) } + scope :skipped, -> { with_status(:skipped) } + scope :manual, -> { with_status(:manual) } + scope :scheduled, -> { with_status(:scheduled) } + scope :alive, -> { with_status(:created, :waiting_for_resource, :preparing, :pending, :running) } + scope :alive_or_scheduled, -> { with_status(:created, :waiting_for_resource, :preparing, :pending, :running, :scheduled) } + scope :created_or_pending, -> { with_status(:created, :pending) } + scope :running_or_pending, -> { with_status(:running, :pending) } + scope :finished, -> { with_status(:success, :failed, :canceled) } + scope :failed_or_canceled, -> { with_status(:failed, :canceled) } + scope :incomplete, -> { without_statuses(completed_statuses) } + + scope :cancelable, -> do + where(status: [:running, :waiting_for_resource, :preparing, :pending, :created, :scheduled]) + end + + scope :without_statuses, -> (names) do + with_status(all_state_names - names.to_a) + end + end + + def started? + STARTED_STATUSES.include?(status) && started_at + end + + def active? + ACTIVE_STATUSES.include?(status) + end + + def complete? + COMPLETED_STATUSES.include?(status) + end + + def blocked? + BLOCKED_STATUS.include?(status) + end + + private + + def calculate_duration + if started_at && finished_at + finished_at - started_at + elsif started_at + Time.current - started_at + end + end + end +end diff --git a/app/models/concerns/ci/metadatable.rb b/app/models/concerns/ci/metadatable.rb index bd40af28bc9..26e644646b4 100644 --- a/app/models/concerns/ci/metadatable.rb +++ b/app/models/concerns/ci/metadatable.rb @@ -87,3 +87,5 @@ module Ci end end end + +Ci::Metadatable.prepend_if_ee('EE::Ci::Metadatable') diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb index 3b893a56bd6..02f7711e927 100644 --- a/app/models/concerns/deployment_platform.rb +++ b/app/models/concerns/deployment_platform.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true module DeploymentPlatform - # EE would override this and utilize environment argument # rubocop:disable Gitlab/ModuleWithInstanceVariables def deployment_platform(environment: nil) @deployment_platform ||= {} @@ -20,16 +19,27 @@ module DeploymentPlatform find_instance_cluster_platform_kubernetes(environment: environment) end - # EE would override this and utilize environment argument - def find_platform_kubernetes_with_cte(_environment) - Clusters::ClustersHierarchy.new(self, include_management_project: cluster_management_project_enabled?).base_and_ancestors + def find_platform_kubernetes_with_cte(environment) + if environment + ::Clusters::ClustersHierarchy.new(self, include_management_project: cluster_management_project_enabled?) + .base_and_ancestors + .enabled + .on_environment(environment, relevant_only: true) + .first&.platform_kubernetes + else + Clusters::ClustersHierarchy.new(self, include_management_project: cluster_management_project_enabled?).base_and_ancestors .enabled.default_environment .first&.platform_kubernetes + end end - # EE would override this and utilize environment argument def find_instance_cluster_platform_kubernetes(environment: nil) - Clusters::Instance.new.clusters.enabled.default_environment + if environment + ::Clusters::Instance.new.clusters.enabled.on_environment(environment, relevant_only: true) .first&.platform_kubernetes + else + Clusters::Instance.new.clusters.enabled.default_environment + .first&.platform_kubernetes + end end end diff --git a/app/models/concerns/has_repository.rb b/app/models/concerns/has_repository.rb index 29d31b8bb4f..d909b67d7ba 100644 --- a/app/models/concerns/has_repository.rb +++ b/app/models/concerns/has_repository.rb @@ -5,7 +5,7 @@ # of directly having a repository, like project or snippet. # # It also includes `Referable`, therefore the method -# `to_reference` should be overriden in case the object +# `to_reference` should be overridden in case the object # needs any special behavior. module HasRepository extend ActiveSupport::Concern @@ -76,7 +76,11 @@ module HasRepository end def default_branch - @default_branch ||= repository.root_ref + @default_branch ||= repository.root_ref || default_branch_from_preferences + end + + def default_branch_from_preferences + empty_repo? ? Gitlab::CurrentSettings.default_branch_name : nil end def reload_default_branch diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb deleted file mode 100644 index c885dea862f..00000000000 --- a/app/models/concerns/has_status.rb +++ /dev/null @@ -1,166 +0,0 @@ -# frozen_string_literal: true - -module HasStatus - extend ActiveSupport::Concern - - DEFAULT_STATUS = 'created' - BLOCKED_STATUS = %w[manual scheduled].freeze - AVAILABLE_STATUSES = %w[created waiting_for_resource preparing pending running success failed canceled skipped manual scheduled].freeze - STARTED_STATUSES = %w[running success failed skipped manual scheduled].freeze - ACTIVE_STATUSES = %w[waiting_for_resource preparing pending running].freeze - COMPLETED_STATUSES = %w[success failed canceled skipped].freeze - ORDERED_STATUSES = %w[failed preparing pending running waiting_for_resource manual scheduled canceled success skipped created].freeze - PASSED_WITH_WARNINGS_STATUSES = %w[failed canceled].to_set.freeze - EXCLUDE_IGNORED_STATUSES = %w[manual failed canceled].to_set.freeze - STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3, - failed: 4, canceled: 5, skipped: 6, manual: 7, - scheduled: 8, preparing: 9, waiting_for_resource: 10 }.freeze - - UnknownStatusError = Class.new(StandardError) - - class_methods do - def legacy_status_sql - scope_relevant = respond_to?(:exclude_ignored) ? exclude_ignored : all - scope_warnings = respond_to?(:failed_but_allowed) ? failed_but_allowed : none - - builds = scope_relevant.select('count(*)').to_sql - created = scope_relevant.created.select('count(*)').to_sql - success = scope_relevant.success.select('count(*)').to_sql - manual = scope_relevant.manual.select('count(*)').to_sql - scheduled = scope_relevant.scheduled.select('count(*)').to_sql - preparing = scope_relevant.preparing.select('count(*)').to_sql - waiting_for_resource = scope_relevant.waiting_for_resource.select('count(*)').to_sql - pending = scope_relevant.pending.select('count(*)').to_sql - running = scope_relevant.running.select('count(*)').to_sql - skipped = scope_relevant.skipped.select('count(*)').to_sql - canceled = scope_relevant.canceled.select('count(*)').to_sql - warnings = scope_warnings.select('count(*) > 0').to_sql.presence || 'false' - - Arel.sql( - "(CASE - WHEN (#{builds})=(#{skipped}) AND (#{warnings}) THEN 'success' - WHEN (#{builds})=(#{skipped}) THEN 'skipped' - WHEN (#{builds})=(#{success}) THEN 'success' - WHEN (#{builds})=(#{created}) THEN 'created' - WHEN (#{builds})=(#{preparing}) THEN 'preparing' - WHEN (#{builds})=(#{success})+(#{skipped}) THEN 'success' - WHEN (#{builds})=(#{success})+(#{skipped})+(#{canceled}) THEN 'canceled' - WHEN (#{builds})=(#{created})+(#{skipped})+(#{pending}) THEN 'pending' - WHEN (#{running})+(#{pending})>0 THEN 'running' - WHEN (#{waiting_for_resource})>0 THEN 'waiting_for_resource' - WHEN (#{manual})>0 THEN 'manual' - WHEN (#{scheduled})>0 THEN 'scheduled' - WHEN (#{preparing})>0 THEN 'preparing' - WHEN (#{created})>0 THEN 'running' - ELSE 'failed' - END)" - ) - end - - def legacy_status - all.pluck(legacy_status_sql).first - end - - # This method should not be used. - # This method performs expensive calculation of status: - # 1. By plucking all related objects, - # 2. Or executes expensive SQL query - def slow_composite_status(project:) - if ::Gitlab::Ci::Features.composite_status?(project) - Gitlab::Ci::Status::Composite - .new(all, with_allow_failure: columns_hash.key?('allow_failure')) - .status - else - legacy_status - end - end - - def started_at - all.minimum(:started_at) - end - - def finished_at - all.maximum(:finished_at) - end - - def all_state_names - state_machines.values.flat_map(&:states).flat_map { |s| s.map(&:name) } - end - - def completed_statuses - COMPLETED_STATUSES.map(&:to_sym) - end - end - - included do - validates :status, inclusion: { in: AVAILABLE_STATUSES } - - state_machine :status, initial: :created do - state :created, value: 'created' - state :waiting_for_resource, value: 'waiting_for_resource' - state :preparing, value: 'preparing' - state :pending, value: 'pending' - state :running, value: 'running' - state :failed, value: 'failed' - state :success, value: 'success' - state :canceled, value: 'canceled' - state :skipped, value: 'skipped' - state :manual, value: 'manual' - state :scheduled, value: 'scheduled' - end - - scope :created, -> { with_status(:created) } - scope :waiting_for_resource, -> { with_status(:waiting_for_resource) } - scope :preparing, -> { with_status(:preparing) } - scope :relevant, -> { without_status(:created) } - scope :running, -> { with_status(:running) } - scope :pending, -> { with_status(:pending) } - scope :success, -> { with_status(:success) } - scope :failed, -> { with_status(:failed) } - scope :canceled, -> { with_status(:canceled) } - scope :skipped, -> { with_status(:skipped) } - scope :manual, -> { with_status(:manual) } - scope :scheduled, -> { with_status(:scheduled) } - scope :alive, -> { with_status(:created, :waiting_for_resource, :preparing, :pending, :running) } - scope :alive_or_scheduled, -> { with_status(:created, :waiting_for_resource, :preparing, :pending, :running, :scheduled) } - scope :created_or_pending, -> { with_status(:created, :pending) } - scope :running_or_pending, -> { with_status(:running, :pending) } - scope :finished, -> { with_status(:success, :failed, :canceled) } - scope :failed_or_canceled, -> { with_status(:failed, :canceled) } - scope :incomplete, -> { without_statuses(completed_statuses) } - - scope :cancelable, -> do - where(status: [:running, :waiting_for_resource, :preparing, :pending, :created, :scheduled]) - end - - scope :without_statuses, -> (names) do - with_status(all_state_names - names.to_a) - end - end - - def started? - STARTED_STATUSES.include?(status) && started_at - end - - def active? - ACTIVE_STATUSES.include?(status) - end - - def complete? - COMPLETED_STATUSES.include?(status) - end - - def blocked? - BLOCKED_STATUS.include?(status) - end - - private - - def calculate_duration - if started_at && finished_at - finished_at - started_at - elsif started_at - Time.current - started_at - end - end -end diff --git a/app/models/concerns/integration.rb b/app/models/concerns/integration.rb index 644a0ba1b5e..34ff5bb1195 100644 --- a/app/models/concerns/integration.rb +++ b/app/models/concerns/integration.rb @@ -15,5 +15,19 @@ module Integration Project.where(id: custom_integration_project_ids) end + + def ids_without_integration(integration, limit) + services = Service + .select('1') + .where('services.project_id = projects.id') + .where(type: integration.type) + + Project + .where('NOT EXISTS (?)', services) + .where(pending_delete: false) + .where(archived: false) + .limit(limit) + .pluck(:id) + end end end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 220af8ab7c7..715cbd15d93 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -411,8 +411,8 @@ module Issuable changes = previous_changes if old_associations - old_labels = old_associations.fetch(:labels, []) - old_assignees = old_associations.fetch(:assignees, []) + old_labels = old_associations.fetch(:labels, labels) + old_assignees = old_associations.fetch(:assignees, assignees) if old_labels != labels changes[:labels] = [old_labels.map(&:hook_attrs), labels.map(&:hook_attrs)] @@ -423,7 +423,7 @@ module Issuable end if self.respond_to?(:total_time_spent) - old_total_time_spent = old_associations.fetch(:total_time_spent, nil) + old_total_time_spent = old_associations.fetch(:total_time_spent, total_time_spent) if old_total_time_spent != total_time_spent changes[:total_time_spent] = [old_total_time_spent, total_time_spent] diff --git a/app/models/concerns/noteable.rb b/app/models/concerns/noteable.rb index 183b902dd37..2dbe9360d42 100644 --- a/app/models/concerns/noteable.rb +++ b/app/models/concerns/noteable.rb @@ -67,6 +67,10 @@ module Noteable false end + def has_any_diff_note_positions? + notes.any? && DiffNotePosition.where(note: notes).exists? + end + def discussion_notes notes end diff --git a/app/models/concerns/partitioned_table.rb b/app/models/concerns/partitioned_table.rb new file mode 100644 index 00000000000..9f1cec5d520 --- /dev/null +++ b/app/models/concerns/partitioned_table.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module PartitionedTable + extend ActiveSupport::Concern + + class_methods do + attr_reader :partitioning_strategy + + PARTITIONING_STRATEGIES = { + monthly: Gitlab::Database::Partitioning::MonthlyStrategy + }.freeze + + def partitioned_by(partitioning_key, strategy:) + strategy_class = PARTITIONING_STRATEGIES[strategy.to_sym] || raise(ArgumentError, "Unknown partitioning strategy: #{strategy}") + + @partitioning_strategy = strategy_class.new(self, partitioning_key) + + Gitlab::Database::Partitioning::PartitionCreator.register(self) + end + end +end diff --git a/app/models/concerns/reactive_caching.rb b/app/models/concerns/reactive_caching.rb index d294563139c..5f30fc0c36c 100644 --- a/app/models/concerns/reactive_caching.rb +++ b/app/models/concerns/reactive_caching.rb @@ -29,7 +29,7 @@ module ReactiveCaching self.reactive_cache_lease_timeout = 2.minutes self.reactive_cache_refresh_interval = 1.minute self.reactive_cache_lifetime = 10.minutes - self.reactive_cache_hard_limit = 1.megabyte + self.reactive_cache_hard_limit = nil # this value should be set in megabytes. E.g: 1.megabyte self.reactive_cache_work_type = :default self.reactive_cache_worker_finder = ->(id, *_args) do find_by(primary_key => id) @@ -159,8 +159,12 @@ module ReactiveCaching WORK_TYPE.fetch(self.class.reactive_cache_work_type.to_sym) end + def reactive_cache_limit_enabled? + !!self.reactive_cache_hard_limit + end + def check_exceeded_reactive_cache_limit!(data) - return unless Feature.enabled?(:reactive_cache_limit) + return unless reactive_cache_limit_enabled? data_deep_size = Gitlab::Utils::DeepSize.new(data, max_size: self.class.reactive_cache_hard_limit) diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb index 129d0fbb2c0..c70ce9bebcc 100644 --- a/app/models/concerns/routable.rb +++ b/app/models/concerns/routable.rb @@ -17,11 +17,8 @@ module Routable after_validation :set_path_errors - before_validation do - if full_path_changed? || full_name_changed? - prepare_route - end - end + before_validation :prepare_route + before_save :prepare_route # in case validation is skipped end class_methods do @@ -118,6 +115,8 @@ module Routable end def prepare_route + return unless full_path_changed? || full_name_changed? + route || build_route(source: self) route.path = build_full_path route.name = build_full_name diff --git a/app/models/concerns/update_project_statistics.rb b/app/models/concerns/update_project_statistics.rb index 6cf012680d8..c0fa14d3369 100644 --- a/app/models/concerns/update_project_statistics.rb +++ b/app/models/concerns/update_project_statistics.rb @@ -35,8 +35,8 @@ module UpdateProjectStatistics @project_statistics_name = project_statistics_name @statistic_attribute = statistic_attribute - after_save(:update_project_statistics_after_save, if: :update_project_statistics_attribute_changed?) - after_destroy(:update_project_statistics_after_destroy, unless: :project_destroyed?) + after_save(:update_project_statistics_after_save, if: :update_project_statistics_after_save?) + after_destroy(:update_project_statistics_after_destroy, if: :update_project_statistics_after_destroy?) end private :update_project_statistics @@ -45,6 +45,14 @@ module UpdateProjectStatistics included do private + def update_project_statistics_after_save? + update_project_statistics_attribute_changed? + end + + def update_project_statistics_after_destroy? + !project_destroyed? + end + def update_project_statistics_after_save attr = self.class.statistic_attribute delta = read_attribute(attr).to_i - attribute_before_last_save(attr).to_i |