Squashed commit of the following:
commit 9d9594ba20097dc4598f7eb42a9f9d78d73eae54 Author: Shinya Maeda <shinya@gitlab.com> Date: Thu Sep 13 20:18:31 2018 +0900 Cancel scheduled jobs commit f31c7172e07a9eb03b58c1e62eaa18cda4064aa6 Author: Shinya Maeda <shinya@gitlab.com> Date: Thu Sep 13 11:18:42 2018 +0900 Add Ci::BuildSchedule commit fb6b3ca638f40f9e1ee38b1fdd892bda4f6fede7 Author: Shinya Maeda <shinya@gitlab.com> Date: Wed Sep 12 20:02:50 2018 +0900 Scheduled jobs
This commit is contained in:
parent
d5184e0d8b
commit
3fc4c096a5
16 changed files with 160 additions and 4 deletions
Binary file not shown.
After Width: | Height: | Size: 176 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -22,6 +22,7 @@ module Ci
|
|||
}.freeze
|
||||
|
||||
has_one :last_deployment, -> { order('deployments.id DESC') }, as: :deployable, class_name: 'Deployment'
|
||||
has_one :build_schedule, class_name: 'Ci::BuildSchedule', foreign_key: :build_id
|
||||
has_many :trace_sections, class_name: 'Ci::BuildTraceSection'
|
||||
has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id
|
||||
|
||||
|
@ -184,6 +185,12 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
after_transition any => [:manual] do |build|
|
||||
build.run_after_commit do
|
||||
build.schedule_delayed_execution
|
||||
end
|
||||
end
|
||||
|
||||
before_transition any => [:failed] do |build|
|
||||
next unless build.project
|
||||
next if build.retries_max.zero?
|
||||
|
@ -229,6 +236,20 @@ module Ci
|
|||
action? && (manual? || retryable?)
|
||||
end
|
||||
|
||||
def autoplay?
|
||||
manual? && options[:autoplay_in].present?
|
||||
end
|
||||
|
||||
def autoplay_at
|
||||
ChronicDuration.parse(options[:autoplay_in])&.seconds&.from_now
|
||||
end
|
||||
|
||||
def schedule_delayed_execution
|
||||
return unless autoplay?
|
||||
|
||||
create_build_schedule!(execute_at: autoplay_at)
|
||||
end
|
||||
|
||||
def action?
|
||||
self.when == 'manual'
|
||||
end
|
||||
|
|
25
app/models/ci/build_schedule.rb
Normal file
25
app/models/ci/build_schedule.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class BuildSchedule < ActiveRecord::Base
|
||||
extend Gitlab::Ci::Model
|
||||
include Importable
|
||||
include AfterCommitQueue
|
||||
|
||||
belongs_to :build
|
||||
|
||||
after_create :schedule, unless: :importing?
|
||||
|
||||
def execute_in
|
||||
self.execute_at - Time.now
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def schedule
|
||||
run_after_commit do
|
||||
Ci::BuildScheduleWorker.perform_at(self.execute_at, self.build_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -92,7 +92,8 @@ module HasStatus
|
|||
scope :failed_or_canceled, -> { where(status: [:failed, :canceled]) }
|
||||
|
||||
scope :cancelable, -> do
|
||||
where(status: [:running, :pending, :created])
|
||||
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))")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 15 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 15 KiB |
|
@ -60,6 +60,7 @@
|
|||
- pipeline_default:build_trace_sections
|
||||
- pipeline_default:pipeline_metrics
|
||||
- pipeline_default:pipeline_notification
|
||||
- pipeline_default:ci_build_schedule
|
||||
- pipeline_hooks:build_hooks
|
||||
- pipeline_hooks:pipeline_hooks
|
||||
- pipeline_processing:build_finished
|
||||
|
|
|
@ -9,6 +9,7 @@ class BuildFinishedWorker
|
|||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def perform(build_id)
|
||||
Ci::Build.find_by(id: build_id).try do |build|
|
||||
build&.build_schedule&.delete
|
||||
# We execute that in sync as this access the files in order to access local file, and reduce IO
|
||||
BuildTraceSectionsWorker.new.perform(build.id)
|
||||
BuildCoverageWorker.new.perform(build.id)
|
||||
|
|
16
app/workers/ci/build_schedule_worker.rb
Normal file
16
app/workers/ci/build_schedule_worker.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class BuildScheduleWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
||||
def perform(build_id)
|
||||
::Ci::Build.preload(:build_schedule).find_by(id: build_id).try do |build|
|
||||
break unless build.build_schedule.present?
|
||||
|
||||
Ci::PlayBuildService.new(build.project, build.user).execute(build)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
db/migrate/20180913102839_create_build_schedules.rb
Normal file
19
db/migrate/20180913102839_create_build_schedules.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateBuildSchedules < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
create_table :ci_build_schedules, id: :bigserial do |t|
|
||||
t.integer :build_id, null: false
|
||||
t.datetime :execute_at, null: false
|
||||
|
||||
t.foreign_key :ci_builds, column: :build_id, on_delete: :cascade
|
||||
t.index :build_id, unique: true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -260,6 +260,13 @@ ActiveRecord::Schema.define(version: 20180924141949) do
|
|||
|
||||
add_index "chat_teams", ["namespace_id"], name: "index_chat_teams_on_namespace_id", unique: true, using: :btree
|
||||
|
||||
create_table "ci_build_schedules", id: :bigserial, force: :cascade do |t|
|
||||
t.integer "build_id", null: false
|
||||
t.datetime "execute_at", null: false
|
||||
end
|
||||
|
||||
add_index "ci_build_schedules", ["build_id"], name: "index_ci_build_schedules_on_build_id", unique: true, using: :btree
|
||||
|
||||
create_table "ci_build_trace_chunks", id: :bigserial, force: :cascade do |t|
|
||||
t.integer "build_id", null: false
|
||||
t.integer "chunk_index", null: false
|
||||
|
@ -2288,6 +2295,7 @@ ActiveRecord::Schema.define(version: 20180924141949) do
|
|||
add_foreign_key "boards", "namespaces", column: "group_id", on_delete: :cascade
|
||||
add_foreign_key "boards", "projects", name: "fk_f15266b5f9", on_delete: :cascade
|
||||
add_foreign_key "chat_teams", "namespaces", on_delete: :cascade
|
||||
add_foreign_key "ci_build_schedules", "ci_builds", column: "build_id", on_delete: :cascade
|
||||
add_foreign_key "ci_build_trace_chunks", "ci_builds", column: "build_id", on_delete: :cascade
|
||||
add_foreign_key "ci_build_trace_section_names", "projects", on_delete: :cascade
|
||||
add_foreign_key "ci_build_trace_sections", "ci_build_trace_section_names", column: "section_name_id", name: "fk_264e112c66", on_delete: :cascade
|
||||
|
|
|
@ -10,7 +10,7 @@ module Gitlab
|
|||
include Attributable
|
||||
|
||||
ALLOWED_KEYS = %i[tags script only except type image services
|
||||
allow_failure type stage when artifacts cache
|
||||
allow_failure type stage when autoplay_in artifacts cache
|
||||
dependencies before_script after_script variables
|
||||
environment coverage retry extends].freeze
|
||||
|
||||
|
@ -34,6 +34,14 @@ module Gitlab
|
|||
|
||||
validates :dependencies, array_of_strings: true
|
||||
validates :extends, type: String
|
||||
|
||||
with_options if: :manual_action? do
|
||||
validates :autoplay_in, duration: true, allow_nil: true
|
||||
end
|
||||
|
||||
with_options unless: :manual_action? do
|
||||
validates :autoplay_in, presence: false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -84,7 +92,7 @@ module Gitlab
|
|||
:artifacts, :commands, :environment, :coverage, :retry
|
||||
|
||||
attributes :script, :tags, :allow_failure, :when, :dependencies,
|
||||
:retry, :extends
|
||||
:retry, :extends, :autoplay_in
|
||||
|
||||
def compose!(deps = nil)
|
||||
super do
|
||||
|
|
|
@ -5,6 +5,7 @@ module Gitlab
|
|||
class Factory < Status::Factory
|
||||
def self.extended_statuses
|
||||
[[Status::Build::Erased,
|
||||
Status::Build::ManualWithAutoPlay,
|
||||
Status::Build::Manual,
|
||||
Status::Build::Canceled,
|
||||
Status::Build::Created,
|
||||
|
|
52
lib/gitlab/ci/status/build/manual_with_auto_play.rb
Normal file
52
lib/gitlab/ci/status/build/manual_with_auto_play.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
module Status
|
||||
module Build
|
||||
class ManualWithAutoPlay < Status::Extended
|
||||
###
|
||||
# TODO: Those are random values. We have to fix accoding to the UX review
|
||||
###
|
||||
|
||||
###
|
||||
# Core override
|
||||
###
|
||||
def text
|
||||
s_('CiStatusText|scheduled')
|
||||
end
|
||||
|
||||
def label
|
||||
s_('CiStatusLabel|scheduled')
|
||||
end
|
||||
|
||||
def icon
|
||||
'timer'
|
||||
end
|
||||
|
||||
def favicon
|
||||
'favicon_status_manual_with_auto_play'
|
||||
end
|
||||
|
||||
###
|
||||
# Extension override
|
||||
###
|
||||
def illustration
|
||||
{
|
||||
image: 'illustrations/canceled-job_empty.svg',
|
||||
size: 'svg-394',
|
||||
title: _('This job is a scheduled job with manual actions!'),
|
||||
content: _('auto playyyyyyyyyyyyyy! This job depends on a user to trigger its process. Often they are used to deploy code to production environments')
|
||||
}
|
||||
end
|
||||
|
||||
def status_tooltip
|
||||
@status.status_tooltip + " (scheulded) : Execute in #{subject.build_schedule.execute_in.round} sec"
|
||||
end
|
||||
|
||||
def self.matches?(build, user)
|
||||
build.autoplay? && !build.canceled?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -49,7 +49,8 @@ module Gitlab
|
|||
script: job[:script],
|
||||
after_script: job[:after_script],
|
||||
environment: job[:environment],
|
||||
retry: job[:retry]
|
||||
retry: job[:retry],
|
||||
autoplay_in: job[:autoplay_in],
|
||||
}.compact }
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue