summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2018-10-05 16:30:33 +0000
committerKamil Trzciński <ayufan@ayufan.eu>2018-10-05 16:30:33 +0000
commit059da9bc8eb9355a760031ef8e73b0aa6285012f (patch)
treeb6057c99d0c53951a650122d624dc37405194551 /lib
parent7f86172f806558d2b614abcb06cef0ea516c5900 (diff)
parent7542a5d102bc48f5f7b8104fda22f0975b2dd931 (diff)
downloadgitlab-ce-059da9bc8eb9355a760031ef8e73b0aa6285012f.tar.gz
Merge branch 'scheduled-manual-jobs' into 'master'
Delayed jobs Closes #51352 See merge request gitlab-org/gitlab-ce!21767
Diffstat (limited to 'lib')
-rw-r--r--lib/api/jobs.rb2
-rw-r--r--lib/gitlab/ci/config/entry/job.rb15
-rw-r--r--lib/gitlab/ci/config/entry/legacy_validation_helpers.rb9
-rw-r--r--lib/gitlab/ci/config/entry/validators.rb6
-rw-r--r--lib/gitlab/ci/status/build/factory.rb2
-rw-r--r--lib/gitlab/ci/status/build/failed.rb3
-rw-r--r--lib/gitlab/ci/status/build/scheduled.rb38
-rw-r--r--lib/gitlab/ci/status/build/unschedule.rb41
-rw-r--r--lib/gitlab/ci/status/pipeline/factory.rb1
-rw-r--r--lib/gitlab/ci/status/pipeline/scheduled.rb21
-rw-r--r--lib/gitlab/ci/status/scheduled.rb23
-rw-r--r--lib/gitlab/ci/yaml_processor.rb3
12 files changed, 157 insertions, 7 deletions
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 016a896bde5..f290ff3a565 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -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 start_in artifacts cache
dependencies before_script after_script variables
environment coverage retry extends].freeze
@@ -28,13 +28,16 @@ module Gitlab
greater_than_or_equal_to: 0,
less_than_or_equal_to: 2 }
validates :when,
- inclusion: { in: %w[on_success on_failure always manual],
+ inclusion: { in: %w[on_success on_failure always manual delayed],
message: 'should be on_success, on_failure, ' \
- 'always or manual' }
+ 'always, manual or delayed' }
validates :dependencies, array_of_strings: true
validates :extends, type: String
end
+
+ validates :start_in, duration: { limit: '1 day' }, if: :delayed?
+ validates :start_in, absence: true, unless: :delayed?
end
entry :before_script, Entry::Script,
@@ -84,7 +87,7 @@ module Gitlab
:artifacts, :commands, :environment, :coverage, :retry
attributes :script, :tags, :allow_failure, :when, :dependencies,
- :retry, :extends
+ :retry, :extends, :start_in
def compose!(deps = nil)
super do
@@ -114,6 +117,10 @@ module Gitlab
self.when == 'manual'
end
+ def delayed?
+ self.when == 'delayed'
+ end
+
def ignored?
allow_failure.nil? ? manual_action? : allow_failure
end
diff --git a/lib/gitlab/ci/config/entry/legacy_validation_helpers.rb b/lib/gitlab/ci/config/entry/legacy_validation_helpers.rb
index a78a85397bd..a3d4432be82 100644
--- a/lib/gitlab/ci/config/entry/legacy_validation_helpers.rb
+++ b/lib/gitlab/ci/config/entry/legacy_validation_helpers.rb
@@ -11,6 +11,15 @@ module Gitlab
false
end
+ def validate_duration_limit(value, limit)
+ return false unless value.is_a?(String)
+
+ ChronicDuration.parse(value).second.from_now <
+ ChronicDuration.parse(limit).second.from_now
+ rescue ChronicDuration::DurationParseError
+ false
+ end
+
def validate_array_of_strings(values)
values.is_a?(Array) && values.all? { |value| validate_string(value) }
end
diff --git a/lib/gitlab/ci/config/entry/validators.rb b/lib/gitlab/ci/config/entry/validators.rb
index b3c889ee92f..f6b4ba7843e 100644
--- a/lib/gitlab/ci/config/entry/validators.rb
+++ b/lib/gitlab/ci/config/entry/validators.rb
@@ -49,6 +49,12 @@ module Gitlab
unless validate_duration(value)
record.errors.add(attribute, 'should be a duration')
end
+
+ if options[:limit]
+ unless validate_duration_limit(value, options[:limit])
+ record.errors.add(attribute, 'should not exceed the limit')
+ end
+ end
end
end
diff --git a/lib/gitlab/ci/status/build/factory.rb b/lib/gitlab/ci/status/build/factory.rb
index 2b26ebb45a1..4a74d6d6ed1 100644
--- a/lib/gitlab/ci/status/build/factory.rb
+++ b/lib/gitlab/ci/status/build/factory.rb
@@ -5,6 +5,7 @@ module Gitlab
class Factory < Status::Factory
def self.extended_statuses
[[Status::Build::Erased,
+ Status::Build::Scheduled,
Status::Build::Manual,
Status::Build::Canceled,
Status::Build::Created,
@@ -14,6 +15,7 @@ module Gitlab
Status::Build::Retryable],
[Status::Build::Failed],
[Status::Build::FailedAllowed,
+ Status::Build::Unschedule,
Status::Build::Play,
Status::Build::Stop],
[Status::Build::Action],
diff --git a/lib/gitlab/ci/status/build/failed.rb b/lib/gitlab/ci/status/build/failed.rb
index 2fa9a0d4541..50b0d044265 100644
--- a/lib/gitlab/ci/status/build/failed.rb
+++ b/lib/gitlab/ci/status/build/failed.rb
@@ -10,7 +10,8 @@ module Gitlab
stuck_or_timeout_failure: 'stuck or timeout failure',
runner_system_failure: 'runner system failure',
missing_dependency_failure: 'missing dependency failure',
- runner_unsupported: 'unsupported runner'
+ runner_unsupported: 'unsupported runner',
+ stale_schedule: 'stale schedule'
}.freeze
private_constant :REASONS
diff --git a/lib/gitlab/ci/status/build/scheduled.rb b/lib/gitlab/ci/status/build/scheduled.rb
new file mode 100644
index 00000000000..eebb3f761c5
--- /dev/null
+++ b/lib/gitlab/ci/status/build/scheduled.rb
@@ -0,0 +1,38 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ class Scheduled < Status::Extended
+ def illustration
+ {
+ image: 'illustrations/illustrations_scheduled-job_countdown.svg',
+ size: 'svg-394',
+ title: _("This is a scheduled to run in ") + " #{execute_in}",
+ content: _("This job will automatically run after it's timer finishes. " \
+ "Often they are used for incremental roll-out deploys " \
+ "to production environments. When unscheduled it converts " \
+ "into a manual action.")
+ }
+ end
+
+ def status_tooltip
+ "scheduled manual action (#{execute_in})"
+ end
+
+ def self.matches?(build, user)
+ build.scheduled? && build.scheduled_at
+ end
+
+ private
+
+ include TimeHelper
+
+ def execute_in
+ remaining_seconds = [0, subject.scheduled_at - Time.now].max
+ duration_in_numbers(remaining_seconds, true)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/build/unschedule.rb b/lib/gitlab/ci/status/build/unschedule.rb
new file mode 100644
index 00000000000..e1b7b83428c
--- /dev/null
+++ b/lib/gitlab/ci/status/build/unschedule.rb
@@ -0,0 +1,41 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ class Unschedule < Status::Extended
+ def label
+ 'unschedule action'
+ end
+
+ def has_action?
+ can?(user, :update_build, subject)
+ end
+
+ def action_icon
+ 'time-out'
+ end
+
+ def action_title
+ 'Unschedule'
+ end
+
+ def action_button_title
+ _('Unschedule job')
+ end
+
+ def action_path
+ unschedule_project_job_path(subject.project, subject)
+ end
+
+ def action_method
+ :post
+ end
+
+ def self.matches?(build, user)
+ build.scheduled?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/pipeline/factory.rb b/lib/gitlab/ci/status/pipeline/factory.rb
index 17f9a75f436..00d8f01cbdc 100644
--- a/lib/gitlab/ci/status/pipeline/factory.rb
+++ b/lib/gitlab/ci/status/pipeline/factory.rb
@@ -5,6 +5,7 @@ module Gitlab
class Factory < Status::Factory
def self.extended_statuses
[[Status::SuccessWarning,
+ Status::Pipeline::Scheduled,
Status::Pipeline::Blocked]]
end
diff --git a/lib/gitlab/ci/status/pipeline/scheduled.rb b/lib/gitlab/ci/status/pipeline/scheduled.rb
new file mode 100644
index 00000000000..9ec6994bd2f
--- /dev/null
+++ b/lib/gitlab/ci/status/pipeline/scheduled.rb
@@ -0,0 +1,21 @@
+module Gitlab
+ module Ci
+ module Status
+ module Pipeline
+ class Scheduled < Status::Extended
+ def text
+ s_('CiStatusText|scheduled')
+ end
+
+ def label
+ s_('CiStatusLabel|waiting for delayed job')
+ end
+
+ def self.matches?(pipeline, user)
+ pipeline.scheduled?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/scheduled.rb b/lib/gitlab/ci/status/scheduled.rb
new file mode 100644
index 00000000000..542100e41da
--- /dev/null
+++ b/lib/gitlab/ci/status/scheduled.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ module Ci
+ module Status
+ class Scheduled < Status::Core
+ def text
+ s_('CiStatusText|scheduled')
+ end
+
+ def label
+ s_('CiStatusLabel|scheduled')
+ end
+
+ def icon
+ 'status_scheduled'
+ end
+
+ def favicon
+ 'favicon_status_scheduled'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index 5d1864ae9e2..a427aa30683 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -49,7 +49,8 @@ module Gitlab
script: job[:script],
after_script: job[:after_script],
environment: job[:environment],
- retry: job[:retry]
+ retry: job[:retry],
+ start_in: job[:start_in]
}.compact }
end