Commit a4770fe1 authored by Luke Duncalfe's avatar Luke Duncalfe

Merge branch '328457-set-iteration-status-on-dates-update' into 'master'

Set iteration state based on updated dates

See merge request gitlab-org/gitlab!62558
parents 7a406c41 97809627
...@@ -46,7 +46,7 @@ module EE ...@@ -46,7 +46,7 @@ module EE
validate :validate_group validate :validate_group
before_validation :set_iterations_cadence, unless: -> { project_id.present? } before_validation :set_iterations_cadence, unless: -> { project_id.present? }
before_create :set_past_iteration_state before_save :set_iteration_state
before_destroy :check_if_can_be_destroyed before_destroy :check_if_can_be_destroyed
scope :upcoming, -> { with_state(:upcoming) } scope :upcoming, -> { with_state(:upcoming) }
...@@ -197,10 +197,20 @@ module EE ...@@ -197,10 +197,20 @@ module EE
errors.add(:project_id, s_("is not allowed. We do not currently support project-level iterations")) errors.add(:project_id, s_("is not allowed. We do not currently support project-level iterations"))
end end
def set_past_iteration_state def set_iteration_state
# if we create an iteration in the past, we set the state to closed right away, self.state = compute_state
# no need to wait for IterationsUpdateStatusWorker to do so. end
self.state = :closed if due_date < Date.current
def compute_state
today = Date.today
if start_date > today
:upcoming
elsif due_date < today
:closed
else
:started
end
end end
# TODO: this method should be removed as part of https://gitlab.com/gitlab-org/gitlab/-/issues/296099 # TODO: this method should be removed as part of https://gitlab.com/gitlab-org/gitlab/-/issues/296099
......
...@@ -8,7 +8,7 @@ RSpec.describe 'User views iteration cadences', :js do ...@@ -8,7 +8,7 @@ RSpec.describe 'User views iteration cadences', :js do
let_it_be(:cadence) { create(:iterations_cadence, group: group) } let_it_be(:cadence) { create(:iterations_cadence, group: group) }
let_it_be(:other_cadence) { create(:iterations_cadence, group: group) } let_it_be(:other_cadence) { create(:iterations_cadence, group: group) }
let_it_be(:iteration_in_cadence) { create(:iteration, group: group, iterations_cadence: cadence) } let_it_be(:iteration_in_cadence) { create(:iteration, group: group, iterations_cadence: cadence) }
let_it_be(:closed_iteration_in_cadence) { create(:closed_iteration, group: group, iterations_cadence: cadence) } let_it_be(:closed_iteration_in_cadence) { create(:iteration, group: group, iterations_cadence: cadence, start_date: 2.weeks.ago, due_date: 1.week.ago) }
let_it_be(:iteration_in_other_cadence) { create(:iteration, group: group, iterations_cadence: other_cadence) } let_it_be(:iteration_in_other_cadence) { create(:iteration, group: group, iterations_cadence: other_cadence) }
before do before do
......
...@@ -13,8 +13,8 @@ RSpec.describe IterationsFinder do ...@@ -13,8 +13,8 @@ RSpec.describe IterationsFinder do
let_it_be(:closed_iteration) { create(:closed_iteration, :skip_future_date_validation, iterations_cadence: iteration_cadence2, group: iteration_cadence2.group, start_date: 7.days.ago, due_date: 2.days.ago) } let_it_be(:closed_iteration) { create(:closed_iteration, :skip_future_date_validation, iterations_cadence: iteration_cadence2, group: iteration_cadence2.group, start_date: 7.days.ago, due_date: 2.days.ago) }
let_it_be(:started_group_iteration) { create(:started_iteration, :skip_future_date_validation, iterations_cadence: iteration_cadence2, group: iteration_cadence2.group, title: 'one test', start_date: 1.day.ago, due_date: Date.today) } let_it_be(:started_group_iteration) { create(:started_iteration, :skip_future_date_validation, iterations_cadence: iteration_cadence2, group: iteration_cadence2.group, title: 'one test', start_date: 1.day.ago, due_date: Date.today) }
let_it_be(:upcoming_group_iteration) { create(:iteration, iterations_cadence: iteration_cadence1, group: iteration_cadence1.group, start_date: 1.day.from_now, due_date: 3.days.from_now) } let_it_be(:upcoming_group_iteration) { create(:iteration, iterations_cadence: iteration_cadence1, group: iteration_cadence1.group, start_date: 1.day.from_now, due_date: 3.days.from_now) }
let_it_be(:root_group_iteration) { create(:started_iteration, iterations_cadence: iteration_cadence3, group: iteration_cadence3.group, start_date: 1.day.from_now, due_date: 2.days.from_now) } let_it_be(:root_group_iteration) { create(:started_iteration, iterations_cadence: iteration_cadence3, group: iteration_cadence3.group, start_date: 1.day.ago, due_date: 2.days.from_now) }
let_it_be(:root_closed_iteration) { create(:closed_iteration, iterations_cadence: iteration_cadence3, group: iteration_cadence3.group, start_date: 1.week.ago, due_date: 1.day.ago) } let_it_be(:root_closed_iteration) { create(:closed_iteration, iterations_cadence: iteration_cadence3, group: iteration_cadence3.group, start_date: 1.week.ago, due_date: 2.days.ago) }
let(:parent) { project_1 } let(:parent) { project_1 }
let(:params) { { parent: parent, include_ancestors: true } } let(:params) { { parent: parent, include_ancestors: true } }
...@@ -132,7 +132,7 @@ RSpec.describe IterationsFinder do ...@@ -132,7 +132,7 @@ RSpec.describe IterationsFinder do
it 'returns iterations with start_date and due_date between timeframe' do it 'returns iterations with start_date and due_date between timeframe' do
params.merge!(start_date: 1.day.ago, end_date: 3.days.from_now) params.merge!(start_date: 1.day.ago, end_date: 3.days.from_now)
expect(subject).to match_array([started_group_iteration, upcoming_group_iteration, root_group_iteration, root_closed_iteration]) expect(subject).to match_array([started_group_iteration, upcoming_group_iteration, root_group_iteration])
end end
it 'returns iterations which start before the timeframe' do it 'returns iterations which start before the timeframe' do
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Iteration do RSpec.describe Iteration do
include ActiveSupport::Testing::TimeHelpers
let(:set_cadence) { nil } let(:set_cadence) { nil }
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
...@@ -452,6 +454,98 @@ RSpec.describe Iteration do ...@@ -452,6 +454,98 @@ RSpec.describe Iteration do
end end
end end
context 'sets correct state based on iteration dates' do
around do |example|
travel_to(Time.utc(2019, 12, 30)) { example.run }
end
let_it_be(:iterations_cadence) { create(:iterations_cadence, group: group, start_date: 10.days.ago.utc.to_date) }
let(:iteration) { build(:iteration, group: iterations_cadence.group, iterations_cadence: iterations_cadence, start_date: start_date, due_date: 2.weeks.after(start_date).to_date) }
context 'start_date is in the future' do
let(:start_date) { 1.day.from_now.utc.to_date }
it 'sets state to started' do
iteration.save!
expect(iteration.state).to eq('upcoming')
end
end
context 'start_date is today' do
let(:start_date) { Time.now.utc.to_date }
it 'sets state to started' do
iteration.save!
expect(iteration.state).to eq('started')
end
end
context 'start_date is in the past and due date is still in the future' do
let(:start_date) { 1.week.ago.utc.to_date }
it 'sets state to started' do
iteration.save!
expect(iteration.state).to eq('started')
end
end
context 'start_date is in the past and due date is also in the past' do
let(:start_date) { 3.weeks.ago.utc.to_date }
it 'sets state to started' do
iteration.save!
expect(iteration.state).to eq('closed')
end
end
context 'when dates for an existing iteration change' do
context 'when iteration dates go from future to past' do
let(:iteration) { create(:iteration, group: iterations_cadence.group, iterations_cadence: iterations_cadence, start_date: 2.weeks.from_now.utc.to_date, due_date: 3.weeks.from_now.utc.to_date)}
it 'sets state to closed' do
expect(iteration.state).to eq('upcoming')
iteration.start_date -= 4.weeks
iteration.due_date -= 4.weeks
iteration.save!
expect(iteration.state).to eq('closed')
end
end
context 'when iteration dates go from past to future' do
let(:iteration) { create(:iteration, group: iterations_cadence.group, iterations_cadence: iterations_cadence, start_date: 2.weeks.ago.utc.to_date, due_date: 1.week.ago.utc.to_date)}
it 'sets state to upcoming' do
expect(iteration.state).to eq('closed')
iteration.start_date += 3.weeks
iteration.due_date += 3.weeks
iteration.save!
expect(iteration.state).to eq('upcoming')
end
context 'and today is between iteration start and due dates' do
it 'sets state to started' do
expect(iteration.state).to eq('closed')
iteration.start_date += 2.weeks
iteration.due_date += 2.weeks
iteration.save!
expect(iteration.state).to eq('started')
end
end
end
end
end
it_behaves_like 'a timebox', :iteration do it_behaves_like 'a timebox', :iteration do
let(:timebox_args) { [:skip_project_validation] } let(:timebox_args) { [:skip_project_validation] }
let(:timebox_table_name) { described_class.table_name.to_sym } let(:timebox_table_name) { described_class.table_name.to_sym }
......
...@@ -8,7 +8,7 @@ RSpec.describe API::Iterations do ...@@ -8,7 +8,7 @@ RSpec.describe API::Iterations do
let_it_be(:group) { create(:group, :private, parent: parent_group) } let_it_be(:group) { create(:group, :private, parent: parent_group) }
let_it_be(:iteration) { create(:iteration, group: group, title: 'search_title') } let_it_be(:iteration) { create(:iteration, group: group, title: 'search_title') }
let_it_be(:closed_iteration) { create(:iteration, :closed, group: group) } let_it_be(:closed_iteration) { create(:iteration, :closed, group: group, start_date: 2.weeks.ago, due_date: 1.week.ago) }
let_it_be(:ancestor_iteration) { create(:iteration, group: parent_group) } let_it_be(:ancestor_iteration) { create(:iteration, group: parent_group) }
before_all do before_all do
......
...@@ -15,7 +15,7 @@ RSpec.describe IterationsUpdateStatusWorker do ...@@ -15,7 +15,7 @@ RSpec.describe IterationsUpdateStatusWorker do
it 'updates the status of iterations that require it', :aggregate_failures do it 'updates the status of iterations that require it', :aggregate_failures do
expect(closed_iteration1.state).to eq('closed') expect(closed_iteration1.state).to eq('closed')
expect(closed_iteration2.state).to eq('closed') expect(closed_iteration2.state).to eq('closed')
expect(started_iteration.state).to eq('upcoming') expect(started_iteration.state).to eq('started')
expect(upcoming_iteration.state).to eq('upcoming') expect(upcoming_iteration.state).to eq('upcoming')
closed_iteration2.update!(state: 'upcoming') closed_iteration2.update!(state: 'upcoming')
......
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