Skip to content
Snippets Groups Projects
Commit 37d6d1e4 authored by Shinya Maeda's avatar Shinya Maeda
Browse files

basic components

parent 5f715f1d
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -9,15 +9,13 @@ module Ci
 
def schedule_next_run!
next_time = Ci::CronParser.new(cron, cron_time_zone).next_time_from_now
update(:next_run_at => next_time) if next_time.present?
end
def valid_ref?
true #TODO:
if next_time.present?
update_attributes(next_run_at: next_time)
end
end
 
def update_last_run!
update(:last_run_at => Time.now)
update_attributes(last_run_at: Time.now)
end
end
end
Loading
Loading
@@ -2,14 +2,14 @@ module Ci
class CreatePipelineService < BaseService
attr_reader :pipeline
 
def execute(ignore_skip_ci: false, save_on_errors: true, trigger_request: nil)
def execute(ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, scheduled_trigger: false)
@pipeline = Ci::Pipeline.new(
project: project,
ref: ref,
sha: sha,
before_sha: before_sha,
tag: tag?,
trigger_requests: Array(trigger_request),
trigger_requests: (scheduled_trigger) ? [] : Array(trigger_request),
user: current_user
)
 
Loading
Loading
@@ -17,8 +17,10 @@ module Ci
return error('Pipeline is disabled')
end
 
unless trigger_request || can?(current_user, :create_pipeline, project)
return error('Insufficient permissions to create a new pipeline')
unless scheduled_trigger
unless trigger_request || can?(current_user, :create_pipeline, project)
return error('Insufficient permissions to create a new pipeline')
end
end
 
unless branch? || tag?
Loading
Loading
Loading
Loading
@@ -3,15 +3,15 @@ class ScheduledTriggerWorker
include CronjobQueue
 
def perform
# TODO: Update next_run_at
Ci::ScheduledTriggers.where("next_run_at < ?", Time.now).find_each do |trigger|
Ci::ScheduledTrigger.where("next_run_at < ?", Time.now).find_each do |trigger|
begin
Ci::CreateTriggerRequestService.new.execute(trigger.project, trigger, trigger.ref)
Ci::CreatePipelineService.new(trigger.project, trigger.owner, ref: trigger.ref).
execute(ignore_skip_ci: true, scheduled_trigger: true)
rescue => e
Rails.logger.error "#{trigger.id}: Failed to trigger job: #{e.message}"
ensure
trigger.schedule_next_run!
trigger.update_last_run!
end
end
end
Loading
Loading
FactoryGirl.define do
factory :ci_scheduled_trigger, class: Ci::ScheduledTrigger do
project factory: :empty_project
project factory: :project
owner factory: :user
ref 'master'
 
trait :force_triggable do
next_run_at Time.now - 1.month
end
trait :cron_nightly_build do
cron '0 1 * * *'
cron_time_zone 'Europe/Istanbul'
next_run_at do # TODO: Use CronParser
time = Time.now.in_time_zone(cron_time_zone)
time = time + 1.day if time.hour > 1
time = time.change(sec: 0, min: 0, hour: 1)
time
end
end
 
trait :cron_weekly_build do
cron '0 1 * * 5'
cron_time_zone 'Europe/Istanbul'
# TODO: next_run_at
end
 
trait :cron_monthly_build do
cron '0 1 22 * *'
cron_time_zone 'Europe/Istanbul'
# TODO: next_run_at
end
 
trait :cron_every_5_minutes do
cron '*/5 * * * *'
cron_time_zone 'Europe/Istanbul'
# TODO: next_run_at
end
 
trait :cron_every_5_hours do
cron '* */5 * * *'
cron_time_zone 'Europe/Istanbul'
# TODO: next_run_at
end
 
trait :cron_every_5_days do
cron '* * */5 * *'
cron_time_zone 'Europe/Istanbul'
# TODO: next_run_at
end
 
trait :cron_every_5_months do
cron '* * * */5 *'
cron_time_zone 'Europe/Istanbul'
# TODO: next_run_at
end
end
end
Loading
Loading
@@ -6,91 +6,62 @@ module Ci
subject { described_class.new(cron, cron_time_zone).next_time_from_now }
 
