diff options
Diffstat (limited to 'app/models/issue.rb')
-rw-r--r-- | app/models/issue.rb | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/app/models/issue.rb b/app/models/issue.rb index bea86168c8d..a19b5809ff8 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -63,7 +63,24 @@ class Issue < ApplicationRecord belongs_to :moved_to, class_name: 'Issue' has_one :moved_from, class_name: 'Issue', foreign_key: :moved_to_id - has_internal_id :iid, scope: :project, track_if: -> { !importing? } + has_internal_id :iid, scope: :namespace, track_if: -> { !importing? }, init: ->(issue, scope) do + # we need this init for the case where the IID allocation in internal_ids#last_value + # is higher than the actual issues.max(iid) value for a given project. For instance + # in case of an import where a batch of IIDs may be prealocated + # + # TODO: remove this once the UpdateIssuesInternalIdScope migration completes + if issue + [ + InternalId.where(project: issue.project, usage: :issues).pick(:last_value).to_i, + issue.namespace&.issues&.maximum(:iid).to_i + ].max + else + [ + InternalId.where(**scope, usage: :issues).pick(:last_value).to_i, + where(**scope).maximum(:iid).to_i + ].max + end + end has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent @@ -104,10 +121,11 @@ class Issue < ApplicationRecord accepts_nested_attributes_for :sentry_issue accepts_nested_attributes_for :incident_management_issuable_escalation_status, update_only: true - validates :project, presence: true + validates :project, presence: true, if: -> { !namespace || namespace.is_a?(Namespaces::ProjectNamespace) } validates :issue_type, presence: true validates :namespace, presence: true validates :work_item_type, presence: true + validates :confidential, inclusion: { in: [true, false], message: 'must be a boolean' } validate :allowed_work_item_type_change, on: :update, if: :work_item_type_id_changed? validate :due_date_after_start_date @@ -136,7 +154,7 @@ class Issue < ApplicationRecord scope :order_due_date_asc, -> { reorder(arel_table[:due_date].asc.nulls_last) } scope :order_due_date_desc, -> { reorder(arel_table[:due_date].desc.nulls_last) } - scope :order_closest_future_date, -> { reorder(Arel.sql('CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC')) } + scope :order_closest_future_date, -> { reorder(Arel.sql("CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC")) } scope :order_created_at_desc, -> { reorder(created_at: :desc) } scope :order_severity_asc, -> do build_keyset_order_on_joined_column( @@ -162,15 +180,15 @@ class Issue < ApplicationRecord scope :order_closed_at_desc, -> { reorder(arel_table[:closed_at].desc.nulls_last) } scope :preload_associated_models, -> { preload(:assignees, :labels, project: :namespace) } - scope :with_web_entity_associations, -> { preload(:author, project: [:project_feature, :route, namespace: :route]) } + scope :with_web_entity_associations, -> { preload(:author, :namespace, project: [:project_feature, :route, namespace: :route]) } scope :preload_awardable, -> { preload(:award_emoji) } scope :with_alert_management_alerts, -> { joins(:alert_management_alert) } scope :with_prometheus_alert_events, -> { joins(:issues_prometheus_alert_events) } scope :with_self_managed_prometheus_alert_events, -> { joins(:issues_self_managed_prometheus_alert_events) } scope :with_api_entity_associations, -> { - preload(:timelogs, :closed_by, :assignees, :author, :labels, :issuable_severity, + preload(:timelogs, :closed_by, :assignees, :author, :labels, :issuable_severity, namespace: [{ parent: :route }, :route], milestone: { project: [:route, { namespace: :route }] }, - project: [:project_feature, :route, { namespace: :route }], + project: [:project_namespace, :project_feature, :route, { group: :route }, { namespace: :route }], duplicated_to: { project: [:project_feature] }) } scope :with_issue_type, ->(types) { where(issue_type: types) } @@ -214,7 +232,7 @@ class Issue < ApplicationRecord before_validation :ensure_namespace_id, :ensure_work_item_type - after_save :ensure_metrics, unless: :importing? + after_save :ensure_metrics!, unless: :importing? after_commit :expire_etag_cache, unless: :importing? after_create_commit :record_create_action, unless: :importing? @@ -345,7 +363,7 @@ class Issue < ApplicationRecord end def self.link_reference_pattern - @link_reference_pattern ||= super(%r{issues(?:\/incident)?}, Gitlab::Regex.issue) + @link_reference_pattern ||= compose_link_reference_pattern(%r{issues(?:\/incident)?}, Gitlab::Regex.issue) end def self.reference_valid?(reference) @@ -450,7 +468,7 @@ class Issue < ApplicationRecord def to_reference(from = nil, full: false) reference = "#{self.class.reference_prefix}#{iid}" - "#{project.to_reference_base(from, full: full)}#{reference}" + "#{namespace.to_reference_base(from, full: full)}#{reference}" end def suggested_branch_name @@ -463,7 +481,7 @@ class Issue < ApplicationRecord "#{to_branch_name}-#{suffix}" end - Uniquify.new(start_counting_from).string(branch_name_generator) do |suggested_branch_name| + Gitlab::Utils::Uniquify.new(start_counting_from).string(branch_name_generator) do |suggested_branch_name| project.repository.branch_exists?(suggested_branch_name) end end @@ -722,8 +740,7 @@ class Issue < ApplicationRecord confidential_changed?(from: true, to: false) end - override :ensure_metrics - def ensure_metrics + def ensure_metrics! Issue::Metrics.record!(self) end |