commit_status.rb 3.58 KB
Newer Older
1
class CommitStatus < ActiveRecord::Base
2
  include HasStatus
3
  include Importable
4
  include AfterCommitQueue
5

6 7
  self.table_name = 'ci_builds'

8
  belongs_to :project
9
  belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id
10 11
  belongs_to :user

12
  delegate :commit, to: :pipeline
Douwe Maan's avatar
Douwe Maan committed
13
  delegate :sha, :short_sha, to: :pipeline
14

15
  validates :pipeline, presence: true, unless: :importing?
16

Douwe Maan's avatar
Douwe Maan committed
17
  validates :name, presence: true
18

Kamil Trzcinski's avatar
Kamil Trzcinski committed
19 20
  alias_attribute :author, :user

21 22 23 24 25
  scope :latest, -> do
    max_id = unscope(:select).select("max(#{quoted_table_name}.id)")

    where(id: max_id.group(:name, :commit_id))
  end
26

27
  scope :failed_but_allowed, -> do
28
    where(allow_failure: true, status: [:failed, :canceled])
29
  end
30

31
  scope :exclude_ignored, -> do
32 33 34
    # We want to ignore failed but allowed to fail jobs.
    #
    # TODO, we also skip ignored optional manual actions.
35
    where("allow_failure = ? OR status IN (?)",
36
      false, all_state_names - [:failed, :canceled, :manual])
37
  end
38

39 40
  scope :retried, -> { where.not(id: latest) }
  scope :ordered, -> { order(:name) }
41 42
  scope :latest_ordered, -> { latest.ordered.includes(project: :namespace) }
  scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) }
43
  scope :after_stage, -> (index) { where('stage_idx > ?', index) }
44

45
  state_machine :status do
46
    event :enqueue do
47
      transition [:created, :skipped, :manual] => :pending
48 49
    end

50
    event :process do
51
      transition [:skipped, :manual] => :created
52 53
    end

54 55 56 57
    event :run do
      transition pending: :running
    end

58 59 60 61
    event :skip do
      transition [:created, :pending] => :skipped
    end

62
    event :drop do
63
      transition [:created, :pending, :running] => :failed
64 65 66
    end

    event :success do
67
      transition [:created, :pending, :running] => :success
68 69 70
    end

    event :cancel do
71
      transition [:created, :pending, :running, :manual] => :canceled
72 73
    end

Kamil Trzcinski's avatar
Kamil Trzcinski committed
74 75
    before_transition created: [:pending, :running] do |commit_status|
      commit_status.queued_at = Time.now
76 77
    end

Kamil Trzcinski's avatar
Kamil Trzcinski committed
78 79
    before_transition [:created, :pending] => :running do |commit_status|
      commit_status.started_at = Time.now
80 81
    end

Kamil Trzcinski's avatar
Kamil Trzcinski committed
82 83
    before_transition any => [:success, :failed, :canceled] do |commit_status|
      commit_status.finished_at = Time.now
84 85
    end

86
    after_transition do |commit_status, transition|
87
      next if transition.loopback?
88

89 90
      commit_status.run_after_commit do
        pipeline.try do |pipeline|
91
          if complete? || manual?
92
            PipelineProcessWorker.perform_async(pipeline.id)
93
          else
94
            PipelineUpdateWorker.perform_async(pipeline.id)
95
          end
96
        end
97
      end
98 99
    end

100
    after_transition any => :failed do |commit_status|
101
      commit_status.run_after_commit do
102 103
        MergeRequests::AddTodoWhenBuildFailsService
          .new(pipeline.project, nil).execute(self)
104
      end
105
    end
106 107
  end

108 109 110 111
  def locking_enabled?
    status_changed?
  end

112
  def before_sha
113
    pipeline.before_sha || Gitlab::Git::BLANK_SHA
114
  end
115

Kamil Trzcinski's avatar
Kamil Trzcinski committed
116
  def group_name
Kamil Trzcinski's avatar
Kamil Trzcinski committed
117
    name.gsub(/\d+[\s:\/\\]+\d+\s*/, '').strip
Kamil Trzcinski's avatar
Kamil Trzcinski committed
118 119
  end

120
  def failed_but_allowed?
121
    allow_failure? && (failed? || canceled?)
122 123
  end

124 125 126 127
  def duration
    calculate_duration
  end

Kamil Trzcinski's avatar
Kamil Trzcinski committed
128 129 130 131
  def playable?
    false
  end

132 133
  def stuck?
    false
134
  end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
135

136
  def has_trace?
137 138
    false
  end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
139

140 141 142 143 144 145
  # Added in 9.0 to keep backward compatibility for projects exported in 8.17
  # and prior.
  def gl_project_id
    'dummy'
  end

146
  def detailed_status(current_user)
147 148 149
    Gitlab::Ci::Status::Factory
      .new(self, current_user)
      .fabricate!
Kamil Trzcinski's avatar
Kamil Trzcinski committed
150
  end
151

Mike Greiling's avatar
Mike Greiling committed
152
  def sortable_name
153 154 155 156
    name.split(/(\d+)/).map do |v|
      v =~ /\d+/ ? v.to_i : v
    end
  end
157
end