context 'when cron and cron_time_zone are valid' do
context 'at 00:00, 00:10, 00:20, 00:30, 00:40, 00:50' do
let(:cron) { '*/10 * * * *' }
let(:cron_time_zone) { 'US/Pacific' }
context 'when specific time' do
let(:cron) { '3 4 5 6 *' }
let(:cron_time_zone) { 'Europe/London' }
 
it 'returns next time from now' do
time = Time.now.in_time_zone(cron_time_zone)
time = time + 10.minutes
time = time.change(sec: 0, min: time.min-time.min%10)
is_expected.to eq(time)
it 'returns exact time in the future' do
expect(subject).to be > Time.now.in_time_zone(cron_time_zone)
expect(subject.min).to eq(3)
expect(subject.hour).to eq(4)
expect(subject.day).to eq(5)
expect(subject.month).to eq(6)
end
end
 
context 'at 10:00, 20:00' do
let(:cron) { '0 */10 * * *' }
let(:cron_time_zone) { 'US/Pacific' }
context 'when specific day of week' do
let(:cron) { '* * * * 0' }
let(:cron_time_zone) { 'Europe/London' }
 
it 'returns next time from now' do
time = Time.now.in_time_zone(cron_time_zone)
time = time + 10.hours
time = time.change(sec: 0, min: 0, hour: time.hour-time.hour%10)
is_expected.to eq(time)
it 'returns exact day of week in the future' do
expect(subject).to be > Time.now.in_time_zone(cron_time_zone)
expect(subject.wday).to eq(0)
end
end
 
context 'when cron is every 10 days' do
let(:cron) { '0 0 */10 * *' }
context 'when slash used' do
let(:cron) { '*/10 */6 */10 */10 *' }
let(:cron_time_zone) { 'US/Pacific' }
 
it 'returns next time from now' do
time = Time.now.in_time_zone(cron_time_zone)
time = time + 10.days
time = time.change(sec: 0, min: 0, hour: 0, day: time.day-time.day%10)
is_expected.to eq(time)
it 'returns exact minute' do
expect(subject).to be > Time.now.in_time_zone(cron_time_zone)
expect(subject.min).to be_in([0, 10, 20, 30, 40, 50])
expect(subject.hour).to be_in([0, 6, 12, 18])
expect(subject.day).to be_in([1, 11, 21, 31])
expect(subject.month).to be_in([1, 11])
end
end
 
context 'when cron is every week 2:00 AM' do
let(:cron) { '0 2 * * *' }
context 'when range used' do
let(:cron) { '0,20,40 * 1-5 * *' }
let(:cron_time_zone) { 'US/Pacific' }
 
it 'returns next time from now' do
time = Time.now.in_time_zone(cron_time_zone)
is_expected.to eq(time.change(sec: 0, min: 0, hour: 2, day: time.day+1))
expect(subject).to be > Time.now.in_time_zone(cron_time_zone)
expect(subject.min).to be_in([0, 20, 40])
expect(subject.day).to be_in((1..5).to_a)
end
end
 
context 'when cron_time_zone is US/Pacific' do
let(:cron) { '0 1 * * *' }
let(:cron) { '* * * * *' }
let(:cron_time_zone) { 'US/Pacific' }
 
it 'returns next time from now' do
time = Time.now.in_time_zone(cron_time_zone)
is_expected.to eq(time.change(sec: 0, min: 0, hour: 1, day: time.day+1))
end
end
context 'when cron_time_zone is Europe/London' do
let(:cron) { '0 1 * * *' }
let(:cron_time_zone) { 'Europe/London' }
it 'returns next time from now' do
time = Time.now.in_time_zone(cron_time_zone)
is_expected.to eq(time.change(sec: 0, min: 0, hour: 1, day: time.day+1))
expect(subject).to be > Time.now.in_time_zone(cron_time_zone)
expect(subject.utc_offset/60/60).to eq(-7)
end
end
context 'when cron_time_zone is Asia/Tokyo' do
let(:cron) { '0 1 * * *' }
let(:cron_time_zone) { 'Asia/Tokyo' }
it 'returns next time from now' do
time = Time.now.in_time_zone(cron_time_zone)
is_expected.to eq(time.change(sec: 0, min: 0, hour: 1, day: time.day+1))
end
end
end
context 'when cron is given and cron_time_zone is not given' do
let(:cron) { '0 1 * * *' }
it 'returns next time from now in utc' do
obj = described_class.new(cron).next_time_from_now
time = Time.now.in_time_zone('UTC')
expect(obj).to eq(time.change(sec: 0, min: 0, hour: 1, day: time.day+1))
end
end
 
