3f6f2bbe14
Create a todo on failing MR build Implements #14067. I worked on this with @DouweM (any mistakes are mine). When a build fails for a commit, create a todo for the author of the merge request that commit is the HEAD of. If the commit isn't the HEAD commit of any MR, don't do anything. If there already is a todo for that user and MR, don't do anything. Current limitations: - This isn't configurable by project. - The author of a merge request might not be the person who pushed the breaking commit. - I haven't tested this with a working CI setup, just with the unit tests below and by modifying my DB directly. See merge request !3177
92 lines
2.4 KiB
Ruby
92 lines
2.4 KiB
Ruby
class CommitStatus < ActiveRecord::Base
|
|
include Statuseable
|
|
|
|
self.table_name = 'ci_builds'
|
|
|
|
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
|
|
belongs_to :commit, class_name: 'Ci::Commit', touch: true
|
|
belongs_to :user
|
|
|
|
validates :commit, presence: true
|
|
|
|
validates_presence_of :name
|
|
|
|
alias_attribute :author, :user
|
|
|
|
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :commit_id)) }
|
|
scope :retried, -> { where.not(id: latest) }
|
|
scope :ordered, -> { order(:name) }
|
|
scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
|
|
|
|
state_machine :status, initial: :pending do
|
|
event :run do
|
|
transition pending: :running
|
|
end
|
|
|
|
event :drop do
|
|
transition [:pending, :running] => :failed
|
|
end
|
|
|
|
event :success do
|
|
transition [:pending, :running] => :success
|
|
end
|
|
|
|
event :cancel do
|
|
transition [:pending, :running] => :canceled
|
|
end
|
|
|
|
after_transition pending: :running do |commit_status|
|
|
commit_status.update_attributes started_at: Time.now
|
|
end
|
|
|
|
after_transition any => [:success, :failed, :canceled] do |commit_status|
|
|
commit_status.update_attributes finished_at: Time.now
|
|
end
|
|
|
|
after_transition [:pending, :running] => :success do |commit_status|
|
|
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.commit.project, nil).trigger(commit_status)
|
|
end
|
|
|
|
after_transition any => :failed do |commit_status|
|
|
MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.commit.project, nil).execute(commit_status)
|
|
end
|
|
end
|
|
|
|
delegate :sha, :short_sha, to: :commit
|
|
|
|
def before_sha
|
|
commit.before_sha || Gitlab::Git::BLANK_SHA
|
|
end
|
|
|
|
def self.stages
|
|
# We group by stage name, but order stages by theirs' index
|
|
unscoped.from(all, :sg).group('stage').order('max(stage_idx)', 'stage').pluck('sg.stage')
|
|
end
|
|
|
|
def self.stages_status
|
|
# We execute subquery for each stage to calculate a stage status
|
|
statuses = unscoped.from(all, :sg).group('stage').pluck('sg.stage', all.where('stage=sg.stage').status_sql)
|
|
statuses.inject({}) do |h, k|
|
|
h[k.first] = k.last
|
|
h
|
|
end
|
|
end
|
|
|
|
def ignored?
|
|
allow_failure? && (failed? || canceled?)
|
|
end
|
|
|
|
def duration
|
|
duration =
|
|
if started_at && finished_at
|
|
finished_at - started_at
|
|
elsif started_at
|
|
Time.now - started_at
|
|
end
|
|
duration
|
|
end
|
|
|
|
def stuck?
|
|
false
|
|
end
|
|
end
|