diff --git a/doc/user/project/merge_requests/drafts.md b/doc/user/project/merge_requests/drafts.md index 8e193fb84d0072408bc1c7f9820fb0dbcf39395f..13cc68f02dd86da0245f08fec202867cc674e80c 100644 --- a/doc/user/project/merge_requests/drafts.md +++ b/doc/user/project/merge_requests/drafts.md @@ -30,7 +30,7 @@ There are several ways to flag a merge request as a draft: - **Commenting in an existing merge request**: Add the `/draft` [quick action](../quick_actions.md#issues-merge-requests-and-epics) in a comment. This quick action is a toggle, and can be repeated to change the status - again. This quick action discards any other text in the comment. + back to Ready. - **Creating a commit**: Add `draft:`, `Draft:`, `fixup!`, or `Fixup!` to the beginning of a commit message targeting the merge request's source branch. This is not a toggle, and adding this text again in a later commit doesn't mark the @@ -49,10 +49,9 @@ When a merge request is ready to be merged, you can remove the `Draft` flag in s - **Editing an existing merge request**: Remove `[Draft]`, `Draft:` or `(Draft)` from the beginning of the title, or select **Remove the Draft: prefix from the title** below the **Title** field. -- **Commenting in an existing merge request**: Add the `/draft` +- **Commenting in an existing merge request**: Add the `/ready` [quick action](../quick_actions.md#issues-merge-requests-and-epics) - in a comment in the merge request. This quick action is a toggle, and can be repeated - to change the status back. This quick action discards any other text in the comment. + in a comment in the merge request. In [GitLab 13.10 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/15332), when you mark a merge request as ready, notifications are triggered to diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index b73b381ffcddf93d02da875740632c44b43c7723..d5a7058d3d289c1b10f92d3cba94641f3cf786db 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -67,7 +67,7 @@ threads. Some quick actions might not be available to all subscription tiers. | `/copy_metadata <#issue>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Copy labels and milestone from another issue in the project. | | `/create_merge_request <branch name>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Create a new merge request starting from the current issue. | | `/done` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark to do as done. | -| `/draft` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Toggle the draft status. | +| `/draft` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Toggle the [draft status](merge_requests/drafts.md). | | `/due <date>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. | | `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue and mark as a duplicate of another issue. Also, mark both as related. | | `/epic <epic>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. | @@ -85,6 +85,7 @@ threads. Some quick actions might not be available to all subscription tiers. | `/promote_to_incident` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Promote issue to incident ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/296787) in GitLab 14.5). | | `/page <policy name>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Start escalations for the incident ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79977) in GitLab 14.9). | | `/publish` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Publish issue to an associated [Status Page](../../operations/incident_management/status_page.md) ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30906) in GitLab 13.0) | +| `/ready` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Set the [ready status](merge_requests/drafts.md#mark-merge-requests-as-ready) ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90361) in GitLab 15.1). | | `/reassign @user1 @user2` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Replace current assignees with those specified. | | `/reassign_reviewer @user1 @user2` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Replace current reviewers with those specified. | | `/rebase` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Rebase source branch. This schedules a background task that attempts to rebase the changes in the source branch on the latest commit of the target branch. If `/rebase` is used, `/merge` is ignored to avoid a race condition where the source branch is merged or deleted before it is rebased. If there are merge conflicts, GitLab displays a message that a rebase cannot be scheduled. Rebase failures are displayed with the merge request status. | diff --git a/lib/gitlab/quick_actions/merge_request_actions.rb b/lib/gitlab/quick_actions/merge_request_actions.rb index 6137e257837216157278f6f5f5e7586c576d5e37..167e7ad67a908ec2b04ae48fb61ed6813703ae3d 100644 --- a/lib/gitlab/quick_actions/merge_request_actions.rb +++ b/lib/gitlab/quick_actions/merge_request_actions.rb @@ -88,11 +88,11 @@ module MergeRequestActions @execution_message[:rebase] = _('Scheduled a rebase of branch %{branch}.') % { branch: branch } end - desc 'Toggle the Draft status' + desc { _('Toggle the Draft status') } explanation do noun = quick_action_target.to_ability_name.humanize(capitalize: false) if quick_action_target.draft? - _("Unmarks this %{noun} as a draft.") + _("Marks this %{noun} as ready.") else _("Marks this %{noun} as a draft.") end % { noun: noun } @@ -100,7 +100,7 @@ module MergeRequestActions execution_message do noun = quick_action_target.to_ability_name.humanize(capitalize: false) if quick_action_target.draft? - _("Unmarked this %{noun} as a draft.") + _("Marked this %{noun} as ready.") else _("Marked this %{noun} as a draft.") end % { noun: noun } @@ -117,6 +117,35 @@ module MergeRequestActions @updates[:wip_event] = quick_action_target.draft? ? 'ready' : 'draft' end + desc { _('Set the Ready status') } + explanation do + noun = quick_action_target.to_ability_name.humanize(capitalize: false) + if quick_action_target.draft? + _("Marks this %{noun} as ready.") + else + _("No change to this %{noun}'s draft status.") + end % { noun: noun } + end + execution_message do + noun = quick_action_target.to_ability_name.humanize(capitalize: false) + if quick_action_target.draft? + _("Marked this %{noun} as ready.") + else + _("No change to this %{noun}'s draft status.") + end % { noun: noun } + end + + types MergeRequest + condition do + # Allow it to mark as draft on MR creation page or through MR notes + # + quick_action_target.respond_to?(:draft?) && + (quick_action_target.new_record? || current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)) + end + command :ready do + @updates[:wip_event] = 'ready' if quick_action_target.draft? + end + desc { _('Set target branch') } explanation do |branch_name| _('Sets target branch to %{branch_name}.') % { branch_name: branch_name } diff --git a/lib/gitlab/usage_data_counters/known_events/quickactions.yml b/lib/gitlab/usage_data_counters/known_events/quickactions.yml index 4ba7ea2d407a99be79e9d64f626a0c300bdfef77..f980503b4bf75d443ba71f885745c2d9687ffd52 100644 --- a/lib/gitlab/usage_data_counters/known_events/quickactions.yml +++ b/lib/gitlab/usage_data_counters/known_events/quickactions.yml @@ -135,6 +135,10 @@ category: quickactions redis_slot: quickactions aggregation: weekly +- name: i_quickactions_ready + category: quickactions + redis_slot: quickactions + aggregation: weekly - name: i_quickactions_reassign category: quickactions redis_slot: quickactions diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 59a53eadc09db2ac60b0fd9bdf92d29ce4f1ff60..9f19cfd563a24c4eb1886eca8c007529ab8aed37 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -23532,6 +23532,9 @@ msgstr "" msgid "Marked this %{noun} as a draft." msgstr "" +msgid "Marked this %{noun} as ready." +msgstr "" + msgid "Marked this issue as a duplicate of %{duplicate_param}." msgstr "" @@ -23544,6 +23547,9 @@ msgstr "" msgid "Marks this %{noun} as a draft." msgstr "" +msgid "Marks this %{noun} as ready." +msgstr "" + msgid "Marks this issue as a duplicate of %{duplicate_reference}." msgstr "" @@ -25614,6 +25620,9 @@ msgstr "" msgid "No branches found" msgstr "" +msgid "No change to this %{noun}'s draft status." +msgstr "" + msgid "No changes" msgstr "" @@ -35115,6 +35124,9 @@ msgstr "" msgid "Set target branch to %{branch_name}." msgstr "" +msgid "Set the Ready status" +msgstr "" + msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one." msgstr "" @@ -40021,6 +40033,9 @@ msgstr "" msgid "Toggle sidebar" msgstr "" +msgid "Toggle the Draft status" +msgstr "" + msgid "Toggle the Performance Bar" msgstr "" @@ -40732,12 +40747,6 @@ msgstr "" msgid "Unlocks the discussion." msgstr "" -msgid "Unmarked this %{noun} as a draft." -msgstr "" - -msgid "Unmarks this %{noun} as a draft." -msgstr "" - msgid "Unreachable" msgstr "" diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 7737e400d93f7273a3442a51d4b51dd6c130e6db..f7ed60060993a53bbe6c59386e896ba2c2a8db65 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -321,7 +321,7 @@ end shared_examples 'draft command' do - it 'returns wip_event: "draft" if content contains /draft' do + it 'returns wip_event: "draft"' do _, updates, _ = service.execute(content, issuable) expect(updates).to eq(wip_event: 'draft') @@ -334,8 +334,16 @@ end end + shared_examples 'draft/ready command no action' do + it 'returns the no action message if there is no change to the status' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("No change to this #{issuable.to_ability_name.humanize(capitalize: false)}'s draft status.") + end + end + shared_examples 'ready command' do - it 'returns wip_event: "ready" if content contains /draft' do + it 'returns wip_event: "ready"' do issuable.update!(title: issuable.draft_title) _, updates, _ = service.execute(content, issuable) @@ -346,7 +354,7 @@ issuable.update!(title: issuable.draft_title) _, _, message = service.execute(content, issuable) - expect(message).to eq("Unmarked this #{issuable.to_ability_name.humanize(capitalize: false)} as a draft.") + expect(message).to eq("Marked this #{issuable.to_ability_name.humanize(capitalize: false)} as ready.") end end @@ -1372,6 +1380,16 @@ let(:issuable) { merge_request } end + it_behaves_like 'draft/ready command no action' do + let(:content) { '/ready' } + let(:issuable) { merge_request } + end + + it_behaves_like 'ready command' do + let(:content) { '/ready' } + let(:issuable) { merge_request } + end + it_behaves_like 'failed command', 'Could not apply remove_due_date command.' do let(:content) { '/remove_due_date' } let(:issuable) { merge_request } @@ -2687,7 +2705,24 @@ it 'includes the new status' do _, explanations = service.explain(content, merge_request) - expect(explanations).to eq(['Marks this merge request as a draft.']) + expect(explanations).to match_array(['Marks this merge request as a draft.']) + end + end + + describe 'ready command' do + let(:content) { '/ready' } + + it 'includes the new status' do + merge_request.update!(title: merge_request.draft_title) + _, explanations = service.explain(content, merge_request) + + expect(explanations).to match_array(['Marks this merge request as ready.']) + end + + it 'includes the no change message when status unchanged' do + _, explanations = service.explain(content, merge_request) + + expect(explanations).to match_array(["No change to this merge request's draft status."]) end end