context 'when cron and cron_time_zone are invalid' do
Loading
Loading
require 'spec_helper'
require 'rufus-scheduler' # Included in sidekiq-cron
 
describe Ci::ScheduledTrigger, models: true do
 
Loading
Loading
@@ -9,30 +8,22 @@ describe Ci::ScheduledTrigger, models: true do
end
 
describe '#schedule_next_run!' do
context 'when cron and cron_time_zone are vaild' do
context 'when nightly build' do
it 'schedules next run' do
scheduled_trigger = create(:ci_scheduled_trigger, :cron_nightly_build)
scheduled_trigger.schedule_next_run!
puts "scheduled_trigger: #{scheduled_trigger.inspect}"
subject { scheduled_trigger.schedule_next_run! }
 
expect(scheduled_trigger.cron).to be_nil
end
end
let(:scheduled_trigger) { create(:ci_scheduled_trigger, :cron_nightly_build, next_run_at: nil) }
 
context 'when weekly build' do
end
context 'when monthly build' do
end
it 'updates next_run_at' do
is_expected.not_to be_nil
end
end
describe '#update_last_run!' do
subject { scheduled_trigger.update_last_run! }
 
context 'when cron and cron_time_zone are invaild' do
it 'schedules nothing' do
let(:scheduled_trigger) { create(:ci_scheduled_trigger, :cron_nightly_build, last_run_at: nil) }
 
end
it 'updates last_run_at' do
is_expected.not_to be_nil
end
end
end
Loading
Loading
@@ -214,5 +214,9 @@ describe Ci::CreatePipelineService, services: true do
expect(Environment.find_by(name: "review/master")).not_to be_nil
end
end
context 'when scheduled_trigger' do
# TODO: spec if approved
end
end
end
require 'spec_helper'
 
describe ScheduledTriggerWorker do
subject { described_class.new.perform }
let(:worker) { described_class.new }
 
context '#perform' do # TODO:
it 'does' do
is_expected.to be_nil
before do
stub_ci_pipeline_to_return_yaml_file
end
context 'when there is a scheduled trigger within next_run_at' do
before do
create(:ci_scheduled_trigger, :cron_nightly_build, :force_triggable)
worker.perform
end
it 'creates a new pipeline' do
expect(Ci::Pipeline.last.status).to eq('pending')
end
it 'schedules next_run_at' do
scheduled_trigger2 = create(:ci_scheduled_trigger, :cron_nightly_build)
expect(Ci::ScheduledTrigger.last.next_run_at).to eq(scheduled_trigger2.next_run_at)
end
end
context 'when there are no scheduled triggers within next_run_at' do
let!(:scheduled_trigger) { create(:ci_scheduled_trigger, :cron_nightly_build) }
before do
worker.perform
end
it 'do not create a new pipeline' do
expect(Ci::Pipeline.all).to be_empty
end
it 'do not reschedule next_run_at' do
expect(Ci::ScheduledTrigger.last.next_run_at).to eq(scheduled_trigger.next_run_at)
end
end
context 'when next_run_at is nil' do
let!(:scheduled_trigger) { create(:ci_scheduled_trigger, :cron_nightly_build, next_run_at: nil) }
before do
worker.perform
end
it 'do not create a new pipeline' do
expect(Ci::Pipeline.all).to be_empty
end
it 'do not reschedule next_run_at' do
expect(Ci::ScheduledTrigger.last.next_run_at).to eq(scheduled_trigger.next_run_at)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment