Commit 407b0aa2 authored by Sean Carroll's avatar Sean Carroll Committed by Lin Jen-Shin
parent 23346d01
......@@ -533,6 +533,7 @@ module Ci
.concat(job_variables)
.concat(environment_changed_page_variables)
.concat(persisted_environment_variables)
.concat(deploy_freeze_variables)
.to_runner_variables
end
end
......@@ -588,6 +589,18 @@ module Ci
end
end
def deploy_freeze_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless freeze_period?
variables.append(key: 'CI_DEPLOY_FREEZE', value: 'true')
end
end
def freeze_period?
Ci::FreezePeriodStatus.new(project: project).execute
end
def features
{ trace_sections: true }
end
......
# frozen_string_literal: true
module Ci
class FreezePeriodStatus
attr_reader :project
def initialize(project:)
@project = project
end
def execute
project.freeze_periods.any? { |period| within_freeze_period?(period) }
end
def within_freeze_period?(period)
# previous_freeze_end, ..., previous_freeze_start, ..., NOW, ..., next_freeze_end, ..., next_freeze_start
# Current time is within a freeze period if
# it falls between a previous freeze start and next freeze end
start_freeze = Gitlab::Ci::CronParser.new(period.freeze_start, period.cron_timezone)
end_freeze = Gitlab::Ci::CronParser.new(period.freeze_end, period.cron_timezone)
previous_freeze_start = previous_time(start_freeze)
previous_freeze_end = previous_time(end_freeze)
next_freeze_start = next_time(start_freeze)
next_freeze_end = next_time(end_freeze)
previous_freeze_end < previous_freeze_start &&
previous_freeze_start <= time_zone_now &&
time_zone_now <= next_freeze_end &&
next_freeze_end < next_freeze_start
end
private
def previous_time(cron_parser)
cron_parser.previous_time_from(time_zone_now)
end
def next_time(cron_parser)
cron_parser.next_time_from(time_zone_now)
end
def time_zone_now
@time_zone_now ||= Time.zone.now
end
end
end
---
title: Add freeze periods via CI_DEPLOY_FREEZE variable
merge_request: 29244
author:
type: added
......@@ -12,8 +12,11 @@ module Gitlab
end
def next_time_from(time)
@cron_line ||= try_parse_cron(@cron, @cron_timezone)
@cron_line.next_time(time).utc.in_time_zone(Time.zone) if @cron_line.present?
cron_line.next_time(time).utc.in_time_zone(Time.zone) if cron_line.present?
end
def previous_time_from(time)
cron_line.previous_time(time).utc.in_time_zone(Time.zone) if cron_line.present?
end
def cron_valid?
......@@ -49,6 +52,10 @@ module Gitlab
def try_parse_cron(cron, cron_timezone)
Fugit::Cron.parse("#{cron} #{cron_timezone}")
end
def cron_line
@cron_line ||= try_parse_cron(@cron, @cron_timezone)
end
end
end
end
This diff is collapsed.
......@@ -2884,6 +2884,19 @@ describe Ci::Build do
it { is_expected.to include(deployment_variable) }
end
context 'when build has a freeze period' do
let(:freeze_variable) { { key: 'CI_DEPLOY_FREEZE', value: 'true', masked: false, public: true } }
before do
expect_next_instance_of(Ci::FreezePeriodStatus) do |freeze_period|
expect(freeze_period).to receive(:execute)
.and_return(true)
end
end
it { is_expected.to include(freeze_variable) }
end
context 'when project has default CI config path' do
let(:ci_config_path) { { key: 'CI_CONFIG_PATH', value: '.gitlab-ci.yml', public: true, masked: false } }
......
......@@ -24,7 +24,7 @@ RSpec.describe Ci::FreezePeriod, type: :model do
expect(freeze_period).not_to be_valid
end
it 'does not allow non-cron strings' do
it 'does not allow an invalid timezone' do
freeze_period = build(:ci_freeze_period, cron_timezone: 'invalid')
expect(freeze_period).not_to be_valid
......
# frozen_string_literal: true
require 'spec_helper'
describe Ci::FreezePeriodStatus do
let(:project) { create :project }
# '0 23 * * 5' == "At 23:00 on Friday."", '0 7 * * 1' == "At 07:00 on Monday.""
let(:friday_2300) { '0 23 * * 5' }
let(:monday_0700) { '0 7 * * 1' }
subject { described_class.new(project: project).execute }
shared_examples 'within freeze period' do |time|
it 'is frozen' do
Timecop.freeze(time) do
expect(subject).to be_truthy
end
end
end
shared_examples 'outside freeze period' do |time|
it 'is not frozen' do
Timecop.freeze(time) do
expect(subject).to be_falsy
end
end
end
describe 'single freeze period' do
let!(:freeze_period) { create(:ci_freeze_period, project: project, freeze_start: friday_2300, freeze_end: monday_0700) }
it_behaves_like 'outside freeze period', Time.utc(2020, 4, 10, 22, 59)
it_behaves_like 'within freeze period', Time.utc(2020, 4, 10, 23, 01)
it_behaves_like 'within freeze period', Time.utc(2020, 4, 13, 6, 59)
it_behaves_like 'outside freeze period', Time.utc(2020, 4, 13, 7, 1)
end
describe 'multiple freeze periods' do
# '30 23 * * 5' == "At 23:30 on Friday."", '0 8 * * 1' == "At 08:00 on Monday.""
let(:friday_2330) { '30 23 * * 5' }
let(:monday_0800) { '0 8 * * 1' }
let!(:freeze_period_1) { create(:ci_freeze_period, project: project, freeze_start: friday_2300, freeze_end: monday_0700) }
let!(:freeze_period_2) { create(:ci_freeze_period, project: project, freeze_start: friday_2330, freeze_end: monday_0800) }
it_behaves_like 'outside freeze period', Time.utc(2020, 4, 10, 22, 59)
it_behaves_like 'within freeze period', Time.utc(2020, 4, 10, 23, 29)
it_behaves_like 'within freeze period', Time.utc(2020, 4, 11, 10, 0)
it_behaves_like 'within freeze period', Time.utc(2020, 4, 10, 23, 1)
it_behaves_like 'within freeze period', Time.utc(2020, 4, 13, 6, 59)
it_behaves_like 'within freeze period', Time.utc(2020, 4, 13, 7, 59)
it_behaves_like 'outside freeze period', Time.utc(2020, 4, 13, 8, 1)
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