diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-14 03:09:07 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-14 03:09:07 +0300 |
commit | e144369009f3404072f7e0f969f7cded93195a01 (patch) | |
tree | d7a354e2c3c69a7ad65dc81aba8fe2ba59b0a26f /app/models | |
parent | d466ee5042520ad078fe050cb078d81dc2ebe196 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/concerns/issuable.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/mentionable.rb | 17 | ||||
-rw-r--r-- | app/models/deployment.rb | 1 | ||||
-rw-r--r-- | app/models/environment.rb | 39 | ||||
-rw-r--r-- | app/models/issue.rb | 2 | ||||
-rw-r--r-- | app/models/merge_request.rb | 6 | ||||
-rw-r--r-- | app/models/note.rb | 5 | ||||
-rw-r--r-- | app/models/snippet.rb | 4 |
8 files changed, 69 insertions, 6 deletions
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index f3e03ed22d7..78d815e5858 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -91,6 +91,7 @@ module Issuable validate :description_max_length_for_new_records_is_valid, on: :update before_validation :truncate_description_on_import! + after_save :store_mentions!, if: :any_mentionable_attributes_changed? scope :authored, ->(user) { where(author_id: user) } scope :recent, -> { reorder(id: :desc) } diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb index b43b91699ab..d157404f7bc 100644 --- a/app/models/concerns/mentionable.rb +++ b/app/models/concerns/mentionable.rb @@ -99,18 +99,23 @@ module Mentionable # threw the `ActiveRecord::RecordNotUnique` exception in first place. self.class.safe_ensure_unique(retries: 1) do user_mention = model_user_mention + + # this may happen due to notes polymorphism, so noteable_id may point to a record that no longer exists + # as we cannot have FK on noteable_id + break if user_mention.blank? + user_mention.mentioned_users_ids = references[:mentioned_users_ids] user_mention.mentioned_groups_ids = references[:mentioned_groups_ids] user_mention.mentioned_projects_ids = references[:mentioned_projects_ids] if user_mention.has_mentions? user_mention.save! - elsif user_mention.persisted? + else user_mention.destroy! end - - true end + + true end def referenced_users @@ -218,6 +223,12 @@ module Mentionable source.select { |key, val| mentionable.include?(key) } end + def any_mentionable_attributes_changed? + self.class.mentionable_attrs.any? do |attr| + saved_changes.key?(attr.first) + end + end + # Determine whether or not a cross-reference Note has already been created between this Mentionable and # the specified target. def cross_reference_exists?(target) diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 0c679a3075b..5450357fe1b 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -39,6 +39,7 @@ class Deployment < ApplicationRecord scope :for_status, -> (status) { where(status: status) } scope :visible, -> { where(status: %i[running success failed canceled]) } + scope :stoppable, -> { where.not(on_stop: nil).where.not(deployable_id: nil).success } state_machine :status, initial: :created do event :run do diff --git a/app/models/environment.rb b/app/models/environment.rb index 973f1243e6b..4635b05fcc7 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -61,6 +61,7 @@ class Environment < ApplicationRecord scope :in_review_folder, -> { where(environment_type: "review") } scope :for_name, -> (name) { where(name: name) } scope :preload_cluster, -> { preload(last_deployment: :cluster) } + scope :auto_stoppable, -> (limit) { available.where('auto_stop_at < ?', Time.zone.now).limit(limit) } ## # Search environments which have names like the given query. @@ -107,6 +108,44 @@ class Environment < ApplicationRecord find_or_create_by(name: name) end + class << self + ## + # This method returns stop actions (jobs) for multiple environments within one + # query. It's useful to avoid N+1 problem. + # + # NOTE: The count of environments should be small~medium (e.g. < 5000) + def stop_actions + cte = cte_for_deployments_with_stop_action + ci_builds = Ci::Build.arel_table + + inner_join_stop_actions = ci_builds.join(cte.table).on( + ci_builds[:project_id].eq(cte.table[:project_id]) + .and(ci_builds[:ref].eq(cte.table[:ref])) + .and(ci_builds[:name].eq(cte.table[:on_stop])) + ).join_sources + + pipeline_ids = ci_builds.join(cte.table).on( + ci_builds[:id].eq(cte.table[:deployable_id]) + ).project(:commit_id) + + Ci::Build.joins(inner_join_stop_actions) + .with(cte.to_arel) + .where(ci_builds[:commit_id].in(pipeline_ids)) + .where(status: HasStatus::BLOCKED_STATUS) + .preload_project_and_pipeline_project + .preload(:user, :metadata, :deployment) + end + + private + + def cte_for_deployments_with_stop_action + Gitlab::SQL::CTE.new(:deployments_with_stop_action, + Deployment.where(environment_id: select(:id)) + .distinct_on_environment + .stoppable) + end + end + def clear_prometheus_reactive_cache!(query_name) cluster_prometheus_adapter&.clear_prometheus_reactive_cache!(query_name, self) end diff --git a/app/models/issue.rb b/app/models/issue.rb index 684108b1a7a..d01aa78a2c1 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -45,7 +45,7 @@ class Issue < ApplicationRecord has_many :issue_assignees has_many :assignees, class_name: "User", through: :issue_assignees has_many :zoom_meetings - has_many :user_mentions, class_name: "IssueUserMention" + has_many :user_mentions, class_name: "IssueUserMention", dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent has_one :sentry_issue accepts_nested_attributes_for :sentry_issue diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index b8f51b58fd3..14aa6ac066e 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -77,7 +77,7 @@ class MergeRequest < ApplicationRecord has_many :merge_request_assignees has_many :assignees, class_name: "User", through: :merge_request_assignees - has_many :user_mentions, class_name: "MergeRequestUserMention" + has_many :user_mentions, class_name: "MergeRequestUserMention", dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent has_many :deployment_merge_requests @@ -840,6 +840,10 @@ class MergeRequest < ApplicationRecord end # rubocop: enable CodeReuse/ServiceClass + def diffable_merge_ref? + Feature.enabled?(:diff_compare_with_head, target_project) && can_be_merged? && merge_ref_head.present? + end + # Returns boolean indicating the merge_status should be rechecked in order to # switch to either can_be_merged or cannot_be_merged. def recheck_merge_status? diff --git a/app/models/note.rb b/app/models/note.rb index 8af650e27aa..97e84bb79f6 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -157,6 +157,7 @@ class Note < ApplicationRecord after_save :expire_etag_cache, unless: :importing? after_save :touch_noteable, unless: :importing? after_destroy :expire_etag_cache + after_save :store_mentions!, if: :any_mentionable_attributes_changed? class << self def model_name @@ -498,6 +499,8 @@ class Note < ApplicationRecord end def user_mentions + return Note.none unless noteable.present? + noteable.user_mentions.where(note: self) end @@ -506,6 +509,8 @@ class Note < ApplicationRecord # Using this method followed by a call to `save` may result in ActiveRecord::RecordNotUnique exception # in a multithreaded environment. Make sure to use it within a `safe_ensure_unique` block. def model_user_mention + return if user_mentions.is_a?(ActiveRecord::NullRelation) + user_mentions.first_or_initialize end diff --git a/app/models/snippet.rb b/app/models/snippet.rb index e2b72dfde7a..4ba8e6a94e6 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -41,7 +41,7 @@ class Snippet < ApplicationRecord belongs_to :project has_many :notes, as: :noteable, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent - has_many :user_mentions, class_name: "SnippetUserMention" + has_many :user_mentions, class_name: "SnippetUserMention", dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent has_one :snippet_repository, inverse_of: :snippet delegate :name, :email, to: :author, prefix: true, allow_nil: true @@ -66,6 +66,8 @@ class Snippet < ApplicationRecord validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values } + after_save :store_mentions!, if: :any_mentionable_attributes_changed? + # Scopes scope :are_internal, -> { where(visibility_level: Snippet::INTERNAL) } scope :are_private, -> { where(visibility_level: Snippet::PRIVATE) } |