Commit e9ef0209 authored by Fatih Acet's avatar Fatih Acet

Add project milestone link to dashboard milestones

One of the steps to deprecate dashboard milestones.
Links do dashboard milestone are replaced with links for each
project milestone
parent f7ac8041
...@@ -45,9 +45,4 @@ ...@@ -45,9 +45,4 @@
&.status-box-upcoming { &.status-box-upcoming {
background: $gl-text-color-secondary; background: $gl-text-color-secondary;
} }
&.status-box-milestone {
color: $gl-text-color;
background: $gray-darker;
}
} }
$status-box-line-height: 26px;
.issues-sortable-list .str-truncated { .issues-sortable-list .str-truncated {
max-width: 90%; max-width: 90%;
} }
...@@ -38,6 +40,7 @@ ...@@ -38,6 +40,7 @@
font-size: $tooltip-font-size; font-size: $tooltip-font-size;
margin-top: 0; margin-top: 0;
margin-right: $gl-padding-4; margin-right: $gl-padding-4;
line-height: $status-box-line-height;
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
line-height: unset; line-height: unset;
......
...@@ -43,14 +43,7 @@ class Groups::MilestonesController < Groups::ApplicationController ...@@ -43,14 +43,7 @@ class Groups::MilestonesController < Groups::ApplicationController
def update def update
# Keep this compatible with legacy group milestones where we have to update # Keep this compatible with legacy group milestones where we have to update
# all projects milestones states at once. # all projects milestones states at once.
if @milestone.legacy_group_milestone? milestones, update_params = get_milestones_for_update
update_params = milestone_params.select { |key| key == "state_event" }
milestones = @milestone.milestones
else
update_params = milestone_params
milestones = [@milestone]
end
milestones.each do |milestone| milestones.each do |milestone|
Milestones::UpdateService.new(milestone.parent, current_user, update_params).execute(milestone) Milestones::UpdateService.new(milestone.parent, current_user, update_params).execute(milestone)
end end
...@@ -71,6 +64,14 @@ class Groups::MilestonesController < Groups::ApplicationController ...@@ -71,6 +64,14 @@ class Groups::MilestonesController < Groups::ApplicationController
private private
def get_milestones_for_update
if @milestone.legacy_group_milestone?
[@milestone.milestones, legacy_milestone_params]
else
[[@milestone], milestone_params]
end
end
def authorize_admin_milestones! def authorize_admin_milestones!
return render_404 unless can?(current_user, :admin_milestone, group) return render_404 unless can?(current_user, :admin_milestone, group)
end end
...@@ -79,6 +80,10 @@ class Groups::MilestonesController < Groups::ApplicationController ...@@ -79,6 +80,10 @@ class Groups::MilestonesController < Groups::ApplicationController
params.require(:milestone).permit(:title, :description, :start_date, :due_date, :state_event) params.require(:milestone).permit(:title, :description, :start_date, :due_date, :state_event)
end end
def legacy_milestone_params
params.require(:milestone).permit(:state_event)
end
def milestone_path def milestone_path
if @milestone.legacy_group_milestone? if @milestone.legacy_group_milestone?
group_milestone_path(group, @milestone.safe_title, title: @milestone.title) group_milestone_path(group, @milestone.safe_title, title: @milestone.title)
......
...@@ -237,12 +237,15 @@ module MilestonesHelper ...@@ -237,12 +237,15 @@ module MilestonesHelper
end end
end end
def group_or_dashboard_milestone_path(milestone) def group_or_project_milestone_path(milestone)
params =
if milestone.group_milestone? if milestone.group_milestone?
group_milestone_path(milestone.group, milestone.iid, milestone: { title: milestone.title }) { milestone: { title: milestone.title } }
else else
dashboard_milestone_path(milestone.safe_title, title: milestone.title) { title: milestone.title }
end end
milestone_path(milestone.milestone, params)
end end
def can_admin_project_milestones? def can_admin_project_milestones?
......
...@@ -42,7 +42,7 @@ module Milestoneish ...@@ -42,7 +42,7 @@ module Milestoneish
def issues_visible_to_user(user) def issues_visible_to_user(user)
memoize_per_user(user, :issues_visible_to_user) do memoize_per_user(user, :issues_visible_to_user) do
IssuesFinder.new(user, issues_finder_params) IssuesFinder.new(user, issues_finder_params)
.execute.preload(:assignees).where(milestone_id: milestoneish_ids) .execute.preload(:assignees).where(milestone_id: milestoneish_id)
end end
end end
......
...@@ -7,7 +7,7 @@ class DashboardGroupMilestone < GlobalMilestone ...@@ -7,7 +7,7 @@ class DashboardGroupMilestone < GlobalMilestone
override :initialize override :initialize
def initialize(milestone) def initialize(milestone)
super(milestone.title, Array(milestone)) super
@group_name = milestone.group.full_name @group_name = milestone.group.full_name
end end
...@@ -19,22 +19,4 @@ class DashboardGroupMilestone < GlobalMilestone ...@@ -19,22 +19,4 @@ class DashboardGroupMilestone < GlobalMilestone
.active .active
.map { |m| new(m) } .map { |m| new(m) }
end end
override :group_milestone?
def group_milestone?
@first_milestone.group_milestone?
end
override :milestoneish_ids
def milestoneish_ids
milestones.map(&:id)
end
def group
@first_milestone.group
end
def iid
@first_milestone.iid
end
end end
# frozen_string_literal: true # frozen_string_literal: true
class DashboardMilestone < GlobalMilestone class DashboardMilestone < GlobalMilestone
def issues_finder_params attr_reader :project_name
{ authorized_only: true }
def initialize(milestone)
super
@project_name = milestone.project.full_name
end end
def dashboard_milestone? def project_milestone?
true true
end end
end end
...@@ -3,69 +3,78 @@ ...@@ -3,69 +3,78 @@
class GlobalMilestone class GlobalMilestone
include Milestoneish include Milestoneish
EPOCH = DateTime.parse('1970-01-01')
STATE_COUNT_HASH = { opened: 0, closed: 0, all: 0 }.freeze STATE_COUNT_HASH = { opened: 0, closed: 0, all: 0 }.freeze
attr_accessor :title, :milestones attr_reader :milestone
alias_attribute :name, :title alias_attribute :name, :title
delegate :title, :state, :due_date, :start_date, :participants, :project, :group, :expires_at, :closed?, :iid, :group_milestone?, :safe_title, :milestoneish_id, to: :milestone
def to_hash
{
name: title,
title: title,
group_name: group&.full_name,
project_name: project&.full_name
}
end
def for_display def for_display
@first_milestone @milestone
end end
def self.build_collection(projects, params) def self.build_collection(projects, params)
params = items = Milestone.of_projects(projects)
{ project_ids: projects.map(&:id), state: params[:state] } .reorder_by_due_date_asc
.order_by_name_asc
child_milestones = MilestonesFinder.new(params).execute # rubocop: disable CodeReuse/Finder
milestones = child_milestones.select(:id, :title).group_by(&:title).map do |title, grouped|
milestones_relation = Milestone.where(id: grouped.map(&:id))
new(title, milestones_relation)
end
milestones.sort_by { |milestone| milestone.due_date || EPOCH } Milestone.filter_by_state(items, params[:state]).map { |m| new(m) }
end end
# necessary for legacy milestones
def self.build(projects, title) def self.build(projects, title)
child_milestones = Milestone.of_projects(projects).where(title: title) milestones = Milestone.of_projects(projects).where(title: title)
return if child_milestones.blank? return if milestones.blank?
new(title, child_milestones) new(milestones.first)
end end
def self.count_by_state(milestones_by_state_and_title, state) def self.states_count(projects, group = nil)
milestones_by_state_and_title.count do |(milestone_state, _), _| legacy_group_milestones_count = legacy_group_milestone_states_count(projects)
milestone_state == state group_milestones_count = group_milestones_states_count(group)
legacy_group_milestones_count.merge(group_milestones_count) do |k, legacy_group_milestones_count, group_milestones_count|
legacy_group_milestones_count + group_milestones_count
end end
end end
private_class_method :count_by_state
def initialize(title, milestones) def self.group_milestones_states_count(group)
@title = title return STATE_COUNT_HASH unless group
@name = title
@milestones = milestones
@first_milestone = milestones.find {|m| m.description.present? } || milestones.first
end
def milestoneish_ids counts_by_state = Milestone.of_groups(group).count_by_state
milestones.select(:id)
end
def safe_title {
@title.to_slug.normalize.to_s opened: counts_by_state['active'] || 0,
closed: counts_by_state['closed'] || 0,
all: counts_by_state.values.sum
}
end end
def projects def self.legacy_group_milestone_states_count(projects)
@projects ||= Project.for_milestones(milestoneish_ids) return STATE_COUNT_HASH unless projects
end
# We need to reorder(nil) on the projects, because the controller passes them in sorted.
relation = Milestone.of_projects(projects.reorder(nil)).count_by_state
def state {
milestones.each do |milestone| opened: relation['active'] || 0,
return 'active' if milestone.state != 'closed' closed: relation['closed'] || 0,
all: relation.values.sum
}
end end
'closed' def initialize(milestone)
@milestone = milestone
end end
def active? def active?
...@@ -77,37 +86,14 @@ class GlobalMilestone ...@@ -77,37 +86,14 @@ class GlobalMilestone
end end
def issues def issues
@issues ||= Issue.of_milestones(milestoneish_ids).includes(:project, :assignees, :labels) @issues ||= Issue.of_milestones(milestone).includes(:project, :assignees, :labels)
end end
def merge_requests def merge_requests
@merge_requests ||= MergeRequest.of_milestones(milestoneish_ids).includes(:target_project, :assignee, :labels) @merge_requests ||= MergeRequest.of_milestones(milestone).includes(:target_project, :assignee, :labels)
end
def participants
@participants ||= milestones.map(&:participants).flatten.uniq
end end
def labels def labels
@labels ||= GlobalLabel.build_collection(milestones.includes(:labels).map(&:labels).flatten) @labels ||= GlobalLabel.build_collection(milestone.labels).sort_by!(&:title)
.sort_by!(&:title)
end
def due_date
return @due_date if defined?(@due_date)
@due_date =
if @milestones.all? { |x| x.due_date == @milestones.first.due_date }
@milestones.first.due_date
end
end
def start_date
return @start_date if defined?(@start_date)
@start_date =
if @milestones.all? { |x| x.start_date == @milestones.first.start_date }
@milestones.first.start_date
end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
# Group Milestones are milestones that can be shared among many projects within the same group # Group Milestones are milestones that can be shared among many projects within the same group
class GroupMilestone < GlobalMilestone class GroupMilestone < GlobalMilestone
attr_accessor :group attr_reader :group, :milestones
def self.build_collection(group, projects, params) def self.build_collection(group, projects, params)
super(projects, params).each do |milestone| params =
milestone.group = group { state: params[:state] }
project_milestones = Milestone.of_projects(projects)
child_milestones = Milestone.filter_by_state(project_milestones, params[:state])
grouped_milestones = child_milestones.group_by(&:title)
grouped_milestones.map do |title, grouped|
new(title, grouped, group)
end end
end end
def self.build(group, projects, title) def self.build(group, projects, title)
super(projects, title).tap do |milestone| child_milestones = Milestone.of_projects(projects).where(title: title)
milestone&.group = group return if child_milestones.blank?
new(title, child_milestones, group)
end end
def initialize(title, milestones, group)
@milestones = milestones
@group = group
end
def milestone
@milestone ||= milestones.find { |m| m.description.present? } || milestones.first
end end
def issues_finder_params def issues_finder_params
......
...@@ -94,6 +94,10 @@ class Milestone < ActiveRecord::Base ...@@ -94,6 +94,10 @@ class Milestone < ActiveRecord::Base
end end
end end
def count_by_state
reorder(nil).group(:state).count
end
def predefined?(milestone) def predefined?(milestone)
milestone == Any || milestone == Any ||
milestone == None || milestone == None ||
...@@ -215,7 +219,7 @@ class Milestone < ActiveRecord::Base ...@@ -215,7 +219,7 @@ class Milestone < ActiveRecord::Base
self.title self.title
end end
def milestoneish_ids def milestoneish_id
id id
end end
......
= render 'shared/milestones/milestone', = render 'shared/milestones/milestone',
milestone_path: group_or_dashboard_milestone_path(milestone), milestone_path: group_or_project_milestone_path(milestone),
issues_path: issues_dashboard_path(milestone_title: milestone.title), issues_path: issues_dashboard_path(milestone_title: milestone.title),
merge_requests_path: merge_requests_dashboard_path(milestone_title: milestone.title), merge_requests_path: merge_requests_dashboard_path(milestone_title: milestone.title),
milestone: milestone, milestone: milestone,
......
- dashboard = local_assigns[:dashboard] - dashboard = local_assigns[:dashboard]
- custom_dom_id = dom_id(milestone.try(:milestones) ? milestone.milestones.first : milestone) - custom_dom_id = dom_id(milestone.try(:milestone) ? milestone.milestone : milestone)
- milestone_type = milestone.group_milestone? ? 'Group Milestone' : 'Project Milestone' - milestone_type = milestone.group_milestone? ? 'Group Milestone' : 'Project Milestone'
%li{ class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: custom_dom_id } %li{ class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: custom_dom_id }
...@@ -21,10 +21,12 @@ ...@@ -21,10 +21,12 @@
= milestone.group.full_name = milestone.group.full_name
- if milestone.legacy_group_milestone? - if milestone.legacy_group_milestone?
.projects .projects
- milestone.milestones.each do |milestone| - link_to milestone_path(milestone.milestone) do
= link_to milestone_path(milestone) do
%span.label-badge.label-badge-blue.d-inline-block.append-bottom-5 %span.label-badge.label-badge-blue.d-inline-block.append-bottom-5
= dashboard ? milestone.project.full_name : milestone.project.name = dashboard ? milestone.project.full_name : milestone.project.name
- if milestone.project
.label-badge.label-badge-gray.d-inline-block
= milestone.project.full_name
.col-sm-4.milestone-progress .col-sm-4.milestone-progress
= milestone_progress_bar(milestone) = milestone_progress_bar(milestone)
...@@ -58,5 +60,5 @@ ...@@ -58,5 +60,5 @@
- else - else
= link_to 'Close Milestone', group_milestone_route(milestone, {state_event: :close }), method: :put, class: "btn btn-sm btn-grouped btn-close" = link_to 'Close Milestone', group_milestone_route(milestone, {state_event: :close }), method: :put, class: "btn btn-sm btn-grouped btn-close"
- if dashboard - if dashboard
.status-box.status-box-milestone .label-badge.label-badge-gray
= milestone_type = milestone_type
...@@ -62,20 +62,19 @@ ...@@ -62,20 +62,19 @@
%th Open issues %th Open issues
%th State %th State
%th Due date %th Due date
- milestone.milestones.each do |ms|
%tr %tr
%td %td
- project_name = group ? ms.project.name : ms.project.full_name - project_name = group ? milestone.project.name : milestone.project.full_name
= link_to project_name, project_milestone_path(ms.project, ms) = link_to project_name, milestone_path(milestone.milestone)
%td %td
= ms.issues_visible_to_user(current_user).opened.count = milestone.milestone.issues_visible_to_user(current_user).opened.count
%td %td
- if ms.closed? - if milestone.closed?
Closed Closed
- else - else
Open Open
%td %td
= ms.expires_at = milestone.expires_at
- elsif milestone.group_milestone? - elsif milestone.group_milestone?
%br %br
View View
......
---
title: Add project milestone link
merge_request: 22552
author:
type: added
...@@ -52,7 +52,7 @@ describe Dashboard::MilestonesController do ...@@ -52,7 +52,7 @@ describe Dashboard::MilestonesController do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response.size).to eq(2) expect(json_response.size).to eq(2)
expect(json_response.map { |i| i["first_milestone"]["id"] }).to match_array([group_milestone.id, project_milestone.id]) expect(json_response.map { |i| i["name"] }).to match_array([group_milestone.name, project_milestone.name])
expect(json_response.map { |i| i["group_name"] }.compact).to match_array(group.name) expect(json_response.map { |i| i["group_name"] }.compact).to match_array(group.name)
end end
......
...@@ -64,7 +64,7 @@ describe Groups::MilestonesController do ...@@ -64,7 +64,7 @@ describe Groups::MilestonesController do
context 'when there is a title parameter' do context 'when there is a title parameter' do
it 'searches for a legacy group milestone' do it 'searches for a legacy group milestone' do
expect(GlobalMilestone).to receive(:build) expect(GroupMilestone).to receive(:build)
expect(Milestone).not_to receive(:find_by_iid) expect(Milestone).not_to receive(:find_by_iid)
get :show, params: { group_id: group.to_param, id: title, title: milestone1.safe_title } get :show, params: { group_id: group.to_param, id: title, title: milestone1.safe_title }
......
...@@ -81,7 +81,7 @@ describe 'Group milestones' do ...@@ -81,7 +81,7 @@ describe 'Group milestones' do
description: 'Lorem Ipsum is simply dummy text' description: 'Lorem Ipsum is simply dummy text'
) )
end end
let!(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.0') } let!(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.1') }
let!(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') } let!(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') }
let!(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') } let!(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') }
let!(:active_group_milestone) { create(:milestone, group: group, state: 'active', title: 'GL-113') } let!(:active_group_milestone) { create(:milestone, group: group, state: 'active', title: 'GL-113') }
...@@ -104,7 +104,7 @@ describe 'Group milestones' do ...@@ -104,7 +104,7 @@ describe 'Group milestones' do
legacy_milestone = GroupMilestone.build_collection(group, group.projects, { state: 'active' }).first legacy_milestone = GroupMilestone.build_collection(group, group.projects, { state: 'active' }).first
expect(page).to have_selector("#milestone_#{active_group_milestone.id}", count: 1) expect(page).to have_selector("#milestone_#{active_group_milestone.id}", count: 1)
expect(page).to have_selector("#milestone_#{legacy_milestone.milestones.first.id}", count: 1) expect(page).to have_selector("#milestone_#{legacy_milestone.milestone.id}", count: 1)
end end
it 'shows milestone detail and supports its edit' do it 'shows milestone detail and supports its edit' do
...@@ -121,6 +121,7 @@ describe 'Group milestones' do ...@@ -121,6 +121,7 @@ describe 'Group milestones' do
it 'renders milestones' do it 'renders milestones' do
expect(page).to have_content('v1.0') expect(page).to have_content('v1.0')
expect(page).to have_content('v1.1')
expect(page).to have_content('GL-113') expect(page).to have_content('GL-113')
expect(page).to have_link( expect(page).to have_link(
'1 Issue', '1 Issue',
......
...@@ -42,6 +42,7 @@ describe 'Milestones sorting', :js do ...@@ -42,6 +42,7 @@ describe 'Milestones sorting', :js do
expect(page).to have_button('Due later') expect(page).to have_button('Due later')
# assert descending sorting
within '.milestones' do within '.milestones' do
expect(page.all('ul.content-list > li').first.text).to include('v1.0') expect(page.all('ul.content-list > li').first.text).to include('v1.0')
expect(page.all('ul.content-list > li')[1].text).to include('v3.0') expect(page.all('ul.content-list > li')[1].text).to include('v3.0')
......
...@@ -65,56 +65,103 @@ describe GlobalMilestone do ...@@ -65,56 +65,103 @@ describe GlobalMilestone do
) )
end end
before do let!(:projects) do
projects = [ [
project1, project1,
project2, project2,
project3 project3
] ]
@global_milestones = described_class.build_collection(projects, {})
end end
let!(:global_milestones) { described_class.build_collection(projects, {}) }
context 'when building a collection of milestones' do
it 'has all project milestones' do it 'has all project milestones' do
expect(@global_milestones.count).to eq(2) expect(global_milestones.count).to eq(6)
end end
it 'has all project milestones titles' do it 'has all project milestones titles' do
expect(@global_milestones.map(&:title)).to match_array(['Milestone v1.2', 'VD-123']) expect(global_milestones.map(&:title)).to match_array(['Milestone v1.2', 'Milestone v1.2', 'Milestone v1.2', 'VD-123', 'VD-123', 'VD-123'])
end end
it 'has all project milestones' do it 'has all project milestones' do
expect(@global_milestones.map { |group_milestone| group_milestone.milestones.count }.sum).to eq(6) expect(global_milestones.size).to eq(6)
end end
it 'sorts collection by due date' do it 'sorts collection by due date' do
expect(@global_milestones.map(&:due_date)).to eq [nil, milestone1_due_date] expect(global_milestones.map(&:due_date)).to eq [milestone1_due_date, milestone1_due_date, milestone1_due_date, nil, nil, nil]
end end
end end
describe '#initialize' do context 'when adding new milestones' do
let(:milestone1_project1) { create(:milestone, title: "Milestone v1.2", project: project1) } it 'does not add more queries' do
let(:milestone1_project2) { create(:milestone, title: "Milestone v1.2", project: project2) } control_count = ActiveRecord::QueryRecorder.new do
let(:milestone1_project3) { create(:milestone, title: "Milestone v1.2", project: project3) } described_class.build_collection(projects, {})
end.count
create_list(:milestone, 3, project: project3)
expect do
described_class.build_collection(projects, {})
end.not_to exceed_all_query_limit(control_count)
end
end
end
describe '.states_count' do
context 'when the projects have milestones' do
before do before do
milestones = create(:closed_milestone, title: 'Active Group Milestone', project: project3)
[ create(:active_milestone, title: 'Active Group Milestone', project: project1)
milestone1_project1, create(:active_milestone, title: 'Active Group Milestone', project: project2)
milestone1_project2, create(:closed_milestone, title: 'Closed Group Milestone', project: project1)
milestone1_project3 create(:closed_milestone, title: 'Closed Group Milestone', project: project2)
] create(:closed_milestone, title: 'Closed Group Milestone', project: project3)
milestones_relation = Milestone.where(id: milestones.map(&:id)) create(:closed_milestone, title: 'Closed Group Milestone 4', group: group)
end
it 'returns the quantity of global milestones and group milestones in each possible state' do
expected_count = { opened: 2, closed: 5, all: 7 }
@global_milestone = described_class.new(milestone1_project1.title, milestones_relation) count = described_class.states_count(Project.all, group)
expect(count).to eq(expected_count)
end end
it 'returns the quantity of global milestones in each possible state' do
expected_count = { opened: 2, closed: 4, all: 6 }
count = described_class.states_count(Project.all)
expect(count).to eq(expected_count)
end
end
context 'when the projects do not have milestones' do
before do
project1
end
it 'returns 0 as the quantity of global milestones in each state' do
expected_count = { opened: 0, closed: 0, all: 0 }
count = described_class.states_count(Project.all)
expect(count).to eq(expected_count)
end
end
end
describe '#initialize' do
let(:milestone1_project1) { create(:milestone, title: "Milestone v1.2", project: project1) }
subject(:global_milestone) { described_class.new(milestone1_project1) }
it 'has exactly one group milestone' do it 'has exactly one group milestone' do
expect(@global_milestone.title).to eq('Milestone v1.2') expect(global_milestone.title).to eq('Milestone v1.2')
end end
it 'has all project milestones with the same title' do it 'has all project milestones with the same title' do
expect(@global_milestone.milestones.count).to eq(3) expect(global_milestone.milestone).to eq(milestone1_project1)
end end
end end
...@@ -122,7 +169,7 @@ describe GlobalMilestone do ...@@ -122,7 +169,7 @@ describe GlobalMilestone do
let(:milestone) { create(:milestone, title: "git / test", project: project1) } let(:milestone) { create(:milestone, title: "git / test", project: project1) }
it 'strips out slashes and spaces' do it 'strips out slashes and spaces' do
global_milestone = described_class.new(milestone.title, Milestone.where(id: milestone.id)) global_milestone = described_class.new(milestone)
expect(global_milestone.safe_title).to eq('git-test') expect(global_milestone.safe_title).to eq('git-test')
end end
...@@ -132,11 +179,8 @@ describe GlobalMilestone do ...@@ -132,11 +179,8 @@ describe GlobalMilestone do
context 'when at least one milestone is active' do context 'when at least one milestone is active' do
it 'returns active' do it 'returns active' do
title = 'Active Group Milestone' title = 'Active Group Milestone'
milestones = [
create(:active_milestone, title: title), global_milestone = described_class.new(create(:active_milestone, title: title))
create(:closed_milestone, title: title)
]
global_milestone = described_class.new(title, milestones)
expect(global_milestone.state).to eq('active') expect(global_milestone.state).to eq('active')
end end
...@@ -145,11 +189,8 @@ describe GlobalMilestone do ...@@ -145,11 +189,8 @@ describe GlobalMilestone do
context 'when all milestones are closed' do context 'when all milestones are closed' do
it 'returns closed' do it 'returns closed' do
title = 'Closed Group Milestone' title = 'Closed Group Milestone'
milestones = [
create(:closed_milestone, title: title), global_milestone = described_class.new(create(:closed_milestone, title: title))
create(:closed_milestone, title: title)
]
global_milestone = described_class.new(title, milestones)
expect(global_milestone.state).to eq('closed') expect(global_milestone.state).to eq('closed')
end end
......
...@@ -20,13 +20,36 @@ describe GroupMilestone do ...@@ -20,13 +20,36 @@ describe GroupMilestone do
end end
describe '.build_collection' do describe '.build_collection' do
before do let(:group) { create(:group) }
project_milestone let(:project1) { create(:project, group: group) }
let(:project2) { create(:project, path: 'gitlab-ci', group: group) }
let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) }
let!(:projects) do
[
project1,
project2,
project3
]
end end
it 'returns array of milestones, each with group assigned' do it 'returns array of milestones, each with group assigned' do
milestones = described_class.build_collection(group, [project], {}) milestones = described_class.build_collection(group, [project], {})
expect(milestones).to all(have_attributes(group: group)) expect(milestones).to all(have_attributes(group: group))
end end
context 'when adding new milestones' do
it 'does not add more queries' do
control_count = ActiveRecord::QueryRecorder.new do
described_class.build_collection(group, projects, {})
end.count
create(:milestone, title: 'This title', project: project1)
expect do
described_class.build_collection(group, projects, {})
end.not_to exceed_all_query_limit(control_count)
end
end
end end
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