Commit 8a59a0ad authored by Shinya Maeda's avatar Shinya Maeda Committed by Alessio Caiazza
Browse files

Add a new status to ci_builds.status

parent 52b6aadc3773
......@@ -113,7 +113,7 @@ def cancel
def unschedule
return respond_422 unless @build.scheduled?
@build.unschedule
@build.unschedule!
redirect_to build_path(@build)
end
......
......@@ -160,6 +160,22 @@ def retry(build, current_user)
transition created: :manual
end
event :schedule do
transition created: :scheduled
end
event :unschedule do
transition scheduled: :manual
end
before_transition created: :scheduled do |build|
build_build_schedule(execute_at: execute_at)
end
before_transition scheduled: any do |build|
build_schedule.delete!
end
after_transition any => [:pending] do |build|
build.run_after_commit do
BuildQueueWorker.perform_async(id)
......@@ -185,12 +201,6 @@ def retry(build, current_user)
end
end
after_transition any => [:manual] do |build|
build.run_after_commit do
build.schedule!
end
end
before_transition any => [:failed] do |build|
next unless build.project
next if build.retries_max.zero?
......@@ -233,25 +243,11 @@ def pages_generator?
end
def playable?
action? && (manual? || retryable?)
action? && (manual? || scheduled? || retryable?)
end
def schedulable?
manual? && options[:start_in].present?
end
def scheduled?
build_schedule.present?
end
def schedule!
return unless schedulable?
create_build_schedule!(execute_at: execute_at)
end
def unschedule!
build_schedule.delete!
self.when == 'delayed' && options[:start_in].present?
end
def execute_at
......@@ -259,7 +255,7 @@ def execute_at
end
def action?
%w[manual delayed].include?(self.when)
%w[manual scheduled].include?(self.when)
end
# rubocop: disable CodeReuse/ServiceClass
......
......@@ -8,14 +8,24 @@ class BuildSchedule < ActiveRecord::Base
belongs_to :build
validate :schedule_at_future
after_create :schedule, unless: :importing?
scope :stale, -> { where("execute_at < ?", Time.now) }
def execute_in
[0, self.execute_at - Time.now].max
end
private
def schedule_at_future
if self.execute_at < Time.now
errors.add(:execute_at, "Excute point must be somewhere in the future")
end
end
def schedule
run_after_commit do
Ci::BuildScheduleWorker.perform_at(self.execute_at, self.build_id)
......
......@@ -26,7 +26,7 @@ class CommitStatus < ActiveRecord::Base
scope :failed_but_allowed, -> do
where(allow_failure: true, status: [:failed, :canceled])
end
scope :exclude_ignored, -> do
# We want to ignore failed but allowed to fail jobs.
#
......@@ -71,7 +71,7 @@ class CommitStatus < ActiveRecord::Base
end
event :enqueue do
transition [:created, :skipped, :manual] => :pending
transition [:created, :skipped, :manual, :scheduled] => :pending
end
event :run do
......@@ -91,10 +91,10 @@ class CommitStatus < ActiveRecord::Base
end
event :cancel do
transition [:created, :pending, :running, :manual] => :canceled
transition [:created, :pending, :running, :manual, :scheduled] => :canceled
end
before_transition [:created, :skipped, :manual] => :pending do |commit_status|
before_transition [:created, :skipped, :manual, :scheduled] => :pending do |commit_status|
commit_status.queued_at = Time.now
end
......
......@@ -4,14 +4,15 @@ module HasStatus
extend ActiveSupport::Concern
DEFAULT_STATUS = 'created'.freeze
BLOCKED_STATUS = 'manual'.freeze
AVAILABLE_STATUSES = %w[created pending running success failed canceled skipped manual].freeze
STARTED_STATUSES = %w[running success failed skipped manual].freeze
BLOCKED_STATUS = %w[manual scheduled].freeze
AVAILABLE_STATUSES = %w[created pending running success failed canceled skipped manual scheduled].freeze
STARTED_STATUSES = %w[running success failed skipped manual scheduled].freeze
ACTIVE_STATUSES = %w[pending running].freeze
COMPLETED_STATUSES = %w[success failed canceled skipped].freeze
ORDERED_STATUSES = %w[failed pending running manual canceled success skipped created].freeze
ORDERED_STATUSES = %w[failed pending running manual scheduled canceled success skipped created].freeze
STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3,
failed: 4, canceled: 5, skipped: 6, manual: 7 }.freeze
failed: 4, canceled: 5, skipped: 6, manual: 7,
scheduled: 8 }.freeze
UnknownStatusError = Class.new(StandardError)
......@@ -24,6 +25,7 @@ def status_sql
created = scope_relevant.created.select('count(*)').to_sql
success = scope_relevant.success.select('count(*)').to_sql
manual = scope_relevant.manual.select('count(*)').to_sql
scheduled = scope_relevant.scheduled.select('count(*)').to_sql
pending = scope_relevant.pending.select('count(*)').to_sql
running = scope_relevant.running.select('count(*)').to_sql
skipped = scope_relevant.skipped.select('count(*)').to_sql
......@@ -31,6 +33,7 @@ def status_sql
warnings = scope_warnings.select('count(*) > 0').to_sql.presence || 'false'
"(CASE
WHEN (#{scheduled})>0 THEN 'scheduled'
WHEN (#{builds})=(#{skipped}) AND (#{warnings}) THEN 'success'
WHEN (#{builds})=(#{skipped}) THEN 'skipped'
WHEN (#{builds})=(#{success}) THEN 'success'
......@@ -92,8 +95,7 @@ def all_state_names
scope :failed_or_canceled, -> { where(status: [:failed, :canceled]) }
scope :cancelable, -> do
where("status IN ('running', 'pending', 'created') OR " \
"(status = 'manual' AND EXISTS (select 1 from ci_build_schedules where ci_builds.id = ci_build_schedules.build_id))")
where("status IN ('running', 'pending', 'created', 'scheduled')")
end
end
......
......@@ -37,7 +37,7 @@ def process_stage(index)
def process_build(build, current_status)
if valid_statuses_for_when(build.when).include?(current_status)
build.action? ? build.actionize : enqueue_build(build)
proceed_build(build)
true
else
build.skip
......@@ -53,8 +53,10 @@ def valid_statuses_for_when(value)
%w[failed]
when 'always'
%w[success failed skipped]
when 'manual', 'delayed'
when 'manual'
%w[success skipped]
when 'delayed'
%w[success skipped] # This might be `success` only
else
[]
end
......@@ -102,8 +104,14 @@ def update_retried
end
# rubocop: enable CodeReuse/ActiveRecord
def enqueue_build(build)
Ci::EnqueueBuildService.new(project, @user).execute(build)
def proceed_build(build)
if build.schedulable?
build.schedule!
elsif build.action?
build.actionize
else
Ci::EnqueueBuildService.new(project, @user).execute(build)
end
end
end
end
......@@ -6,10 +6,9 @@ class BuildScheduleWorker
include PipelineQueue
def perform(build_id)
::Ci::Build.preload(:build_schedule).find_by(id: build_id).try do |build|
::Ci::Build.find_by(id: build_id).try do |build|
break unless build.scheduled?
build.unschedule!
Ci::PlayBuildService.new(build.project, build.user).execute(build)
end
end
......
......@@ -151,7 +151,7 @@ class Jobs < Grape::API
present build, with: Entities::Job
end
desc 'Trigger a manual job' do
desc 'Trigger a actionable job (manual, scheduled, etc)' do
success Entities::Job
detail 'This feature was added in GitLab 8.11'
end
......
......@@ -35,11 +35,11 @@ class Job < Node
validates :dependencies, array_of_strings: true
validates :extends, type: String
with_options if: :manual_action? do
validates :start_in, duration: true, allow_nil: true
with_options if: :delayed? do
validates :start_in, duration: true, allow_nil: false
end
with_options unless: :manual_action? do
with_options unless: :delayed? do
validates :start_in, presence: false
end
end
......@@ -119,7 +119,11 @@ def commands
end
def manual_action?
%w[manual delayed].include?(self.when)
self.when == 'manual'
end
def delayed?
self.when == 'delayed'
end
def ignored?
......
......@@ -39,7 +39,7 @@ def status_tooltip
end
def self.matches?(build, user)
build.schedulable? && !build.canceled?
build.scheduled?
end
private
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment