From 4779c43ef9c2c3d534effdbacf3af910ed3e3c3e Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 10:05:57 +0200 Subject: Create a feature spec for "/tag" --- .../commits/user_uses_slash_commands_spec.rb | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 spec/features/commits/user_uses_slash_commands_spec.rb diff --git a/spec/features/commits/user_uses_slash_commands_spec.rb b/spec/features/commits/user_uses_slash_commands_spec.rb new file mode 100644 index 00000000000..f356155be61 --- /dev/null +++ b/spec/features/commits/user_uses_slash_commands_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +describe 'Commit > User uses quick actions', :js do + include Spec::Support::Helpers::Features::NotesHelpers + include RepoHelpers + + let(:project) { create(:project, :public, :repository) } + let(:user) { project.creator } + let(:commit) { project.commit } + + before do + project.add_maintainer(user) + sign_in(user) + + visit project_commit_path(project, commit.id) + end + + describe 'Tagging a commit' do + let(:tag_name) { 'v1.2.3' } + let(:tag_message) { 'Stable release' } + let(:truncated_commit_sha) { Commit.truncate_sha(commit.sha) } + + it 'tags this commit' do + add_note("/tag #{tag_name} #{tag_message}") + + expect(page).to have_content 'Commands applied' + expect(page).to have_content "tagged commit #{truncated_commit_sha}" + expect(page).to have_content tag_name + + visit project_tag_path(project, tag_name) + expect(page).to have_content tag_name + expect(page).to have_content tag_message + expect(page).to have_content truncated_commit_sha + end + end +end -- cgit v1.2.1 From d23fbbc6928983582198092cf28a0cd46d30252f Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 10:11:07 +0200 Subject: Build noteables in AutocompleteSourcesController#target --- app/controllers/projects/autocomplete_sources_controller.rb | 4 ++-- app/services/projects/autocomplete_service.rb | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb index 07627ffb69f..eaaac5ca940 100644 --- a/app/controllers/projects/autocomplete_sources_controller.rb +++ b/app/controllers/projects/autocomplete_sources_controller.rb @@ -34,9 +34,9 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController def target case params[:type]&.downcase when 'issue' - IssuesFinder.new(current_user, project_id: @project.id).find_by(iid: params[:type_id]) + IssuesFinder.new(current_user, project_id: @project.id).find_by(iid: params[:type_id]) || @project.issues.build when 'mergerequest' - MergeRequestsFinder.new(current_user, project_id: @project.id).find_by(iid: params[:type_id]) + MergeRequestsFinder.new(current_user, project_id: @project.id).find_by(iid: params[:type_id]) || @project.merge_requests.build when 'commit' @project.commit(params[:type_id]) end diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb index 10eb2cea4a2..5286b92ab6b 100644 --- a/app/services/projects/autocomplete_service.rb +++ b/app/services/projects/autocomplete_service.rb @@ -47,15 +47,7 @@ module Projects end def commands(noteable, type) - noteable ||= - case type - when 'Issue' - @project.issues.build - when 'MergeRequest' - @project.merge_requests.build - end - - return [] unless noteable&.is_a?(Issuable) + return [] unless noteable QuickActions::InterpretService.new(project, current_user).available_commands(noteable) end -- cgit v1.2.1 From 2022243a222583daaf9e00d44fa6d1a9d75d4b02 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 10:52:07 +0200 Subject: Create empty Commits::UpdateService and wire it up --- app/models/commit.rb | 4 ++++ app/policies/commit_policy.rb | 3 +++ app/services/commits/update_service.rb | 9 +++++++++ app/services/notes/quick_actions_service.rb | 3 ++- app/services/quick_actions/interpret_service.rb | 24 ++++++++++++++++-------- 5 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 app/policies/commit_policy.rb create mode 100644 app/services/commits/update_service.rb diff --git a/app/models/commit.rb b/app/models/commit.rb index 8b9f4490ffa..27fbdc3e386 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -448,6 +448,10 @@ class Commit true end + def to_ability_name + model_name.singular + end + def touch # no-op but needs to be defined since #persisted? is defined end diff --git a/app/policies/commit_policy.rb b/app/policies/commit_policy.rb new file mode 100644 index 00000000000..44063181241 --- /dev/null +++ b/app/policies/commit_policy.rb @@ -0,0 +1,3 @@ +class CommitPolicy < BasePolicy + delegate { @subject.project } +end diff --git a/app/services/commits/update_service.rb b/app/services/commits/update_service.rb new file mode 100644 index 00000000000..9cd5ddc7f91 --- /dev/null +++ b/app/services/commits/update_service.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Commits + class UpdateService < BaseService + def execute(commit) + # TODO authorize user + end + end +end diff --git a/app/services/notes/quick_actions_service.rb b/app/services/notes/quick_actions_service.rb index 7280449bb1c..d183f280d77 100644 --- a/app/services/notes/quick_actions_service.rb +++ b/app/services/notes/quick_actions_service.rb @@ -4,7 +4,8 @@ module Notes class QuickActionsService < BaseService UPDATE_SERVICES = { 'Issue' => Issues::UpdateService, - 'MergeRequest' => MergeRequests::UpdateService + 'MergeRequest' => MergeRequests::UpdateService, + 'Commit' => Commits::UpdateService }.freeze def self.noteable_update_service(note) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index cdc8514c47c..36a35b6afb7 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -60,7 +60,8 @@ module QuickActions "Closes this #{issuable.to_ability_name.humanize(capitalize: false)}." end condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && issuable.open? && current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end @@ -75,7 +76,8 @@ module QuickActions "Reopens this #{issuable.to_ability_name.humanize(capitalize: false)}." end condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && issuable.closed? && current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end @@ -149,7 +151,8 @@ module QuickActions issuable.allows_multiple_assignees? ? '@user1 @user2' : '' end condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && issuable.assignees.any? && current_user.can?(:"admin_#{issuable.to_ability_name}", project) end @@ -188,7 +191,8 @@ module QuickActions "Removes #{issuable.milestone.to_reference(format: :name)} milestone." end condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && issuable.milestone_id? && current_user.can?(:"admin_#{issuable.to_ability_name}", project) end @@ -231,7 +235,8 @@ module QuickActions end params '~label1 ~"label 2"' condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && issuable.labels.any? && current_user.can?(:"admin_#{issuable.to_ability_name}", project) end @@ -257,7 +262,8 @@ module QuickActions end params '~label1 ~"label 2"' condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && issuable.labels.any? && current_user.can?(:"admin_#{issuable.to_ability_name}", project) end @@ -317,7 +323,8 @@ module QuickActions "Subscribes to this #{issuable.to_ability_name.humanize(capitalize: false)}." end condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && !issuable.subscribed?(current_user, project) end command :subscribe do @@ -329,7 +336,8 @@ module QuickActions "Unsubscribes from this #{issuable.to_ability_name.humanize(capitalize: false)}." end condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && issuable.subscribed?(current_user, project) end command :unsubscribe do -- cgit v1.2.1 From cc1aecdb4f3b3950f50ae53ae842f6b8912f401c Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 12:23:53 +0200 Subject: Implement the `tag` commands --- app/services/quick_actions/interpret_service.rb | 17 ++++++++ .../quick_actions/interpret_service_spec.rb | 45 ++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 36a35b6afb7..6345f78af90 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -582,6 +582,23 @@ module QuickActions @updates[:confidential] = true end + desc 'Tag this commit.' + explanation do |(tag_name), _| + "Tags this commit to #{tag_name}." + end + params 'v1.2.3 ' + parse_params do |tag_name_and_message| + tag_name_and_message.split(' ', 2) + end + condition do + issuable.is_a?(Commit) + # TODO authorize + end + command :tag do |(tag_name, message)| + @updates[:tag_name] = tag_name + @updates[:tag_message] = message + end + def extract_users(params) return [] if params.nil? diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 743e281183e..e83648d5111 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -6,6 +6,7 @@ describe QuickActions::InterpretService do let(:developer2) { create(:user) } let(:issue) { create(:issue, project: project) } let(:milestone) { create(:milestone, project: project, title: '9.10') } + let(:commit) { create(:commit, project: project) } let(:inprogress) { create(:label, project: project, title: 'In Progress') } let(:bug) { create(:label, project: project, title: 'Bug') } let(:note) { build(:note, commit_id: merge_request.diff_head_sha) } @@ -347,6 +348,14 @@ describe QuickActions::InterpretService do end end + shared_examples 'tag command' do + it 'tags a commit' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(tag_name: tag_name, tag_message: tag_message) + end + end + it_behaves_like 'reopen command' do let(:content) { '/reopen' } let(:issuable) { issue } @@ -1102,6 +1111,32 @@ describe QuickActions::InterpretService do it_behaves_like 'empty command' end end + + context '/tag command' do + let(:issuable) { commit } + + context 'ignores command with no argument' do + it_behaves_like 'empty command' do + let(:content) { '/tag' } + end + end + + context 'tags a commit with a tag name' do + it_behaves_like 'tag command' do + let(:tag_name) { 'v1.2.3' } + let(:tag_message) { nil } + let(:content) { "/tag #{tag_name}" } + end + end + + context 'tags a commit with a tag name and message' do + it_behaves_like 'tag command' do + let(:tag_name) { 'v1.2.3' } + let(:tag_message) { 'Stable release' } + let(:content) { "/tag #{tag_name} #{tag_message}" } + end + end + end end describe '#explain' do @@ -1319,5 +1354,15 @@ describe QuickActions::InterpretService do expect(explanations).to eq(["Moves this issue to test/project."]) end end + + describe 'tag a commit' do + let(:content) { '/tag 1.2.3 some message' } + + it 'includes the tag name' do + _, explanations = service.explain(content, commit) + + expect(explanations).to eq(["Tags this commit to 1.2.3."]) + end + end end end -- cgit v1.2.1 From a892b2354c953d62445a5cf9ac747ee166256c66 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 12:24:07 +0200 Subject: Tag a commit via `/tag 1.2.3 message` --- app/services/commits/update_service.rb | 21 ++++++++++++- spec/services/commits/update_service_spec.rb | 47 ++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 spec/services/commits/update_service_spec.rb diff --git a/app/services/commits/update_service.rb b/app/services/commits/update_service.rb index 9cd5ddc7f91..7ec678ff1cf 100644 --- a/app/services/commits/update_service.rb +++ b/app/services/commits/update_service.rb @@ -3,7 +3,26 @@ module Commits class UpdateService < BaseService def execute(commit) - # TODO authorize user + tag_commit(commit) + end + + private + + def tag_commit(commit) + # TODO authorize + return unless params[:tag_name] + + tag_name = params[:tag_name] + message = params[:tag_message] + release_description = nil + + result = Tags::CreateService + .new(commit.project, current_user) + .execute(tag_name, commit.sha, message, release_description) + + if result[:status] + commit + end end end end diff --git a/spec/services/commits/update_service_spec.rb b/spec/services/commits/update_service_spec.rb new file mode 100644 index 00000000000..cfca3a85236 --- /dev/null +++ b/spec/services/commits/update_service_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Commits::UpdateService do + let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + + let(:commit) { create(:commit, project: project) } + + before do + project.add_maintainer(user) + end + + describe 'execute' do + let(:service) { described_class.new(project, user, opts) } + + context 'valid params' do + let(:opts) do + { + tag_name: '1.2.3', + tag_message: 'Release' + } + end + + it 'tags a commit' do + tag_stub = instance_double(Tags::CreateService) + allow(Tags::CreateService).to receive(:new).and_return(tag_stub) + allow(tag_stub).to receive(:execute) + .with(opts[:tag_name], commit.sha, opts[:tag_message], nil) + .and_return({ status: :success }) + + service.execute(commit) + end + end + + context 'invalid params' do + let(:opts) do + {} + end + + it 'does not call the tag create service' do + expect(Tags::CreateService).not_to receive(:new) + + service.execute(commit) + end + end + end +end -- cgit v1.2.1 From f89a91d8da6b00e44b28c52ae57bf2c7761bbe35 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 13:22:03 +0200 Subject: Quick actions are now also supported on commits --- spec/views/shared/notes/_form.html.haml_spec.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/spec/views/shared/notes/_form.html.haml_spec.rb b/spec/views/shared/notes/_form.html.haml_spec.rb index c57319869f3..0189f926a5f 100644 --- a/spec/views/shared/notes/_form.html.haml_spec.rb +++ b/spec/views/shared/notes/_form.html.haml_spec.rb @@ -16,7 +16,7 @@ describe 'shared/notes/_form' do render end - %w[issue merge_request].each do |noteable| + %w[issue merge_request commit].each do |noteable| context "with a note on #{noteable}" do let(:note) { build(:"note_on_#{noteable}", project: project) } @@ -25,12 +25,4 @@ describe 'shared/notes/_form' do end end end - - context 'with a note on a commit' do - let(:note) { build(:note_on_commit, project: project) } - - it 'says that only markdown is supported, not quick actions' do - expect(rendered).to have_content('Markdown is supported') - end - end end -- cgit v1.2.1 From d6eaf38be4fa1785b6e47eeb76f4ca2cb20a144d Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 13:37:01 +0200 Subject: Commit notes now support quick actions --- spec/services/notes/quick_actions_service_spec.rb | 46 ++--------------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb index 784dac55454..b3ee0cadcb7 100644 --- a/spec/services/notes/quick_actions_service_spec.rb +++ b/spec/services/notes/quick_actions_service_spec.rb @@ -11,40 +11,6 @@ describe Notes::QuickActionsService do end end - shared_examples 'note on noteable that does not support quick actions' do - include_context 'note on noteable' - - before do - note.note = note_text - end - - describe 'note with only command' do - describe '/close, /label, /assign & /milestone' do - let(:note_text) { %(/close\n/assign @#{assignee.username}") } - - it 'saves the note and does not alter the note text' do - content, command_params = service.extract_commands(note) - - expect(content).to eq note_text - expect(command_params).to be_empty - end - end - end - - describe 'note with command & text' do - describe '/close, /label, /assign & /milestone' do - let(:note_text) { %(HELLO\n/close\n/assign @#{assignee.username}\nWORLD) } - - it 'saves the note and does not alter the note text' do - content, command_params = service.extract_commands(note) - - expect(content).to eq note_text - expect(command_params).to be_empty - end - end - end - end - shared_examples 'note on noteable that supports quick actions' do include_context 'note on noteable' @@ -147,16 +113,16 @@ describe Notes::QuickActionsService do expect(described_class.noteable_update_service(note)).to eq(Issues::UpdateService) end - it 'returns Issues::UpdateService for a note on a merge request' do + it 'returns MergeRequests::UpdateService for a note on a merge request' do note = create(:note_on_merge_request, project: project) expect(described_class.noteable_update_service(note)).to eq(MergeRequests::UpdateService) end - it 'returns nil for a note on a commit' do + it 'returns Commits::UpdateService for a note on a commit' do note = create(:note_on_commit, project: project) - expect(described_class.noteable_update_service(note)).to be_nil + expect(described_class.noteable_update_service(note)).to eq(Commits::UpdateService) end end @@ -175,7 +141,7 @@ describe Notes::QuickActionsService do let(:note) { create(:note_on_commit, project: project) } it 'returns false' do - expect(described_class.supported?(note)).to be_falsy + expect(described_class.supported?(note)).to be_truthy end end end @@ -203,10 +169,6 @@ describe Notes::QuickActionsService do it_behaves_like 'note on noteable that supports quick actions' do let(:note) { build(:note_on_merge_request, project: project) } end - - it_behaves_like 'note on noteable that does not support quick actions' do - let(:note) { build(:note_on_commit, project: project) } - end end context 'CE restriction for issue assignees' do -- cgit v1.2.1 From 7a4b288ec96e64bd9eaf1296d319a39401901df4 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 21 Jul 2018 14:57:52 +0200 Subject: Create a system note after tagging a commit --- app/models/system_note_metadata.rb | 2 +- app/services/commits/update_service.rb | 3 ++- app/services/system_note_service.rb | 14 ++++++++++++++ spec/services/commits/update_service_spec.rb | 18 +++++++++++++++++- spec/services/system_note_service_spec.rb | 17 +++++++++++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb index c5c77bc8333..376ef673ca8 100644 --- a/app/models/system_note_metadata.rb +++ b/app/models/system_note_metadata.rb @@ -15,7 +15,7 @@ class SystemNoteMetadata < ActiveRecord::Base commit description merge confidential visible label assignee cross_reference title time_tracking branch milestone discussion task moved opened closed merged duplicate locked unlocked - outdated + outdated tag ].freeze validates :note, presence: true diff --git a/app/services/commits/update_service.rb b/app/services/commits/update_service.rb index 7ec678ff1cf..45c971d153a 100644 --- a/app/services/commits/update_service.rb +++ b/app/services/commits/update_service.rb @@ -20,7 +20,8 @@ module Commits .new(commit.project, current_user) .execute(tag_name, commit.sha, message, release_description) - if result[:status] + if result[:status] == :success && (tag = result[:tag]) + SystemNoteService.tag_commit(commit, commit.project, current_user, tag.name) commit end end diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 77494295f14..452b80b1bfa 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -32,6 +32,20 @@ module SystemNoteService create_note(NoteSummary.new(noteable, project, author, body, action: 'commit', commit_count: total_count)) end + # Called when a commit was tagged + # + # noteable - Noteable object + # project - Project owning noteable + # author - User performing the tag + # tag_name - The created tag name + # + # Returns the created Note object + def tag_commit(noteable, project, author, tag_name) + body = "tagged commit #{noteable.sha} to `#{tag_name}`" + + create_note(NoteSummary.new(noteable, project, author, body, action: 'tag')) + end + # Called when the assignee of a Noteable is changed or removed # # noteable - Noteable object diff --git a/spec/services/commits/update_service_spec.rb b/spec/services/commits/update_service_spec.rb index cfca3a85236..05d1e4ec254 100644 --- a/spec/services/commits/update_service_spec.rb +++ b/spec/services/commits/update_service_spec.rb @@ -22,11 +22,26 @@ describe Commits::UpdateService do end it 'tags a commit' do + tag_double = double(name: opts[:tag_name]) tag_stub = instance_double(Tags::CreateService) allow(Tags::CreateService).to receive(:new).and_return(tag_stub) allow(tag_stub).to receive(:execute) .with(opts[:tag_name], commit.sha, opts[:tag_message], nil) - .and_return({ status: :success }) + .and_return({ status: :success, tag: tag_double }) + + expect(SystemNoteService).to receive(:tag_commit).with(commit, project, user, opts[:tag_name]) + + service.execute(commit) + end + + it 'fails to tag the commit' do + tag_stub = instance_double(Tags::CreateService) + allow(Tags::CreateService).to receive(:new).and_return(tag_stub) + allow(tag_stub).to receive(:execute) + .with(opts[:tag_name], commit.sha, opts[:tag_message], nil) + .and_return({ status: :error }) + + expect(SystemNoteService).not_to receive(:tag_commit) service.execute(commit) end @@ -39,6 +54,7 @@ describe Commits::UpdateService do it 'does not call the tag create service' do expect(Tags::CreateService).not_to receive(:new) + expect(SystemNoteService).not_to receive(:tag_commit) service.execute(commit) end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 57d081cffb3..cbe5668cf08 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -108,6 +108,23 @@ describe SystemNoteService do end end + describe '.tag_commit' do + let(:noteable) do + project.commit + end + let(:tag_name) { '1.2.3' } + + subject { described_class.tag_commit(noteable, project, author, tag_name) } + + it_behaves_like 'a system note' do + let(:action) { 'tag' } + end + + it 'sets the note text' do + expect(subject.note).to eq "tagged commit #{noteable.sha} to `#{tag_name}`" + end + end + describe '.change_assignee' do subject { described_class.change_assignee(noteable, project, author, assignee) } -- cgit v1.2.1 From ac6b1ad09712f9f9cdcb5a6479767d69ad689aa4 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 19:58:30 +0200 Subject: Add changelog [ci skip] --- changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml diff --git a/changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml b/changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml new file mode 100644 index 00000000000..6d664511e6e --- /dev/null +++ b/changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml @@ -0,0 +1,5 @@ +--- +title: "`/tag` quick action on Commit comments" +merge_request: 20694 +author: Peter Leitzen +type: added -- cgit v1.2.1 From 591fc8f57f6c9242d291ffc059124d7a0f2d21b8 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 20:08:54 +0200 Subject: Document `/tag` in quick actions user doc --- doc/user/project/quick_actions.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index 0ef8eddad20..8fdfd2a6f4d 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -1,7 +1,7 @@ # GitLab quick actions -Quick actions are textual shortcuts for common actions on issues or merge -requests that are usually done by clicking buttons or dropdowns in GitLab's UI. +Quick actions are textual shortcuts for common actions on issues, merge requests +or commits that are usually done by clicking buttons or dropdowns in GitLab's UI. You can enter these commands while creating a new issue or merge request, and in comments. Each command should be on a separate line in order to be properly detected and executed. The commands are removed from the issue, merge request or @@ -39,7 +39,8 @@ do. | `/board_move ~column` | Move issue to column on the board | | `/duplicate #issue` | Closes this issue and marks it as a duplicate of another issue | | `/move path/to/project` | Moves issue to another project | +| `/tag v1.2.3 ` | Tags a commit with a given tag name and optional message | | `/tableflip` | Append the comment with `(╯°□°)╯︵ ┻━┻` | | `/shrug` | Append the comment with `¯\_(ツ)_/¯` | | /copy_metadata #issue | !merge_request | Copy labels and milestone from other issue or merge request | -| `/confidential` | Makes the issue confidential | \ No newline at end of file +| `/confidential` | Makes the issue confidential | -- cgit v1.2.1 From d331377af5e2a8aae9db365b8a4892ad027dcfa7 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 20:27:44 +0200 Subject: Show optional tag message in quick action explanation --- app/services/quick_actions/interpret_service.rb | 5 ++-- .../quick_actions/interpret_service_spec.rb | 32 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 6345f78af90..f8dccfa465d 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -583,8 +583,9 @@ module QuickActions end desc 'Tag this commit.' - explanation do |(tag_name), _| - "Tags this commit to #{tag_name}." + explanation do |(tag_name, message)| + with_message = %{ with "#{message}"} if message.present? + "Tags this commit to #{tag_name}#{with_message}." end params 'v1.2.3 ' parse_params do |tag_name_and_message| diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index e83648d5111..be209c41c0f 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -1356,12 +1356,36 @@ describe QuickActions::InterpretService do end describe 'tag a commit' do - let(:content) { '/tag 1.2.3 some message' } + describe 'with a tag name' do + context 'without a message' do + let(:content) { '/tag v1.2.3' } - it 'includes the tag name' do - _, explanations = service.explain(content, commit) + it 'includes the tag name only' do + _, explanations = service.explain(content, commit) - expect(explanations).to eq(["Tags this commit to 1.2.3."]) + expect(explanations).to eq(["Tags this commit to v1.2.3."]) + end + end + + context 'with an empty message' do + let(:content) { '/tag v1.2.3 ' } + + it 'includes the tag name only' do + _, explanations = service.explain(content, commit) + + expect(explanations).to eq(["Tags this commit to v1.2.3."]) + end + end + end + + describe 'with a tag name and message' do + let(:content) { '/tag v1.2.3 Stable release' } + + it 'includes the tag name and message' do + _, explanations = service.explain(content, commit) + + expect(explanations).to eq(["Tags this commit to v1.2.3 with \"Stable release\"."]) + end end end end -- cgit v1.2.1 From 18611f0eebe0bb3646c7f32bd333b92c184771eb Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 21:05:38 +0200 Subject: Refactor spec for Commits::UpdateService --- spec/services/commits/update_service_spec.rb | 78 ++++++++++++++++++---------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/spec/services/commits/update_service_spec.rb b/spec/services/commits/update_service_spec.rb index 05d1e4ec254..b4f260096ad 100644 --- a/spec/services/commits/update_service_spec.rb +++ b/spec/services/commits/update_service_spec.rb @@ -4,46 +4,75 @@ describe Commits::UpdateService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } - let(:commit) { create(:commit, project: project) } + let(:commit) { project.commit } before do project.add_maintainer(user) end - describe 'execute' do + describe '#execute' do let(:service) { described_class.new(project, user, opts) } + shared_examples 'tagging fails' do + it 'returns nil' do + tagged_commit = service.execute(commit) + + expect(tagged_commit).to be_nil + end + + it 'does not add a system note' do + service.execute(commit) + + description_notes = find_notes('tag') + expect(description_notes).to be_empty + end + end + + def find_notes(action) + commit + .notes + .joins(:system_note_metadata) + .where(system_note_metadata: { action: action }) + end + context 'valid params' do let(:opts) do { - tag_name: '1.2.3', + tag_name: 'v1.2.3', tag_message: 'Release' } end - it 'tags a commit' do - tag_double = double(name: opts[:tag_name]) - tag_stub = instance_double(Tags::CreateService) - allow(Tags::CreateService).to receive(:new).and_return(tag_stub) - allow(tag_stub).to receive(:execute) - .with(opts[:tag_name], commit.sha, opts[:tag_message], nil) - .and_return({ status: :success, tag: tag_double }) + def find_notes(action) + commit + .notes + .joins(:system_note_metadata) + .where(system_note_metadata: { action: action }) + end - expect(SystemNoteService).to receive(:tag_commit).with(commit, project, user, opts[:tag_name]) + context 'when tagging succeeds' do + it 'returns the commit' do + tagged_commit = service.execute(commit) - service.execute(commit) - end + expect(tagged_commit).to eq(commit) + end - it 'fails to tag the commit' do - tag_stub = instance_double(Tags::CreateService) - allow(Tags::CreateService).to receive(:new).and_return(tag_stub) - allow(tag_stub).to receive(:execute) - .with(opts[:tag_name], commit.sha, opts[:tag_message], nil) - .and_return({ status: :error }) + it 'adds a system note' do + service.execute(commit) - expect(SystemNoteService).not_to receive(:tag_commit) + description_notes = find_notes('tag') + expect(description_notes.length).to eq(1) + end + end - service.execute(commit) + context 'when tagging fails' do + before do + tag_stub = instance_double(Tags::CreateService) + allow(Tags::CreateService).to receive(:new).and_return(tag_stub) + allow(tag_stub).to receive(:execute).and_return({ status: :error }) + end + + include_examples 'tagging fails' end end @@ -52,12 +81,7 @@ describe Commits::UpdateService do {} end - it 'does not call the tag create service' do - expect(Tags::CreateService).not_to receive(:new) - expect(SystemNoteService).not_to receive(:tag_commit) - - service.execute(commit) - end + include_examples 'tagging fails' end end end -- cgit v1.2.1 From 7405a7ae5fd9155ef90cc62988214135503eb99b Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 22:01:23 +0200 Subject: Rename Commits::UpdateService to Commits::TagService --- app/services/commits/tag_service.rb | 23 ++++++ app/services/commits/update_service.rb | 29 -------- app/services/notes/quick_actions_service.rb | 2 +- spec/services/commits/tag_service_spec.rb | 87 +++++++++++++++++++++++ spec/services/commits/update_service_spec.rb | 87 ----------------------- spec/services/notes/quick_actions_service_spec.rb | 4 +- 6 files changed, 113 insertions(+), 119 deletions(-) create mode 100644 app/services/commits/tag_service.rb delete mode 100644 app/services/commits/update_service.rb create mode 100644 spec/services/commits/tag_service_spec.rb delete mode 100644 spec/services/commits/update_service_spec.rb diff --git a/app/services/commits/tag_service.rb b/app/services/commits/tag_service.rb new file mode 100644 index 00000000000..0d361a3b77b --- /dev/null +++ b/app/services/commits/tag_service.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Commits + class TagService < BaseService + def execute(commit) + # TODO authorize + return unless params[:tag_name] + + tag_name = params[:tag_name] + message = params[:tag_message] + release_description = nil + + result = Tags::CreateService + .new(commit.project, current_user) + .execute(tag_name, commit.sha, message, release_description) + + if result[:status] == :success && (tag = result[:tag]) + SystemNoteService.tag_commit(commit, commit.project, current_user, tag.name) + commit + end + end + end +end diff --git a/app/services/commits/update_service.rb b/app/services/commits/update_service.rb deleted file mode 100644 index 45c971d153a..00000000000 --- a/app/services/commits/update_service.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module Commits - class UpdateService < BaseService - def execute(commit) - tag_commit(commit) - end - - private - - def tag_commit(commit) - # TODO authorize - return unless params[:tag_name] - - tag_name = params[:tag_name] - message = params[:tag_message] - release_description = nil - - result = Tags::CreateService - .new(commit.project, current_user) - .execute(tag_name, commit.sha, message, release_description) - - if result[:status] == :success && (tag = result[:tag]) - SystemNoteService.tag_commit(commit, commit.project, current_user, tag.name) - commit - end - end - end -end diff --git a/app/services/notes/quick_actions_service.rb b/app/services/notes/quick_actions_service.rb index d183f280d77..4c14d834949 100644 --- a/app/services/notes/quick_actions_service.rb +++ b/app/services/notes/quick_actions_service.rb @@ -5,7 +5,7 @@ module Notes UPDATE_SERVICES = { 'Issue' => Issues::UpdateService, 'MergeRequest' => MergeRequests::UpdateService, - 'Commit' => Commits::UpdateService + 'Commit' => Commits::TagService }.freeze def self.noteable_update_service(note) diff --git a/spec/services/commits/tag_service_spec.rb b/spec/services/commits/tag_service_spec.rb new file mode 100644 index 00000000000..5e778681544 --- /dev/null +++ b/spec/services/commits/tag_service_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe Commits::TagService do + let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + + let(:commit) { project.commit } + + before do + project.add_maintainer(user) + end + + describe '#execute' do + let(:service) { described_class.new(project, user, opts) } + + shared_examples 'tagging fails' do + it 'returns nil' do + tagged_commit = service.execute(commit) + + expect(tagged_commit).to be_nil + end + + it 'does not add a system note' do + service.execute(commit) + + description_notes = find_notes('tag') + expect(description_notes).to be_empty + end + end + + def find_notes(action) + commit + .notes + .joins(:system_note_metadata) + .where(system_note_metadata: { action: action }) + end + + context 'valid params' do + let(:opts) do + { + tag_name: 'v1.2.3', + tag_message: 'Release' + } + end + + def find_notes(action) + commit + .notes + .joins(:system_note_metadata) + .where(system_note_metadata: { action: action }) + end + + context 'when tagging succeeds' do + it 'returns the commit' do + tagged_commit = service.execute(commit) + + expect(tagged_commit).to eq(commit) + end + + it 'adds a system note' do + service.execute(commit) + + description_notes = find_notes('tag') + expect(description_notes.length).to eq(1) + end + end + + context 'when tagging fails' do + before do + tag_stub = instance_double(Tags::CreateService) + allow(Tags::CreateService).to receive(:new).and_return(tag_stub) + allow(tag_stub).to receive(:execute).and_return({ status: :error }) + end + + include_examples 'tagging fails' + end + end + + context 'invalid params' do + let(:opts) do + {} + end + + include_examples 'tagging fails' + end + end +end diff --git a/spec/services/commits/update_service_spec.rb b/spec/services/commits/update_service_spec.rb deleted file mode 100644 index b4f260096ad..00000000000 --- a/spec/services/commits/update_service_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'spec_helper' - -describe Commits::UpdateService do - let(:project) { create(:project, :repository) } - let(:user) { create(:user) } - - let(:commit) { project.commit } - - before do - project.add_maintainer(user) - end - - describe '#execute' do - let(:service) { described_class.new(project, user, opts) } - - shared_examples 'tagging fails' do - it 'returns nil' do - tagged_commit = service.execute(commit) - - expect(tagged_commit).to be_nil - end - - it 'does not add a system note' do - service.execute(commit) - - description_notes = find_notes('tag') - expect(description_notes).to be_empty - end - end - - def find_notes(action) - commit - .notes - .joins(:system_note_metadata) - .where(system_note_metadata: { action: action }) - end - - context 'valid params' do - let(:opts) do - { - tag_name: 'v1.2.3', - tag_message: 'Release' - } - end - - def find_notes(action) - commit - .notes - .joins(:system_note_metadata) - .where(system_note_metadata: { action: action }) - end - - context 'when tagging succeeds' do - it 'returns the commit' do - tagged_commit = service.execute(commit) - - expect(tagged_commit).to eq(commit) - end - - it 'adds a system note' do - service.execute(commit) - - description_notes = find_notes('tag') - expect(description_notes.length).to eq(1) - end - end - - context 'when tagging fails' do - before do - tag_stub = instance_double(Tags::CreateService) - allow(Tags::CreateService).to receive(:new).and_return(tag_stub) - allow(tag_stub).to receive(:execute).and_return({ status: :error }) - end - - include_examples 'tagging fails' - end - end - - context 'invalid params' do - let(:opts) do - {} - end - - include_examples 'tagging fails' - end - end -end diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb index b3ee0cadcb7..a8c994c101c 100644 --- a/spec/services/notes/quick_actions_service_spec.rb +++ b/spec/services/notes/quick_actions_service_spec.rb @@ -119,10 +119,10 @@ describe Notes::QuickActionsService do expect(described_class.noteable_update_service(note)).to eq(MergeRequests::UpdateService) end - it 'returns Commits::UpdateService for a note on a commit' do + it 'returns Commits::TagService for a note on a commit' do note = create(:note_on_commit, project: project) - expect(described_class.noteable_update_service(note)).to eq(Commits::UpdateService) + expect(described_class.noteable_update_service(note)).to eq(Commits::TagService) end end -- cgit v1.2.1 From 394107f5f6a5bc5d5df80ce1120ff3d3b8b5693e Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 22:16:00 +0200 Subject: Link to the tag in system note --- app/services/system_note_service.rb | 3 ++- spec/services/system_note_service_spec.rb | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 452b80b1bfa..dda89830179 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -41,7 +41,8 @@ module SystemNoteService # # Returns the created Note object def tag_commit(noteable, project, author, tag_name) - body = "tagged commit #{noteable.sha} to `#{tag_name}`" + link = url_helpers.project_tag_url(project, id: tag_name) + body = "tagged commit #{noteable.sha} to [`#{tag_name}`](#{link})" create_note(NoteSummary.new(noteable, project, author, body, action: 'tag')) end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index cbe5668cf08..442de61f69b 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -112,7 +112,7 @@ describe SystemNoteService do let(:noteable) do project.commit end - let(:tag_name) { '1.2.3' } + let(:tag_name) { 'v1.2.3' } subject { described_class.tag_commit(noteable, project, author, tag_name) } @@ -121,7 +121,9 @@ describe SystemNoteService do end it 'sets the note text' do - expect(subject.note).to eq "tagged commit #{noteable.sha} to `#{tag_name}`" + link = "http://localhost/#{project.full_path}/tags/#{tag_name}" + + expect(subject.note).to eq "tagged commit #{noteable.sha} to [`#{tag_name}`](#{link})" end end -- cgit v1.2.1 From 839b776f87d5eb3606720fd5552f3488d91c51f2 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 22:21:49 +0200 Subject: Remove "TODO authorize" Authorisation is done in to Tags::CreateService --- app/services/commits/tag_service.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/services/commits/tag_service.rb b/app/services/commits/tag_service.rb index 0d361a3b77b..fb841655fee 100644 --- a/app/services/commits/tag_service.rb +++ b/app/services/commits/tag_service.rb @@ -3,7 +3,6 @@ module Commits class TagService < BaseService def execute(commit) - # TODO authorize return unless params[:tag_name] tag_name = params[:tag_name] -- cgit v1.2.1 From c491d86473c55a58811e22ab73e02a22ba216e84 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 23 Jul 2018 22:37:23 +0200 Subject: Hide `/tag` quick action from non-authorised users --- app/services/quick_actions/interpret_service.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index f8dccfa465d..09f39523c35 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -592,8 +592,7 @@ module QuickActions tag_name_and_message.split(' ', 2) end condition do - issuable.is_a?(Commit) - # TODO authorize + issuable.is_a?(Commit) && current_user.can?(:push_code, project) end command :tag do |(tag_name, message)| @updates[:tag_name] = tag_name -- cgit v1.2.1 From 19f97d2a0fe16b905f95dc17480fdbbfba4654d7 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 28 Jul 2018 23:04:26 +0200 Subject: No need to destruct block arguments --- app/services/quick_actions/interpret_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 09f39523c35..d84da989924 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -583,7 +583,7 @@ module QuickActions end desc 'Tag this commit.' - explanation do |(tag_name, message)| + explanation do |tag_name, message| with_message = %{ with "#{message}"} if message.present? "Tags this commit to #{tag_name}#{with_message}." end @@ -594,7 +594,7 @@ module QuickActions condition do issuable.is_a?(Commit) && current_user.can?(:push_code, project) end - command :tag do |(tag_name, message)| + command :tag do |tag_name, message| @updates[:tag_name] = tag_name @updates[:tag_message] = message end -- cgit v1.2.1 From 9b95fe78ae39aa2c0f9c3dc49b897097fc3fef5e Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 28 Jul 2018 23:42:06 +0200 Subject: Move finding autocompletion targets into AutocompleteService --- app/controllers/projects/autocomplete_sources_controller.rb | 11 ++--------- app/services/projects/autocomplete_service.rb | 11 +++++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb index eaaac5ca940..6e3edb31b99 100644 --- a/app/controllers/projects/autocomplete_sources_controller.rb +++ b/app/controllers/projects/autocomplete_sources_controller.rb @@ -1,5 +1,5 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController - before_action :load_autocomplete_service, except: [:members] + before_action :load_autocomplete_service def members render json: ::Projects::ParticipantsService.new(@project, current_user).execute(target) @@ -32,13 +32,6 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController end def target - case params[:type]&.downcase - when 'issue' - IssuesFinder.new(current_user, project_id: @project.id).find_by(iid: params[:type_id]) || @project.issues.build - when 'mergerequest' - MergeRequestsFinder.new(current_user, project_id: @project.id).find_by(iid: params[:type_id]) || @project.merge_requests.build - when 'commit' - @project.commit(params[:type_id]) - end + @autocomplete_service.target(params[:type], params[:type_id]) end end diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb index 5286b92ab6b..d116ad11294 100644 --- a/app/services/projects/autocomplete_service.rb +++ b/app/services/projects/autocomplete_service.rb @@ -51,5 +51,16 @@ module Projects QuickActions::InterpretService.new(project, current_user).available_commands(noteable) end + + def target(type, type_id) + case type&.downcase + when 'issue' + IssuesFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.issues.build + when 'mergerequest' + MergeRequestsFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.merge_requests.build + when 'commit' + project.commit(type_id) + end + end end end -- cgit v1.2.1 From 9c6fc59c6c95f8439e47d62eb4fd4b11f8d0acdc Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Sat, 28 Jul 2018 23:43:21 +0200 Subject: Support "Preview" tab also for commit commands --- app/services/preview_markdown_service.rb | 12 ++++-------- spec/services/preview_markdown_service_spec.rb | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/app/services/preview_markdown_service.rb b/app/services/preview_markdown_service.rb index a15ee4911ef..c8c8ebbcc6c 100644 --- a/app/services/preview_markdown_service.rb +++ b/app/services/preview_markdown_service.rb @@ -16,7 +16,7 @@ class PreviewMarkdownService < BaseService private def explain_quick_actions(text) - return text, [] unless %w(Issue MergeRequest).include?(commands_target_type) + return text, [] unless %w(Issue MergeRequest Commit).include?(commands_target_type) quick_actions_service = QuickActions::InterpretService.new(project, current_user) quick_actions_service.explain(text, find_commands_target) @@ -29,13 +29,9 @@ class PreviewMarkdownService < BaseService end def find_commands_target - if commands_target_id.present? - finder = commands_target_type == 'Issue' ? IssuesFinder : MergeRequestsFinder - finder.new(current_user, project_id: project.id).find(commands_target_id) - else - collection = commands_target_type == 'Issue' ? project.issues : project.merge_requests - collection.build - end + Projects::AutocompleteService + .new(project, current_user) + .target(commands_target_type, commands_target_id) end def commands_target_type diff --git a/spec/services/preview_markdown_service_spec.rb b/spec/services/preview_markdown_service_spec.rb index 81dc7c57f4a..507909d9231 100644 --- a/spec/services/preview_markdown_service_spec.rb +++ b/spec/services/preview_markdown_service_spec.rb @@ -65,6 +65,31 @@ describe PreviewMarkdownService do end end + context 'commit description' do + let(:project) { create(:project, :repository) } + let(:commit) { project.commit } + let(:params) do + { + text: "My work\n/tag v1.2.3 Stable release", + quick_actions_target_type: 'Commit', + quick_actions_target_id: commit.id + } + end + let(:service) { described_class.new(project, user, params) } + + it 'removes quick actions from text' do + result = service.execute + + expect(result[:text]).to eq 'My work' + end + + it 'explains quick actions effect' do + result = service.execute + + expect(result[:commands]).to eq 'Tags this commit to v1.2.3 with "Stable release".' + end + end + it 'sets correct markdown engine' do service = described_class.new(project, user, { markdown_version: CacheMarkdownField::CACHE_REDCARPET_VERSION }) result = service.execute -- cgit v1.2.1 From fbd0f162524b6dd875097f76e1175a55dba5f3f6 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Mon, 30 Jul 2018 13:25:51 +0200 Subject: Let Commits::TagService return a result hash --- app/services/commits/tag_service.rb | 10 +++++++--- spec/services/commits/tag_service_spec.rb | 33 +++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/app/services/commits/tag_service.rb b/app/services/commits/tag_service.rb index fb841655fee..7961ba4d3c4 100644 --- a/app/services/commits/tag_service.rb +++ b/app/services/commits/tag_service.rb @@ -3,7 +3,9 @@ module Commits class TagService < BaseService def execute(commit) - return unless params[:tag_name] + unless params[:tag_name] + return error('Missing parameter tag_name') + end tag_name = params[:tag_name] message = params[:tag_message] @@ -13,10 +15,12 @@ module Commits .new(commit.project, current_user) .execute(tag_name, commit.sha, message, release_description) - if result[:status] == :success && (tag = result[:tag]) + if result[:status] == :success + tag = result[:tag] SystemNoteService.tag_commit(commit, commit.project, current_user, tag.name) - commit end + + result end end end diff --git a/spec/services/commits/tag_service_spec.rb b/spec/services/commits/tag_service_spec.rb index 5e778681544..f14eb9ea2b9 100644 --- a/spec/services/commits/tag_service_spec.rb +++ b/spec/services/commits/tag_service_spec.rb @@ -13,11 +13,12 @@ describe Commits::TagService do describe '#execute' do let(:service) { described_class.new(project, user, opts) } - shared_examples 'tagging fails' do - it 'returns nil' do - tagged_commit = service.execute(commit) + shared_examples 'tag failure' do + it 'returns a hash with the :error status' do + result = service.execute(commit) - expect(tagged_commit).to be_nil + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq(error_message) end it 'does not add a system note' do @@ -51,10 +52,14 @@ describe Commits::TagService do end context 'when tagging succeeds' do - it 'returns the commit' do - tagged_commit = service.execute(commit) + it 'returns a hash with the :success status and created tag' do + result = service.execute(commit) - expect(tagged_commit).to eq(commit) + expect(result[:status]).to eq(:success) + + tag = result[:tag] + expect(tag.name).to eq(opts[:tag_name]) + expect(tag.message).to eq(opts[:tag_message]) end it 'adds a system note' do @@ -66,13 +71,19 @@ describe Commits::TagService do end context 'when tagging fails' do + let(:tag_error) { 'GitLab: You are not allowed to push code to this project.' } + before do tag_stub = instance_double(Tags::CreateService) allow(Tags::CreateService).to receive(:new).and_return(tag_stub) - allow(tag_stub).to receive(:execute).and_return({ status: :error }) + allow(tag_stub).to receive(:execute).and_return({ + status: :error, message: tag_error + }) end - include_examples 'tagging fails' + it_behaves_like 'tag failure' do + let(:error_message) { tag_error } + end end end @@ -81,7 +92,9 @@ describe Commits::TagService do {} end - include_examples 'tagging fails' + it_behaves_like 'tag failure' do + let(:error_message) { 'Missing parameter tag_name' } + end end end end -- cgit v1.2.1 From 56ce46674f93e35b2ed54771c1a54dde21f38685 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Wed, 1 Aug 2018 16:54:13 +0200 Subject: You cannot `/award` a Commit --- app/services/quick_actions/interpret_service.rb | 3 ++- spec/services/quick_actions/interpret_service_spec.rb | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index d84da989924..eb71f04c164 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -393,7 +393,8 @@ module QuickActions end params ':emoji:' condition do - issuable.persisted? + issuable.is_a?(Issuable) && + issuable.persisted? end parse_params do |emoji_param| match = emoji_param.match(Banzai::Filter::EmojiFilter.emoji_pattern) diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index be209c41c0f..af1064d032d 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -980,6 +980,12 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end end + + context 'if issuable is a Commit' do + let(:content) { '/award :100:' } + let(:issuable) { commit } + it_behaves_like 'empty command' + end end context '/shrug command' do -- cgit v1.2.1 From 2881886417ba08fb4a47fb95f43678578454766d Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Wed, 1 Aug 2018 17:05:02 +0200 Subject: Cannot mark a Commit as todo via `/todo` --- app/services/quick_actions/interpret_service.rb | 3 +- .../quick_actions/interpret_service_spec.rb | 32 +++++++++++++++------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index eb71f04c164..8838ed06324 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -301,7 +301,8 @@ module QuickActions desc 'Add a todo' explanation 'Adds a todo.' condition do - issuable.persisted? && + issuable.is_a?(Issuable) && + issuable.persisted? && !TodoService.new.todo_exist?(issuable, current_user) end command :todo do diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index af1064d032d..bf1c157c4a2 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -637,16 +637,6 @@ describe QuickActions::InterpretService do let(:issuable) { merge_request } end - it_behaves_like 'todo command' do - let(:content) { '/todo' } - let(:issuable) { issue } - end - - it_behaves_like 'todo command' do - let(:content) { '/todo' } - let(:issuable) { merge_request } - end - it_behaves_like 'done command' do let(:content) { '/done' } let(:issuable) { issue } @@ -796,6 +786,28 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end + context '/todo' do + let(:content) { '/todo' } + + context 'if issuable is an Issue' do + it_behaves_like 'todo command' do + let(:issuable) { issue } + end + end + + context 'if issuable is a MergeRequest' do + it_behaves_like 'todo command' do + let(:issuable) { merge_request } + end + end + + context 'if issuable is a Commit' do + it_behaves_like 'empty command' do + let(:issuable) { commit } + end + end + end + context '/copy_metadata command' do let(:todo_label) { create(:label, project: project, title: 'To Do') } let(:inreview_label) { create(:label, project: project, title: 'In Review') } -- cgit v1.2.1 From 82337dd684d88ec38285d51cfb1180b1a1057b95 Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Thu, 9 Aug 2018 11:04:12 +0200 Subject: Implement QuickActions::TargetService --- .../projects/autocomplete_sources_controller.rb | 6 +- app/services/preview_markdown_service.rb | 4 +- app/services/projects/autocomplete_service.rb | 11 ---- app/services/quick_actions/target_service.rb | 32 +++++++++ spec/services/quick_actions/target_service_spec.rb | 75 ++++++++++++++++++++++ 5 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 app/services/quick_actions/target_service.rb create mode 100644 spec/services/quick_actions/target_service_spec.rb diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb index 6e3edb31b99..a8f73ed5cb0 100644 --- a/app/controllers/projects/autocomplete_sources_controller.rb +++ b/app/controllers/projects/autocomplete_sources_controller.rb @@ -1,5 +1,5 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController - before_action :load_autocomplete_service + before_action :load_autocomplete_service, except: [:members] def members render json: ::Projects::ParticipantsService.new(@project, current_user).execute(target) @@ -32,6 +32,8 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController end def target - @autocomplete_service.target(params[:type], params[:type_id]) + QuickActions::TargetService + .new(project, current_user) + .execute(params[:type], params[:type_id]) end end diff --git a/app/services/preview_markdown_service.rb b/app/services/preview_markdown_service.rb index c8c8ebbcc6c..11b996ed4b6 100644 --- a/app/services/preview_markdown_service.rb +++ b/app/services/preview_markdown_service.rb @@ -29,9 +29,9 @@ class PreviewMarkdownService < BaseService end def find_commands_target - Projects::AutocompleteService + QuickActions::TargetService .new(project, current_user) - .target(commands_target_type, commands_target_id) + .execute(commands_target_type, commands_target_id) end def commands_target_type diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb index d116ad11294..5286b92ab6b 100644 --- a/app/services/projects/autocomplete_service.rb +++ b/app/services/projects/autocomplete_service.rb @@ -51,16 +51,5 @@ module Projects QuickActions::InterpretService.new(project, current_user).available_commands(noteable) end - - def target(type, type_id) - case type&.downcase - when 'issue' - IssuesFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.issues.build - when 'mergerequest' - MergeRequestsFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.merge_requests.build - when 'commit' - project.commit(type_id) - end - end end end diff --git a/app/services/quick_actions/target_service.rb b/app/services/quick_actions/target_service.rb new file mode 100644 index 00000000000..b29b141a309 --- /dev/null +++ b/app/services/quick_actions/target_service.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module QuickActions + class TargetService < BaseService + def execute(type, type_id) + case type&.downcase + when 'issue' + issue(type_id) + when 'mergerequest' + merge_request(type_id) + when 'commit' + commit(type_id) + end + end + + private + + def issue(type_id) + IssuesFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.issues.build + end + + def merge_request(type_id) + MergeRequestsFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.merge_requests.build + end + + def commit(type_id) + return nil unless type_id + + project.commit(type_id) + end + end +end diff --git a/spec/services/quick_actions/target_service_spec.rb b/spec/services/quick_actions/target_service_spec.rb new file mode 100644 index 00000000000..36de5269dea --- /dev/null +++ b/spec/services/quick_actions/target_service_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe QuickActions::TargetService do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:service) { described_class.new(project, user) } + + before do + project.add_maintainer(user) + end + + describe '#execute' do + shared_examples 'no target' do |type_id:| + it 'returns nil' do + target = service.execute(type, type_id) + + expect(target).to be_nil + end + end + + shared_examples 'find target' do + it 'returns the target' do + found_target = service.execute(type, target_id) + + expect(found_target).to eq(target) + end + end + + shared_examples 'build target' do |type_id:| + it 'builds a new target' do + target = service.execute(type, type_id) + + expect(target.project).to eq(project) + expect(target).to be_new_record + end + end + + context 'for issue' do + let(:target) { create(:issue, project: project) } + let(:target_id) { target.iid } + let(:type) { 'Issue' } + + it_behaves_like 'find target' + it_behaves_like 'build target', type_id: nil + it_behaves_like 'build target', type_id: -1 + end + + context 'for merge request' do + let(:target) { create(:merge_request, source_project: project) } + let(:target_id) { target.iid } + let(:type) { 'MergeRequest' } + + it_behaves_like 'find target' + it_behaves_like 'build target', type_id: nil + it_behaves_like 'build target', type_id: -1 + end + + context 'for commit' do + let(:project) { create(:project, :repository) } + let(:target) { project.commit } + let(:target_id) { target.sha } + let(:type) { 'Commit' } + + it_behaves_like 'find target' + it_behaves_like 'no target', type_id: 'invalid_sha' + it_behaves_like 'no target', type_id: nil + end + + context 'for unknown type' do + let(:type) { 'unknown' } + + it_behaves_like 'no target', type_id: :unused + end + end +end -- cgit v1.2.1 From ea9c7bee4b167e85e192cc40720d2c4cc07540ab Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Fri, 10 Aug 2018 17:51:34 +0200 Subject: Fix preview of commit tagging --- app/services/quick_actions/target_service.rb | 2 -- spec/features/commits/user_uses_slash_commands_spec.rb | 10 ++++++++++ spec/services/quick_actions/target_service_spec.rb | 10 ++++++++-- spec/support/helpers/features/notes_helpers.rb | 7 +++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app/services/quick_actions/target_service.rb b/app/services/quick_actions/target_service.rb index b29b141a309..d8ba52c6e50 100644 --- a/app/services/quick_actions/target_service.rb +++ b/app/services/quick_actions/target_service.rb @@ -24,8 +24,6 @@ module QuickActions end def commit(type_id) - return nil unless type_id - project.commit(type_id) end end diff --git a/spec/features/commits/user_uses_slash_commands_spec.rb b/spec/features/commits/user_uses_slash_commands_spec.rb index f356155be61..d8359766509 100644 --- a/spec/features/commits/user_uses_slash_commands_spec.rb +++ b/spec/features/commits/user_uses_slash_commands_spec.rb @@ -32,5 +32,15 @@ describe 'Commit > User uses quick actions', :js do expect(page).to have_content tag_message expect(page).to have_content truncated_commit_sha end + + describe 'preview', :js do + it 'removes quick action from note and explains it' do + preview_note("/tag #{tag_name} #{tag_message}") + + expect(page).not_to have_content '/tag' + expect(page).to have_content %{Tags this commit to #{tag_name} with "#{tag_message}"} + expect(page).to have_content tag_name + end + end end end diff --git a/spec/services/quick_actions/target_service_spec.rb b/spec/services/quick_actions/target_service_spec.rb index 36de5269dea..abe07ae90ba 100644 --- a/spec/services/quick_actions/target_service_spec.rb +++ b/spec/services/quick_actions/target_service_spec.rb @@ -57,13 +57,19 @@ describe QuickActions::TargetService do context 'for commit' do let(:project) { create(:project, :repository) } - let(:target) { project.commit } + let(:target) { project.commit.parent } let(:target_id) { target.sha } let(:type) { 'Commit' } it_behaves_like 'find target' it_behaves_like 'no target', type_id: 'invalid_sha' - it_behaves_like 'no target', type_id: nil + + context 'with nil target_id' do + let(:target) { project.commit } + let(:target_id) { nil } + + it_behaves_like 'find target' + end end context 'for unknown type' do diff --git a/spec/support/helpers/features/notes_helpers.rb b/spec/support/helpers/features/notes_helpers.rb index 2b9f8b30c60..89517fde6e2 100644 --- a/spec/support/helpers/features/notes_helpers.rb +++ b/spec/support/helpers/features/notes_helpers.rb @@ -20,6 +20,13 @@ module Spec end end end + + def preview_note(text) + page.within('.js-main-target-form') do + fill_in('note[note]', with: text) + click_on('Preview') + end + end end end end -- cgit v1.2.1 From 7fe85c1d42e89e91e619dcbe9ac945a9223ec72b Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Fri, 10 Aug 2018 18:15:25 +0200 Subject: Freeze string literals See Danger's suggestions: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6869#note_93730253 --- app/policies/commit_policy.rb | 2 ++ spec/features/commits/user_uses_slash_commands_spec.rb | 2 ++ spec/services/commits/tag_service_spec.rb | 2 ++ spec/services/quick_actions/target_service_spec.rb | 2 ++ 4 files changed, 8 insertions(+) diff --git a/app/policies/commit_policy.rb b/app/policies/commit_policy.rb index 44063181241..67e9bc12804 100644 --- a/app/policies/commit_policy.rb +++ b/app/policies/commit_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CommitPolicy < BasePolicy delegate { @subject.project } end diff --git a/spec/features/commits/user_uses_slash_commands_spec.rb b/spec/features/commits/user_uses_slash_commands_spec.rb index d8359766509..9a4b7bd2444 100644 --- a/spec/features/commits/user_uses_slash_commands_spec.rb +++ b/spec/features/commits/user_uses_slash_commands_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Commit > User uses quick actions', :js do diff --git a/spec/services/commits/tag_service_spec.rb b/spec/services/commits/tag_service_spec.rb index f14eb9ea2b9..82377a8dace 100644 --- a/spec/services/commits/tag_service_spec.rb +++ b/spec/services/commits/tag_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Commits::TagService do diff --git a/spec/services/quick_actions/target_service_spec.rb b/spec/services/quick_actions/target_service_spec.rb index abe07ae90ba..0aeb29cbeec 100644 --- a/spec/services/quick_actions/target_service_spec.rb +++ b/spec/services/quick_actions/target_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe QuickActions::TargetService do -- cgit v1.2.1 From 7b87c75c1235732716455cad016c848c6930f03e Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Fri, 10 Aug 2018 19:13:52 +0200 Subject: Tag message is frozen so avoid stripping destructively --- app/services/tags/create_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/tags/create_service.rb b/app/services/tags/create_service.rb index 329722df747..35390f5082c 100644 --- a/app/services/tags/create_service.rb +++ b/app/services/tags/create_service.rb @@ -7,7 +7,7 @@ module Tags return error('Tag name invalid') unless valid_tag repository = project.repository - message&.strip! + message = message&.strip new_tag = nil -- cgit v1.2.1