Commit 39f7c9e3 authored by Shinya Maeda's avatar Shinya Maeda Committed by Alessio Caiazza
Browse files

Update pipelines and stages status as well

parent 7b4268db2120
......@@ -7,6 +7,7 @@
#
# See 'detailed_status?` method and `Gitlab::Ci::Status` module.
#
# TODO: DO I need to update this deprecated module?
module CiStatusHelper
def ci_label_for_status(status)
if detailed_status?(status)
......
......@@ -169,11 +169,11 @@ def retry(build, current_user)
end
before_transition created: :scheduled do |build|
build_build_schedule(execute_at: execute_at)
build.build_build_schedule(execute_at: build.execute_at)
end
before_transition scheduled: any do |build|
build_schedule.delete!
build.build_schedule.delete
end
after_transition any => [:pending] do |build|
......
......@@ -108,6 +108,10 @@ class Pipeline < ActiveRecord::Base
transition any - [:manual] => :manual
end
event :schedule do
transition any - [:scheduled] => :scheduled
end
# IMPORTANT
# Do not add any operations to this state_machine
# Create a separate worker for each new operation
......@@ -544,6 +548,7 @@ def update_status
when 'canceled' then cancel
when 'skipped' then skip
when 'manual' then block
when 'scheduled' then schedule
else
raise HasStatus::UnknownStatusError,
"Unknown status `#{latest_builds_status}`"
......
......@@ -65,6 +65,10 @@ class Stage < ActiveRecord::Base
event :block do
transition any - [:manual] => :manual
end
event :schedule do
transition any - [:scheduled] => :scheduled
end
end
def update_status
......@@ -77,6 +81,7 @@ def update_status
when 'failed' then drop
when 'canceled' then cancel
when 'manual' then block
when 'scheduled' then schedule
when 'skipped', nil then skip
else
raise HasStatus::UnknownStatusError,
......
......@@ -77,6 +77,7 @@ def all_state_names
state :canceled, value: 'canceled'
state :skipped, value: 'skipped'
state :manual, value: 'manual'
state :scheduled, value: 'scheduled'
end
scope :created, -> { where(status: 'created') }
......@@ -88,6 +89,7 @@ def all_state_names
scope :canceled, -> { where(status: 'canceled') }
scope :skipped, -> { where(status: 'skipped') }
scope :manual, -> { where(status: 'manual') }
scope :scheduled, -> { where(status: 'scheduled') }
scope :alive, -> { where(status: [:created, :pending, :running]) }
scope :created_or_pending, -> { where(status: [:created, :pending]) }
scope :running_or_pending, -> { where(status: [:running, :pending]) }
......
......@@ -3,31 +3,9 @@ module Ci
module Status
module Build
class Scheduled < Status::Extended
###
# Core override
###
def text
s_('CiStatusText|scheduled')
end
def label
s_('CiStatusLabel|scheduled')
end
def icon
'timer'
end
def favicon
'favicon_status_scheduled'
end
###
# Extension override
###
def illustration
{
image: 'illustrations/canceled-job_empty.svg',
image: '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.")
......
module Gitlab
module Ci
module Status
class Scheduled < Status::Core
def text
s_('CiStatusText|scheduled')
end
def label
s_('CiStatusLabel|scheduled')
end
def icon
'timer' # TODO: 'status_scheduled'
end
def favicon
'favicon_status_scheduled'
end
end
end
end
end
......@@ -62,31 +62,87 @@
# require '/path/to/scheduled_job_fixture.rb' # Load this script
# ```
#
# ### Reproduce the scenario A) ~ Succeccfull timed incremantal rollout ~
#
# ````
# project = Project.find_by(path: 'incremental-rollout')
# user = User.find_by(username: 'root')
# fixture = ScheduledJobFixture.new(project.id, user.id)
#
# fixture.create_pipeline('master')
# fixture.finish_stage_until('test') # Succeed 'build' and 'test' jobs. 'rollout 10%' job will be scheduled. See the pipeline page
# fixture.finish_stage_until('rollout 10%') # Succeed `rollout 10%` job. 'rollout 50%' job will be scheduled.
# fixture.finish_stage_until('rollout 50%') # Succeed `rollout 50%` job. 'rollout 100%' job will be scheduled.
# fixture.finish_stage_until('rollout 100%') # Succeed `rollout 100%` job. 'cleanup' job will be scheduled.
# fixture.finish_stage_until('cleanup') # Succeed `cleanup` job. The pipeline becomes green.
# ```
# ### Reproduce the scenario ~ when all stages succeeded ~
#
# 1. ScheduledJobFixture.new(29, 1).create_pipeline('master')
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('test')
# 1. Wait until rollout 10% job is triggered
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('rollout 10%')
# 1. Wait until rollout 50% job is triggered
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('rollout 50%')
# 1. Wait until rollout 100% job is triggered
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('rollout 100%')
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('cleanup')
#
# Expectation: Users see a succeccful pipeline
#
# ### Reproduce the scenario ~ when rollout 10% jobs failed ~
#
# 1. ScheduledJobFixture.new(29, 1).create_pipeline('master')
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('test')
# 1. Wait until rollout 10% job is triggered
# 1. ScheduledJobFixture.new(29, 1).drop_jobs('rollout 10%')
#
# Expectation: Following stages should be skipped.
#
# ### Reproduce the scenario ~ when user clicked cancel button before build job finished ~
#
# 1. ScheduledJobFixture.new(29, 1).create_pipeline('master')
# 1. ScheduledJobFixture.new(29, 1).cancel_pipeline
#
# Expectation: All stages should be canceled.
#
# ### Reproduce the scenario ~ when user canceled the pipeline after rollout 10% job is scheduled ~
#
# 1. ScheduledJobFixture.new(29, 1).create_pipeline('master')
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('test')
# 1. Run next command before rollout 10% job is triggered
# 1. ScheduledJobFixture.new(29, 1).cancel_pipeline
#
# Expectation: rollout 10% job will be canceled. Following stages will be skipped.
#
# ### Reproduce the scenario ~ when user canceled rollout 10% job after rollout 10% job is scheduled ~
#
# 1. ScheduledJobFixture.new(29, 1).create_pipeline('master')
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('test')
# 1. Run next command before rollout 10% job is triggered
# 1. ScheduledJobFixture.new(29, 1).cancel_jobs('rollout 10%')
#
# Expectation: rollout 10% job will be canceled. Following stages will be skipped.
#
# ### Reproduce the scenario ~ when user played rollout 10% job immidiately ~
#
# 1. ScheduledJobFixture.new(29, 1).create_pipeline('master')
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('test')
# 1. Play rollout 10% job before rollout 10% job is triggered
#
# Expectation: rollout 10% becomes pending immidiately
#
# ### Reproduce the scenario ~ when rollout 10% job is allowed to fail ~
#
# 1. Set `allow_failure: true` to rollout 10% job
# 1. ScheduledJobFixture.new(29, 1).create_pipeline('master')
# 1. ScheduledJobFixture.new(29, 1).finish_stage_until('test')
# 1. Wait until rollout 10% job is triggered
# 1. ScheduledJobFixture.new(29, 1).drop_jobs('rollout 10%')
#
# Expectation: rollout 50% job should be triggered
#
class ScheduledJobFixture
attr_reader :project
attr_reader :user
include GitlabRoutingHelper
def initialize(project_id, user_id)
@project = Project.find_by_id(project_id)
@user = User.find_by_id(user_id)
end
def create_pipeline(ref)
Ci::CreatePipelineService.new(project, user, ref: ref).execute(:web)
pipeline = Ci::CreatePipelineService.new(project, user, ref: ref).execute(:web)
Rails.application.routes.url_helpers.namespace_project_pipeline_url(project.namespace, project, pipeline)
end
def finish_stage_until(stage_name)
......@@ -99,4 +155,32 @@ def finish_stage_until(stage_name)
return if stage.name == stage_name
end
end
def run_jobs(stage_name)
pipeline = Ci::Pipeline.last
stage = pipeline.stages.find_by_name(stage_name)
stage.builds.map(&:run)
stage.update_status
pipeline.update_status
end
def drop_jobs(stage_name)
pipeline = Ci::Pipeline.last
stage = pipeline.stages.find_by_name(stage_name)
stage.builds.map(&:drop)
stage.update_status
pipeline.update_status
end
def cancel_jobs(stage_name)
pipeline = Ci::Pipeline.last
stage = pipeline.stages.find_by_name(stage_name)
stage.builds.map(&:cancel)
stage.update_status
pipeline.update_status
end
def cancel_pipeline
Ci::Pipeline.last.cancel_running
end
end
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