Commit 7691d182 authored by Pedro Pombeiro's avatar Pedro Pombeiro Committed by Natalia Tepluhina

Add /health_status, /clear_health_status quick actions

parent 8bb0cff3
......@@ -639,6 +639,9 @@ You can then see the issue's status in the issues list and the epic tree.
After an issue is closed, its health status can't be edited and the **Edit** button becomes disabled
until the issue is reopened.
You can also set and clear health statuses using the `/health_status` and `/clear_health_status`
[quick actions](../quick_actions.md#issues-merge-requests-and-epics).
## Publish an issue **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30906) in GitLab 13.1.
......
This diff is collapsed.
---
key_path: redis_hll_counters.quickactions.i_quickactions_clear_health_status_monthly
name: "count_clear_health_status_quick_actions_monthly"
description: Count of MAU using the `/clear_health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_clear_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
---
key_path: redis_hll_counters.quickactions.i_quickactions_health_status_monthly
name: "count_health_status_quick_actions_monthly"
description: Count of MAU using the `/health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
---
key_path: redis_hll_counters.quickactions.i_quickactions_health_status_weekly
name: "count_health_status_quick_actions_weekly"
description: Count of WAU using the `/health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
---
key_path: redis_hll_counters.quickactions.i_quickactions_clear_health_status_weekly
name: "count_clear_health_status_quick_actions_weekly"
description: Count of WAU using the `/clear_health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_clear_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
......@@ -136,6 +136,52 @@ module EE
@execution_message[:publish] = _('Failed to publish issue on status page.')
end
end
desc _('Set health status')
explanation do |health_status|
_("Sets health status to %{health_status}.") % { health_status: health_status } if health_status
end
params "<#{::Issue.health_statuses.keys.join('|')}>"
types Issue
condition do
quick_action_target.supports_health_status? &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
end
parse_params do |health_status|
find_health_status(health_status)
end
command :health_status do |health_status|
if health_status
@updates[:health_status] = health_status
@execution_message[:health_status] = _("Set health status to %{health_status}.") % { health_status: health_status }
end
end
desc _('Clear health status')
explanation _('Clears health status.')
execution_message _('Cleared health status.')
types Issue
condition do
quick_action_target.persisted? &&
quick_action_target.supports_health_status? &&
quick_action_target.health_status &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
end
command :clear_health_status do
@updates[:health_status] = nil
end
end
private
def find_health_status(health_status_param)
return unless health_status_param
health_status_param = health_status_param.downcase
health_statuses = ::Issue.health_statuses.keys.map(&:downcase)
health_statuses.include?(health_status_param) && health_status_param
end
end
end
......
......@@ -1043,6 +1043,127 @@ RSpec.describe QuickActions::InterpretService do
end
end
shared_examples 'health_status command' do
it 'populates health_status specified by the /health_status command' do
_, updates = service.execute(content, issuable)
expect(updates).to eq(health_status: health_status)
end
end
shared_examples 'clear_health_status command' do
it 'populates health_status: nil if content contains /clear_health_status' do
issuable.update!(health_status: 'on_track')
_, updates = service.execute(content, issuable)
expect(updates).to eq(health_status: nil)
end
end
context 'issuable health statuses licensed' do
let(:issuable) { issue }
before do
stub_licensed_features(issuable_health_status: true)
end
context 'health_status' do
let(:content) { "/health_status #{health_status}" }
it_behaves_like 'health_status command' do
let(:health_status) { 'on_track' }
end
it_behaves_like 'health_status command' do
let(:health_status) { 'at_risk' }
end
context 'when health_status is invalid' do
it 'does not populate health_status' do
content = "/health_status unknown"
_, updates = service.execute(content, issuable)
expect(updates).to be_empty
end
end
context 'when the user does not have enough permissions' do
before do
allow(current_user).to receive(:can?).with(:use_quick_actions).and_return(true)
allow(current_user).to receive(:can?).with(:admin_issue, issuable).and_return(false)
end
it 'returns an error message' do
content = "/health_status on_track"
_, updates, message = service.execute(content, issuable)
expect(updates).to be_empty
expect(message).to eq('Could not apply health_status command.')
end
end
end
context 'clear_health_status' do
it_behaves_like 'clear_health_status command' do
let(:content) { '/clear_health_status' }
end
context 'when the user does not have enough permissions' do
before do
allow(current_user).to receive(:can?).with(:use_quick_actions).and_return(true)
allow(current_user).to receive(:can?).with(:admin_issue, issuable).and_return(false)
end
it 'returns an error message' do
content = "/clear_health_status"
_, updates, message = service.execute(content, issuable)
expect(updates).to be_empty
expect(message).to eq('Could not apply clear_health_status command.')
end
end
end
end
context 'issuable health_status unlicensed' do
before do
stub_licensed_features(issuable_health_status: false)
end
it 'does not recognise /health_status X' do
_, updates = service.execute('/health_status needs_attention', issue)
expect(updates).to be_empty
end
it 'does not recognise /clear_health_status' do
_, updates = service.execute('/clear_health_status', issue)
expect(updates).to be_empty
end
end
context 'issuable health_status not supported by type' do
let_it_be(:incident) { create(:incident, project: project) }
before do
stub_licensed_features(issuable_health_status: true)
end
it 'does not recognise /health_status X' do
_, updates = service.execute('/health_status on_track', incident)
expect(updates).to be_empty
end
it 'does not recognise /clear_health_status' do
_, updates = service.execute('/clear_health_status', incident)
expect(updates).to be_empty
end
end
shared_examples 'empty command' do
it 'populates {} if content contains an unsupported command' do
_, updates = service.execute(content, issuable)
......@@ -1095,6 +1216,21 @@ RSpec.describe QuickActions::InterpretService do
end
describe '#explain' do
describe 'health_status command' do
let(:content) { '/health_status on_track' }
context 'issuable health statuses licensed' do
before do
stub_licensed_features(issuable_health_status: true)
end
it 'includes the value' do
_, explanations = service.explain(content, issue)
expect(explanations).to eq(['Sets health status to on_track.'])
end
end
end
describe 'unassign command' do
let(:content) { '/unassign' }
let(:issue) { create(:issue, project: project, assignees: [user, user2]) }
......
......@@ -39,6 +39,10 @@
category: quickactions
redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_clear_health_status
category: quickactions
redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_clone
category: quickactions
redis_slot: quickactions
......@@ -263,6 +267,10 @@
category: quickactions
redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_health_status
category: quickactions
redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_wip
category: quickactions
redis_slot: quickactions
......
......@@ -7326,6 +7326,9 @@ msgstr ""
msgid "Clear due date"
msgstr ""
msgid "Clear health status"
msgstr ""
msgid "Clear recent searches"
msgstr ""
......@@ -7344,9 +7347,15 @@ msgstr ""
msgid "Clear weight"
msgstr ""
msgid "Cleared health status."
msgstr ""
msgid "Cleared weight."
msgstr ""
msgid "Clears health status."
msgstr ""
msgid "Clears weight."
msgstr ""
......@@ -32275,6 +32284,12 @@ msgstr ""
msgid "Set due date"
msgstr ""
msgid "Set health status"
msgstr ""
msgid "Set health status to %{health_status}."
msgstr ""
msgid "Set iteration"
msgstr ""
......@@ -32431,6 +32446,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
msgid "Sets health status to %{health_status}."
msgstr ""
msgid "Sets target branch to %{branch_name}."
msgstr ""
......
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