diff options
-rw-r--r-- | app/controllers/projects/jobs_controller.rb | 2 | ||||
-rw-r--r-- | app/models/ci/build.rb | 42 | ||||
-rw-r--r-- | app/models/ci/build_schedule.rb | 10 | ||||
-rw-r--r-- | app/models/commit_status.rb | 8 | ||||
-rw-r--r-- | app/models/concerns/has_status.rb | 16 | ||||
-rw-r--r-- | app/services/ci/process_pipeline_service.rb | 16 | ||||
-rw-r--r-- | app/workers/ci/build_schedule_worker.rb | 3 | ||||
-rw-r--r-- | lib/api/jobs.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/ci/config/entry/job.rb | 12 | ||||
-rw-r--r-- | lib/gitlab/ci/status/build/scheduled.rb | 2 |
10 files changed, 66 insertions, 47 deletions
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index d4a0af6f0f9..9c9bbe04947 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -113,7 +113,7 @@ class Projects::JobsController < Projects::ApplicationController def unschedule return respond_422 unless @build.scheduled? - @build.unschedule + @build.unschedule! redirect_to build_path(@build) end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index b608bfdb8b9..3ef149f3632 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -160,6 +160,22 @@ module Ci 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 @@ module Ci 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 @@ module Ci 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 @@ module Ci end def action? - %w[manual delayed].include?(self.when) + %w[manual scheduled].include?(self.when) end # rubocop: disable CodeReuse/ServiceClass diff --git a/app/models/ci/build_schedule.rb b/app/models/ci/build_schedule.rb index d6378224fe0..4128fade86c 100644 --- a/app/models/ci/build_schedule.rb +++ b/app/models/ci/build_schedule.rb @@ -8,14 +8,24 @@ module Ci 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) diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index fe2f144ef03..6bf2888505e 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -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 diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb index e2700db1438..0a97e4cdfc4 100644 --- a/app/models/concerns/has_status.rb +++ b/app/models/concerns/has_status.rb @@ -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 @@ module HasStatus 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 @@ module HasStatus 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 @@ module HasStatus 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 diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb index 323075d404b..0a13da198cd 100644 --- a/app/services/ci/process_pipeline_service.rb +++ b/app/services/ci/process_pipeline_service.rb @@ -37,7 +37,7 @@ module Ci 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 @@ module Ci %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 @@ module Ci 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 diff --git a/app/workers/ci/build_schedule_worker.rb b/app/workers/ci/build_schedule_worker.rb index 84ef2edb767..0d17a960c00 100644 --- a/app/workers/ci/build_schedule_worker.rb +++ b/app/workers/ci/build_schedule_worker.rb @@ -6,10 +6,9 @@ module Ci 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 diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb index 63fab6b0abb..fa992b9a440 100644 --- a/lib/api/jobs.rb +++ b/lib/api/jobs.rb @@ -151,7 +151,7 @@ module 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 diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index 02589d147ef..3ad048883af 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -35,11 +35,11 @@ module Gitlab 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 @@ module Gitlab end def manual_action? - %w[manual delayed].include?(self.when) + self.when == 'manual' + end + + def delayed? + self.when == 'delayed' end def ignored? diff --git a/lib/gitlab/ci/status/build/scheduled.rb b/lib/gitlab/ci/status/build/scheduled.rb index 93da8fb9538..010d5e2142f 100644 --- a/lib/gitlab/ci/status/build/scheduled.rb +++ b/lib/gitlab/ci/status/build/scheduled.rb @@ -39,7 +39,7 @@ module Gitlab end def self.matches?(build, user) - build.schedulable? && !build.canceled? + build.scheduled? end private |