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

jira_import_state.rb « models « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 2d952c552a80956de58275a2f4afb76982f4eea5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# frozen_string_literal: true

class JiraImportState < ApplicationRecord
  include AfterCommitQueue
  include ImportState::SidekiqJobTracker
  include UsageStatistics

  self.table_name = 'jira_imports'

  ERROR_MESSAGE_SIZE = 1000 # 1000 characters limit
  STATUSES = { initial: 0, scheduled: 1, started: 2, failed: 3, finished: 4 }.freeze

  belongs_to :project
  belongs_to :user
  belongs_to :label

  scope :by_jira_project_key, -> (jira_project_key) { where(jira_project_key: jira_project_key) }
  scope :with_status, ->(statuses) { where(status: statuses) }

  validates :project, presence: true
  validates :jira_project_key, presence: true
  validates :jira_project_name, presence: true
  validates :jira_project_xid, presence: true

  validates :project, uniqueness: {
    conditions: -> { where.not(status: STATUSES.values_at(:failed, :finished)) },
    message: _('Cannot have multiple Jira imports running at the same time')
  }

  before_save :ensure_error_message_size

  alias_method :scheduled_by, :user

  state_machine :status, initial: :initial do
    event :schedule do
      transition initial: :scheduled
    end

    event :start do
      transition scheduled: :started
    end

    event :finish do
      transition started: :finished
    end

    event :do_fail do
      transition [:initial, :scheduled, :started] => :failed
    end

    after_transition initial: :scheduled do |state, _|
      state.run_after_commit do
        job_id = Gitlab::JiraImport::Stage::StartImportWorker.perform_async(project.id)
        state.update(jid: job_id, scheduled_at: Time.current) if job_id
      end
    end

    before_transition any => :finished do |state, _|
      InternalId.flush_records!(project: state.project)
      state.project.update_project_counter_caches
      state.store_issue_counts
    end

    after_transition any => :finished do |state, _|
      if state.jid.present?
        Gitlab::SidekiqStatus.unset(state.jid)

        state.update_column(:jid, nil)
      end
    end

    after_transition any => :failed do |state, transition|
      arguments_hash = transition.args.first
      error_message = arguments_hash&.dig(:error_message)

      state.update_column(:error_message, error_message) if error_message.present?
    end

    # Supress warning:
    # both JiraImportState and its :status machine have defined a different default for "status".
    # although both have same value but represented in 2 ways: integer(0) and symbol(:initial)
    def owner_class_attribute_default
      'initial'
    end
  end

  enum status: STATUSES

  def in_progress?
    scheduled? || started?
  end

  def non_initial?
    !initial?
  end

  def store_issue_counts
    import_label_id = Gitlab::JiraImport.get_import_label_id(project.id)

    failed_to_import_count = Gitlab::JiraImport.issue_failures(project.id)
    successfully_imported_count = project.issues.with_label_ids(import_label_id).count
    total_issue_count = successfully_imported_count + failed_to_import_count

    update(
      {
        failed_to_import_count: failed_to_import_count,
        imported_issues_count: successfully_imported_count,
        total_issue_count: total_issue_count
      }
    )
  end

  def self.finished_imports_count
    finished.sum(:imported_issues_count)
  end

  def mark_as_failed(error_message)
    sanitized_message = Gitlab::UrlSanitizer.sanitize(error_message)

    do_fail(error_message: error_message)
  rescue ActiveRecord::ActiveRecordError => e
    Gitlab::AppLogger.error("Error setting import status to failed: #{e.message}. Original error: #{sanitized_message}")
  end

  private

  def ensure_error_message_size
    self.error_message = error_message&.truncate(ERROR_MESSAGE_SIZE)
  end
end