Commit ce5c8c67 authored by Jan Provaznik's avatar Jan Provaznik

Merge branch 'bulk-edit-health-status' into 'master'

Bulk edit health status

See merge request gitlab-org/gitlab!33065
parents e99e3f2d 6143f05f
...@@ -86,6 +86,7 @@ export default { ...@@ -86,6 +86,7 @@ export default {
milestone_id: this.form.find('input[name="update[milestone_id]"]').val(), milestone_id: this.form.find('input[name="update[milestone_id]"]').val(),
issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(), issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(),
subscription_event: this.form.find('input[name="update[subscription_event]"]').val(), subscription_event: this.form.find('input[name="update[subscription_event]"]').val(),
health_status: this.form.find('input[name="update[health_status]"]').val(),
add_label_ids: [], add_label_ids: [],
remove_label_ids: [], remove_label_ids: [],
}, },
......
...@@ -7,6 +7,8 @@ import MilestoneSelect from './milestone_select'; ...@@ -7,6 +7,8 @@ import MilestoneSelect from './milestone_select';
import issueStatusSelect from './issue_status_select'; import issueStatusSelect from './issue_status_select';
import subscriptionSelect from './subscription_select'; import subscriptionSelect from './subscription_select';
import LabelsSelect from './labels_select'; import LabelsSelect from './labels_select';
import HealthStatusSelect from 'ee_else_ce/vue_shared/components/sidebar/health_status_select/health_status_bundle';
import issueableEventHub from './issuables_list/eventhub'; import issueableEventHub from './issuables_list/eventhub';
const HIDDEN_CLASS = 'hidden'; const HIDDEN_CLASS = 'hidden';
...@@ -63,6 +65,10 @@ export default class IssuableBulkUpdateSidebar { ...@@ -63,6 +65,10 @@ export default class IssuableBulkUpdateSidebar {
new MilestoneSelect(); new MilestoneSelect();
issueStatusSelect(); issueStatusSelect();
subscriptionSelect(); subscriptionSelect();
if (HealthStatusSelect) {
HealthStatusSelect();
}
} }
setupBulkUpdateActions() { setupBulkUpdateActions() {
......
...@@ -110,9 +110,13 @@ module IssuableActions ...@@ -110,9 +110,13 @@ module IssuableActions
def bulk_update def bulk_update
result = Issuable::BulkUpdateService.new(parent, current_user, bulk_update_params).execute(resource_name) result = Issuable::BulkUpdateService.new(parent, current_user, bulk_update_params).execute(resource_name)
quantity = result[:count]
if result.success?
quantity = result.payload[:count]
render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" } render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" }
elsif result.error?
render json: { errors: result.message }, status: result.http_status
end
end end
# rubocop:disable CodeReuse/ActiveRecord # rubocop:disable CodeReuse/ActiveRecord
......
...@@ -11,40 +11,29 @@ module Issuable ...@@ -11,40 +11,29 @@ module Issuable
end end
def execute(type) def execute(type)
model_class = type.classify.constantize
update_class = type.classify.pluralize.constantize::UpdateService
ids = params.delete(:issuable_ids).split(",") ids = params.delete(:issuable_ids).split(",")
items = find_issuables(parent, model_class, ids) set_update_params(type)
items = update_issuables(type, ids)
response_success(payload: { count: items.count })
rescue ArgumentError => e
response_error(e.message, 422)
end
private
def set_update_params(type)
params.slice!(*permitted_attrs(type)) params.slice!(*permitted_attrs(type))
params.delete_if { |k, v| v.blank? } params.delete_if { |k, v| v.blank? }
if params[:assignee_ids] == [IssuableFinder::Params::NONE.to_s] if params[:assignee_ids] == [IssuableFinder::Params::NONE.to_s]
params[:assignee_ids] = [] params[:assignee_ids] = []
end end
items.each do |issuable|
next unless can?(current_user, :"update_#{type}", issuable)
update_class.new(issuable.issuing_parent, current_user, params).execute(issuable)
end
{
count: items.count,
success: !items.count.zero?
}
end end
private
def permitted_attrs(type) def permitted_attrs(type)
attrs = %i(state_event milestone_id add_label_ids remove_label_ids subscription_event) attrs = %i(state_event milestone_id add_label_ids remove_label_ids subscription_event)
issuable_specific_attrs(type, attrs)
end
def issuable_specific_attrs(type, attrs)
if type == 'issue' || type == 'merge_request' if type == 'issue' || type == 'merge_request'
attrs.push(:assignee_ids) attrs.push(:assignee_ids)
else else
...@@ -52,6 +41,20 @@ module Issuable ...@@ -52,6 +41,20 @@ module Issuable
end end
end end
def update_issuables(type, ids)
model_class = type.classify.constantize
update_class = type.classify.pluralize.constantize::UpdateService
items = find_issuables(parent, model_class, ids)
items.each do |issuable|
next unless can?(current_user, :"update_#{type}", issuable)
update_class.new(issuable.issuing_parent, current_user, params).execute(issuable)
end
items
end
def find_issuables(parent, model_class, ids) def find_issuables(parent, model_class, ids)
if parent.is_a?(Project) if parent.is_a?(Project)
model_class.id_in(ids).of_projects(parent) model_class.id_in(ids).of_projects(parent)
...@@ -59,6 +62,14 @@ module Issuable ...@@ -59,6 +62,14 @@ module Issuable
model_class.id_in(ids).of_projects(parent.all_projects) model_class.id_in(ids).of_projects(parent.all_projects)
end end
end end
def response_success(message: nil, payload: nil)
ServiceResponse.success(message: message, payload: payload)
end
def response_error(message, http_status)
ServiceResponse.error(message: message, http_status: http_status)
end
end end
end end
......
- type = local_assigns.fetch(:type) - type = local_assigns.fetch(:type)
- bulk_issue_health_status_flag = Feature.enabled?(:bulk_update_health_status, @project&.group) && type == :issues && @project&.group&.feature_available?(:issuable_health_status)
%aside.issues-bulk-update.js-right-sidebar.right-sidebar{ "aria-live" => "polite", data: { 'signed-in': current_user.present? } } %aside.issues-bulk-update.js-right-sidebar.right-sidebar{ "aria-live" => "polite", data: { 'signed-in': current_user.present? } }
.issuable-sidebar.hidden .issuable-sidebar.hidden
...@@ -36,6 +37,13 @@ ...@@ -36,6 +37,13 @@
= _('Labels') = _('Labels')
.filter-item.labels-filter .filter-item.labels-filter
= render "shared/issuable/label_dropdown", classes: ["js-filter-bulk-update", "js-multiselect"], dropdown_title: _("Apply a label"), show_create: false, show_footer: false, extra_options: false, filter_submit: false, data_options: { persist_when_hide: "true", field_name: "update[label_ids][]", show_no: false, show_any: false, use_id: true, default_label: _("Labels") }, label_name: _("Select labels"), no_default_styles: true = render "shared/issuable/label_dropdown", classes: ["js-filter-bulk-update", "js-multiselect"], dropdown_title: _("Apply a label"), show_create: false, show_footer: false, extra_options: false, filter_submit: false, data_options: { persist_when_hide: "true", field_name: "update[label_ids][]", show_no: false, show_any: false, use_id: true, default_label: _("Labels") }, label_name: _("Select labels"), no_default_styles: true
- if bulk_issue_health_status_flag
.block
.title
= _('Health status')
.filter-item.health-status.health-status-filter
#js-bulk-update-health-status-root
%input{ id: 'issue_health_status_value', type: 'hidden', name: 'update[health_status]' }
.block .block
.title .title
= _('Subscriptions') = _('Subscriptions')
......
<script>
import { GlButton, GlDropdownItem, GlDropdown, GlDropdownDivider } from '@gitlab/ui';
import { s__ } from '~/locale';
import { healthStatusTextMap } from '../../constants';
export default {
components: {
GlButton,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
},
props: {
isEditable: {
type: Boolean,
required: false,
default: false,
},
isFetching: {
type: Boolean,
required: false,
default: false,
},
status: {
type: String,
required: false,
default: '',
},
},
data() {
return {
isDropdownShowing: false,
selectedStatus: this.status,
statusOptions: Object.keys(healthStatusTextMap).map(key => ({
key,
value: healthStatusTextMap[key],
})),
};
},
computed: {
statusText() {
return this.status ? healthStatusTextMap[this.status] : s__('Sidebar|None');
},
dropdownText() {
if (this.status === null) {
return s__('No status');
}
return this.status ? healthStatusTextMap[this.status] : s__('Select health status');
},
tooltipText() {
let tooltipText = s__('Sidebar|Health status');
if (this.status) {
tooltipText += `: ${this.statusText}`;
}
return tooltipText;
},
},
watch: {
status(status) {
this.selectedStatus = status;
},
},
methods: {
handleDropdownClick(status) {
this.selectedStatus = status;
this.$emit('onDropdownClick', status);
this.hideDropdown();
},
hideDropdown() {
this.isDropdownShowing = false;
},
isSelected(status) {
return this.status === status;
},
},
};
</script>
<template>
<div class="dropdown dropdown-menu-selectable">
<gl-dropdown
ref="dropdown"
class="w-100"
:text="dropdownText"
@keydown.esc.native="hideDropdown"
@hide="hideDropdown"
>
<div class="dropdown-title">
<span class="health-title">{{ s__('Sidebar|Assign health status') }}</span>
<gl-button
:aria-label="__('Close')"
variant="link"
class="dropdown-title-button dropdown-menu-close"
icon="close"
@click="hideDropdown"
/>
</div>
<div class="dropdown-content dropdown-body">
<gl-dropdown-item @click="handleDropdownClick(null)">
<gl-button
variant="link"
class="dropdown-item health-dropdown-item"
:class="{ 'is-active': isSelected(null) }"
>
{{ s__('Sidebar|No status') }}
</gl-button>
</gl-dropdown-item>
<gl-dropdown-divider class="divider health-divider" />
<gl-dropdown-item
v-for="option in statusOptions"
:key="option.key"
@click="handleDropdownClick(option.key)"
>
<gl-button
variant="link"
class="dropdown-item health-dropdown-item"
:class="{ 'is-active': isSelected(option.key) }"
>
{{ option.value }}
</gl-button>
</gl-dropdown-item>
</div>
</gl-dropdown>
</div>
</template>
...@@ -18,3 +18,10 @@ export const iterationSelectTextMap = { ...@@ -18,3 +18,10 @@ export const iterationSelectTextMap = {
noIterationItem: [{ title: __('No iteration'), id: null }], noIterationItem: [{ title: __('No iteration'), id: null }],
iterationSelectFail: __('Failed to set iteration on this issue. Please try again.'), iterationSelectFail: __('Failed to set iteration on this issue. Please try again.'),
}; };
export const healthStatusForRestApi = {
NO_STATUS: '0',
[healthStatus.ON_TRACK]: 'on_track',
[healthStatus.NEEDS_ATTENTION]: 'needs_attention',
[healthStatus.AT_RISK]: 'at_risk',
};
import Vue from 'vue';
import HealthStatusSelect from 'ee/sidebar/components/status/health_status_dropdown.vue';
import { healthStatusForRestApi } from 'ee/sidebar/constants';
export default () => {
const el = document.getElementById('js-bulk-update-health-status-root');
const healthStatusFormFieldEl = document.getElementById('issue_health_status_value');
if (!el && !healthStatusFormFieldEl) {
return false;
}
return new Vue({
el,
components: {
HealthStatusSelect,
},
data() {
return {
selectedStatus: undefined,
};
},
methods: {
handleHealthStatusSelect(selectedStatus) {
this.selectedStatus = selectedStatus;
healthStatusFormFieldEl.setAttribute(
'value',
healthStatusForRestApi[selectedStatus || 'NO_STATUS'],
);
},
},
render(createElement) {
return createElement('health-status-select', {
props: {
isFetching: false,
isEditable: true,
showDropdown: true,
status: this.selectedStatus,
},
on: {
onDropdownClick: this.handleHealthStatusSelect.bind(this),
},
});
},
});
};
...@@ -7,6 +7,7 @@ module EE ...@@ -7,6 +7,7 @@ module EE
EE_PERMITTED_KEYS = %w[ EE_PERMITTED_KEYS = %w[
weight weight
health_status
].freeze ].freeze
private private
......
...@@ -14,11 +14,24 @@ module EE ...@@ -14,11 +14,24 @@ module EE
super super
end end
override :issuable_specific_attrs override :permitted_attrs
def issuable_specific_attrs(type, attrs) def permitted_attrs(type)
return super unless type == 'issue' return super unless type == 'issue'
super.push(:health_status, :epic) super.push(:health_status, :epic_id)
end
override :set_update_params
def set_update_params(type)
super
set_health_status
end
def set_health_status
return unless params[:health_status].present?
params[:health_status] = nil if params[:health_status] == IssuableFinder::Params::NONE.to_s
end end
end end
end end
......
- group = local_assigns.fetch(:group) - group = local_assigns.fetch(:group)
- type = local_assigns.fetch(:type) - type = local_assigns.fetch(:type)
- bulk_issue_health_status_flag = type == :issues && Feature.enabled?(:bulk_update_health_status, group) && group&.feature_available?(:issuable_health_status)
%aside.issues-bulk-update.js-right-sidebar.right-sidebar{ 'aria-live' => 'polite', data: { 'signed-in': current_user.present? } } %aside.issues-bulk-update.js-right-sidebar.right-sidebar{ 'aria-live' => 'polite', data: { 'signed-in': current_user.present? } }
.issuable-sidebar.hidden .issuable-sidebar.hidden
...@@ -19,6 +20,13 @@ ...@@ -19,6 +20,13 @@
= _('Labels') = _('Labels')
.filter-item.labels-filter .filter-item.labels-filter
= render "shared/issuable/label_dropdown", classes: ["js-filter-bulk-update", "js-multiselect"], dropdown_title: _('Apply a label'), show_create: false, show_footer: false, extra_options: false, filter_submit: false, data_options: { persist_when_hide: "true", field_name: "update[label_ids][]", show_no: false, show_any: false, use_id: true, default_label: "Labels" }, label_name: _('Select labels'), no_default_styles: true, edit_context: group = render "shared/issuable/label_dropdown", classes: ["js-filter-bulk-update", "js-multiselect"], dropdown_title: _('Apply a label'), show_create: false, show_footer: false, extra_options: false, filter_submit: false, data_options: { persist_when_hide: "true", field_name: "update[label_ids][]", show_no: false, show_any: false, use_id: true, default_label: "Labels" }, label_name: _('Select labels'), no_default_styles: true, edit_context: group
- if bulk_issue_health_status_flag
.block
.title
= _('Health status')
.filter-item.health-status.health-status-filter
#js-bulk-update-health-status-root
%input{ id: 'issue_health_status_value', type: 'hidden', name: 'update[health_status]' }
= hidden_field_tag 'update[issuable_ids]', [] = hidden_field_tag 'update[issuable_ids]', []
= hidden_field_tag :state_event, params[:state_event] = hidden_field_tag :state_event, params[:state_event]
---
title: Bulk edit health status
merge_request: 33065
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Issues > Health status bulk assignment' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, group: group) }
let_it_be(:issue1) { create(:issue, project: project, title: "Issue 1") }
let_it_be(:issue2) { create(:issue, project: project, title: "Issue 2") }
shared_examples 'bulk edit option in sidebar' do |context|
it 'is present when bulk edit is enabled' do
enable_bulk_update(context)
expect(page).to have_css('.issuable-sidebar')
end
it 'is not present when bulk edit is disabled' do
expect(page).not_to have_css('.issuable-sidebar')
end
end
shared_examples 'bulk edit health status' do |context|
before do
enable_bulk_update(context)
end
context 'health_status', :js do
context 'to all issues' do
before do
check 'check-all-issues'
open_health_status_dropdown ['On track']
update_issues
end
it 'updates the health statuses' do
expect(issue1.reload.health_status).to eq 'on_track'
expect(issue2.reload.health_status).to eq 'on_track'
end
end
context 'to an issue' do
before do
check "selected_issue_#{issue1.id}"
open_health_status_dropdown ['At risk']
update_issues
end
it 'updates the checked issue\'s status' do
expect(issue1.reload.health_status).to eq 'at_risk'
expect(issue2.reload.health_status).to eq nil
end
end
end
end
shared_examples 'bulk edit health_status with insufficient permissions' do
it 'cannot bulk assign health_status' do
expect(page).not_to have_button 'Edit issues'
expect(page).not_to have_css '.check-all-issues'
expect(page).not_to have_css '.issue-check'
end
end
before do
stub_feature_flags(vue_issuables_list: false)
end
context 'as an allowed user', :js do
before do
allow(group).to receive(:feature_enabled?).and_return(true)
stub_licensed_features(group_bulk_edit: true, issuable_health_status: true)
group.add_maintainer(user)
sign_in user
end
context 'at group level' do
it_behaves_like 'bulk edit option in sidebar', :group
it_behaves_like 'bulk edit health status', :group
end
context 'at project level' do
it_behaves_like 'bulk edit option in sidebar', :project
it_behaves_like 'bulk edit health status', :project
end
end
context 'as a guest', :js do
before do
sign_in user
allow(group).to receive(:feature_enabled?).and_return(true)
stub_licensed_features(issuable_health_status: true)
end
context 'at group level' do
before do
visit issues_group_path(group)
end
it_behaves_like 'bulk edit health_status with insufficient permissions'
end
context 'at project level' do
before do
visit project_issues_path(project)
end
it_behaves_like 'bulk edit health_status with insufficient permissions'
end
end
def open_health_status_dropdown(items = [])
page.within('.issues-bulk-update') do
click_button 'Select health status'
items.map do |item|
find('.gl-button-text', { text: item }).click
end
end
end
def toggle_issue(issue, uncheck = false)
page.within('.issues-list') do
if uncheck
uncheck "selected_issue_#{issue.id}"
else
check "selected_issue_#{issue.id}"
end
end
end
def uncheck_issue(issue)
toggle_issue(issue, uncheck: true)
end
def update_issues
find('.update-selected-issues').click
wait_for_requests
end
def enable_bulk_update(context)
if context == :project
visit project_issues_path(project)
else
visit issues_group_path(group)
end
click_button 'Edit issues'
end
end
...@@ -12,8 +12,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -12,8 +12,8 @@ RSpec.describe Issuable::BulkUpdateService do
shared_examples 'updates issuables attribute' do |attribute| shared_examples 'updates issuables attribute' do |attribute|
it 'succeeds and returns the correct number of issuables updated' do it 'succeeds and returns the correct number of issuables updated' do
expect(subject[:success]).to be_truthy expect(subject.success?).to be_truthy
expect(subject[:count]).to eq(issuables.count) expect(subject.payload[:count]).to eq(issuables.count)
issuables.each do |issuable| issuables.each do |issuable|
expect(issuable.reload.send(attribute)).to eq(new_value) expect(issuable.reload.send(attribute)).to eq(new_value)
end end
...@@ -31,48 +31,55 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -31,48 +31,55 @@ RSpec.describe Issuable::BulkUpdateService do
context 'with issues' do context 'with issues' do
let_it_be(:type) { 'issue' } let_it_be(:type) { 'issue' }
let_it_be(:parent) { group } let_it_be(:parent) { group }
let(:issue1) { create(:issue, project: project1, health_status: :at_risk, epic: epic) } let(:issue1) { create(:issue, project: project1, health_status: :at_risk) }
let(:issue2) { create(:issue, project: project2, health_status: :at_risk, epic: epic) } let(:issue2) { create(:issue, project: project2, health_status: :at_risk) }
let(:epic) { create(:epic, group: group) }
let(:epic2) { create(:epic, group: group) }
let(:issuables) { [issue1, issue2] } let(:issuables) { [issue1, issue2] }
before do before do
group.add_reporter(user) group.add_reporter(user)
end end
context 'updating health status and epic' do context 'updating health status' do
let(:params) do let(:params) do
{ {
issuable_ids: issuables.map(&:id), issuable_ids: issuables.map(&:id),
health_status: :on_track, health_status: :on_track
epic: epic2
} }
end end
context 'when features are enabled' do context 'when features are enabled' do
before do before do
stub_licensed_features(epics: true, issuable_health_status: true) stub_licensed_features(issuable_health_status: true)
end end
it 'succeeds and returns the correct number of issuables updated' do it 'succeeds and returns the correct number of issuables updated' do
expect(subject[:success]).to be_truthy expect(subject.success?).to be_truthy
expect(subject[:count]).to eq(issuables.count) expect(subject.payload[:count]).to eq(issuables.count)
issuables.each do |issuable|
expect(issuable.reload.health_status).to eq('on_track')
end
end
context "when params value is '0'" do
let(:params) { { issuable_ids: issuables.map(&:id), health_status: '0' } }
it 'succeeds and remove values' do
expect(subject.success?).to be_truthy
expect(subject.payload[:count]).to eq(issuables.count)
issuables.each do |issuable| issuables.each do |issuable|
issuable.reload issuable.reload
expect(issuable.epic).to eq(epic2) expect(issuable.health_status).to be_nil
expect(issuable.health_status).to eq('on_track') end
end end
end end
end end
context 'when features are disabled' do context 'when feature issuable_health_status is disabled' do
before do before do
stub_licensed_features(epics: false, issuable_health_status: false) stub_licensed_features(issuable_health_status: false)
end end
it_behaves_like 'does not update issuables attribute', :health_status it_behaves_like 'does not update issuables attribute', :health_status
it_behaves_like 'does not update issuables attribute', :epic
end end
context 'when user can not update issues' do context 'when user can not update issues' do
...@@ -81,14 +88,6 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -81,14 +88,6 @@ RSpec.describe Issuable::BulkUpdateService do
end end
it_behaves_like 'does not update issuables attribute', :health_status it_behaves_like 'does not update issuables attribute', :health_status
it_behaves_like 'does not update issuables attribute', :epic
end
context 'when user can not admin epic' do
let(:epic3) { create(:epic, group: create(:group)) }
let(:params) { { issuable_ids: issuables.map(&:id), epic: epic3 } }
it_behaves_like 'does not update issuables attribute', :epic
end end
end end
end end
...@@ -140,8 +139,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -140,8 +139,8 @@ RSpec.describe Issuable::BulkUpdateService do
let(:params) { { issuable_ids: [epic1.id, epic3.id, outer_epic.id], add_label_ids: [label3.id] } } let(:params) { { issuable_ids: [epic1.id, epic3.id, outer_epic.id], add_label_ids: [label3.id] } }
it 'updates epics that belong to the parent group or descendants' do it 'updates epics that belong to the parent group or descendants' do
expect(subject[:success]).to be_truthy expect(subject.success?).to be_truthy
expect(subject[:count]).to eq(2) expect(subject.payload[:count]).to eq(2)
expect(epic1.reload.labels).to eq([label1, label3]) expect(epic1.reload.labels).to eq([label1, label3])
expect(epic3.reload.labels).to eq([label1, label3]) expect(epic3.reload.labels).to eq([label1, label3])
......
...@@ -11749,6 +11749,9 @@ msgstr "" ...@@ -11749,6 +11749,9 @@ msgstr ""
msgid "Health information can be retrieved from the following endpoints. More information is available" msgid "Health information can be retrieved from the following endpoints. More information is available"
msgstr "" msgstr ""
msgid "Health status"
msgstr ""
msgid "HealthCheck|Access token is" msgid "HealthCheck|Access token is"
msgstr "" msgstr ""
...@@ -15391,6 +15394,9 @@ msgstr "" ...@@ -15391,6 +15394,9 @@ msgstr ""
msgid "No start date" msgid "No start date"
msgstr "" msgstr ""
msgid "No status"
msgstr ""
msgid "No template" msgid "No template"
msgstr "" msgstr ""
......
...@@ -18,8 +18,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -18,8 +18,8 @@ RSpec.describe Issuable::BulkUpdateService do
it 'succeeds' do it 'succeeds' do
result = bulk_update(issuables, milestone_id: milestone.id) result = bulk_update(issuables, milestone_id: milestone.id)
expect(result[:success]).to be_truthy expect(result.success?).to be_truthy
expect(result[:count]).to eq(issuables.count) expect(result.payload[:count]).to eq(issuables.count)
end end
it 'updates the issuables milestone' do it 'updates the issuables milestone' do
...@@ -121,8 +121,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -121,8 +121,8 @@ RSpec.describe Issuable::BulkUpdateService do
it 'succeeds and returns the correct number of issues updated' do it 'succeeds and returns the correct number of issues updated' do
result = bulk_update(issues, state_event: 'close') result = bulk_update(issues, state_event: 'close')
expect(result[:success]).to be_truthy expect(result.success?).to be_truthy
expect(result[:count]).to eq(issues.count) expect(result.payload[:count]).to eq(issues.count)
end end
it 'closes all the issues passed' do it 'closes all the issues passed' do
...@@ -139,8 +139,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -139,8 +139,8 @@ RSpec.describe Issuable::BulkUpdateService do
it 'succeeds and returns the correct number of issues updated' do it 'succeeds and returns the correct number of issues updated' do
result = bulk_update(issues, state_event: 'reopen') result = bulk_update(issues, state_event: 'reopen')
expect(result[:success]).to be_truthy expect(result.success?).to be_truthy
expect(result[:count]).to eq(issues.count) expect(result.payload[:count]).to eq(issues.count)
end end
it 'reopens all the issues passed' do it 'reopens all the issues passed' do
...@@ -161,8 +161,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -161,8 +161,8 @@ RSpec.describe Issuable::BulkUpdateService do
result = bulk_update(merge_request, assignee_ids: [user.id, new_assignee.id]) result = bulk_update(merge_request, assignee_ids: [user.id, new_assignee.id])
expect(result[:success]).to be_truthy expect(result.success?).to be_truthy
expect(result[:count]).to eq(1) expect(result.payload[:count]).to eq(1)
end end
it 'updates the assignee to the user ID passed' do it 'updates the assignee to the user ID passed' do
...@@ -199,8 +199,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -199,8 +199,8 @@ RSpec.describe Issuable::BulkUpdateService do
result = bulk_update(issue, assignee_ids: [new_assignee.id]) result = bulk_update(issue, assignee_ids: [new_assignee.id])
expect(result[:success]).to be_truthy expect(result.success?).to be_truthy
expect(result[:count]).to eq(1) expect(result.payload[:count]).to eq(1)
end end
it 'updates the assignee to the user ID passed' do it 'updates the assignee to the user ID passed' do
...@@ -273,8 +273,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -273,8 +273,8 @@ RSpec.describe Issuable::BulkUpdateService do
issue2 = create(:issue, project: create(:project)) issue2 = create(:issue, project: create(:project))
result = bulk_update([issue1, issue2], assignee_ids: [user.id]) result = bulk_update([issue1, issue2], assignee_ids: [user.id])
expect(result[:success]).to be_truthy expect(result.success?).to be_truthy
expect(result[:count]).to eq(1) expect(result.payload[:count]).to eq(1)
expect(issue1.reload.assignees).to eq([user]) expect(issue1.reload.assignees).to eq([user])
expect(issue2.reload.assignees).to be_empty expect(issue2.reload.assignees).to be_empty
...@@ -332,8 +332,8 @@ RSpec.describe Issuable::BulkUpdateService do ...@@ -332,8 +332,8 @@ RSpec.describe Issuable::BulkUpdateService do
milestone = create(:milestone, group: group) milestone = create(:milestone, group: group)
result = bulk_update([issue1, issue2, issue3], milestone_id: milestone.id) result = bulk_update([issue1, issue2, issue3], milestone_id: milestone.id)
expect(result[:success]).to be_truthy expect(result.success?).to be_truthy
expect(result[:count]).to eq(2) expect(result.payload[:count]).to eq(2)
expect(issue1.reload.milestone).to eq(milestone) expect(issue1.reload.milestone).to eq(milestone)
expect(issue2.reload.milestone).to be_nil expect(issue2.reload.milestone).to be_nil
......
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