summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManolis Mavrofidis <mavrofidise@gmail.com>2017-08-09 18:37:06 +0300
committermanolis <mavrofidise@gmail.com>2017-08-31 21:30:36 +0100
commit7e71f958ac721f5c36c20a5366c1e46adce4c67d (patch)
tree63b74b20bdb22d42afcd82764fdf97f01d8c655a
parent420d835e5fb41e1c3291a814f807b555b24646ca (diff)
downloadgitlab-ce-7e71f958ac721f5c36c20a5366c1e46adce4c67d.tar.gz
/move project functionality. Squash commit.
Update to add all issues to be updated. Added functionality, proper tests, documentation and changelog.
-rw-r--r--app/services/issuable_base_service.rb1
-rw-r--r--app/services/issues/update_service.rb13
-rw-r--r--app/services/quick_actions/interpret_service.rb18
-rw-r--r--changelogs/unreleased/move-action.yml4
-rw-r--r--doc/user/project/quick_actions.md1
-rw-r--r--spec/features/issues/user_uses_slash_commands_spec.rb109
-rw-r--r--spec/services/issues/update_service_spec.rb20
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb10
8 files changed, 175 insertions, 1 deletions
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index b84a6fd2b7d..7c205e9c789 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -56,6 +56,7 @@ class IssuableBaseService < BaseService
params.delete(:assignee_id)
params.delete(:due_date)
params.delete(:canonical_issue_id)
+ params.delete(:project)
end
filter_assignee(issuable)
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 8d918ccc635..deb4990eb4f 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -6,7 +6,7 @@ module Issues
handle_move_between_iids(issue)
filter_spam_check_params
change_issue_duplicate(issue)
- update(issue)
+ move_issue_to_new_project(issue) || update(issue)
end
def before_update(issue)
@@ -74,6 +74,17 @@ module Issues
end
end
+ def move_issue_to_new_project(issue)
+ target_project = params.delete(:target_project)
+
+ return unless target_project &&
+ issue.can_move?(current_user, target_project) &&
+ target_project != issue.project
+
+ update(issue)
+ Issues::MoveService.new(project, current_user).execute(issue, target_project)
+ end
+
private
def get_issue_if_allowed(project, iid)
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index c7832c47e1a..9cdb9935bea 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -505,6 +505,24 @@ module QuickActions
end
end
+ desc 'Move this issue to another project.'
+ explanation do |path_to_project|
+ "Moves this issue to #{path_to_project}."
+ end
+ params 'path/to/project'
+ condition do
+ issuable.is_a?(Issue) &&
+ issuable.persisted? &&
+ current_user.can?(:"admin_#{issuable.to_ability_name}", project)
+ end
+ command :move do |target_project_path|
+ target_project = Project.find_by_full_path(target_project_path)
+
+ if target_project.present?
+ @updates[:target_project] = target_project
+ end
+ end
+
def extract_users(params)
return [] if params.nil?
diff --git a/changelogs/unreleased/move-action.yml b/changelogs/unreleased/move-action.yml
new file mode 100644
index 00000000000..65eceae3ef9
--- /dev/null
+++ b/changelogs/unreleased/move-action.yml
@@ -0,0 +1,4 @@
+---
+title: Allow users to move issues to other projects using a / command
+merge_request: 13436
+author: Manolis Mavrofidis
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index ce4dd4e99d5..6a5d2d40927 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -38,3 +38,4 @@ do.
| `/award :emoji:` | Toggle award for :emoji: |
| `/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 |
diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb
index 4b63cc844f3..9261acda9dc 100644
--- a/spec/features/issues/user_uses_slash_commands_spec.rb
+++ b/spec/features/issues/user_uses_slash_commands_spec.rb
@@ -155,5 +155,114 @@ feature 'Issues > User uses quick actions', js: true do
end
end
end
+
+ describe 'move the issue to another project' do
+ let(:issue) { create(:issue, project: project) }
+
+ context 'when the project is valid', js: true do
+ let(:target_project) { create(:project, :public) }
+
+ before do
+ target_project.team << [user, :master]
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ end
+
+ it 'moves the issue' do
+ write_note("/move #{target_project.full_path}")
+
+ expect(page).to have_content 'Commands applied'
+ expect(issue.reload).to be_closed
+
+ visit project_issue_path(target_project, issue)
+
+ expect(page).to have_content 'Issues 1'
+ end
+ end
+
+ context 'when the project is valid but the user not authorized', js: true do
+ let(:project_unauthorized) {create(:project, :public)}
+
+ before do
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ end
+
+ it 'does not move the issue' do
+ write_note("/move #{project_unauthorized.full_path}")
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(issue.reload).to be_open
+ end
+ end
+
+ context 'when the project is invalid', js: true do
+ before do
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ end
+
+ it 'does not move the issue' do
+ write_note("/move not/valid")
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(issue.reload).to be_open
+ end
+ end
+
+ context 'when the user issues multiple commands', js: true do
+ let(:target_project) { create(:project, :public) }
+ let(:milestone) { create(:milestone, title: '1.0', project: project) }
+ let(:target_milestone) { create(:milestone, title: '1.0', project: target_project) }
+ let(:bug) { create(:label, project: project, title: 'bug') }
+ let(:wontfix) { create(:label, project: project, title: 'wontfix') }
+ let(:bug_target) { create(:label, project: target_project, title: 'bug') }
+ let(:wontfix_target) { create(:label, project: target_project, title: 'wontfix') }
+
+ before do
+ target_project.team << [user, :master]
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ end
+
+ it 'applies the commands to both issues and moves the issue' do
+ write_note("/label ~#{bug.title} ~#{wontfix.title}\n/milestone %\"#{milestone.title}\"\n/move #{target_project.full_path}")
+
+ expect(page).to have_content 'Commands applied'
+ expect(issue.reload).to be_closed
+
+ visit project_issue_path(target_project, issue)
+
+ expect(page).to have_content 'bug'
+ expect(page).to have_content 'wontfix'
+ expect(page).to have_content '1.0'
+
+ visit project_issue_path(project, issue)
+ expect(page).to have_content 'Closed'
+ expect(page).to have_content 'bug'
+ expect(page).to have_content 'wontfix'
+ expect(page).to have_content '1.0'
+ end
+
+ it 'moves the issue and applies the commands to both issues' do
+ write_note("/move #{target_project.full_path}\n/label ~#{bug.title} ~#{wontfix.title}\n/milestone %\"#{milestone.title}\"")
+
+ expect(page).to have_content 'Commands applied'
+ expect(issue.reload).to be_closed
+
+ visit project_issue_path(target_project, issue)
+
+ expect(page).to have_content 'bug'
+ expect(page).to have_content 'wontfix'
+ expect(page).to have_content '1.0'
+
+ visit project_issue_path(project, issue)
+ expect(page).to have_content 'Closed'
+ expect(page).to have_content 'bug'
+ expect(page).to have_content 'wontfix'
+ expect(page).to have_content '1.0'
+ end
+ end
+ end
end
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 34fb16edc84..2176469aba6 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -510,6 +510,26 @@ describe Issues::UpdateService, :mailer do
end
end
+ context 'move issue to another project' do
+ let(:target_project) { create(:project) }
+
+ context 'valid project' do
+ before do
+ target_project.team << [user, :master]
+ end
+
+ it 'calls the move service with the proper issue and project' do
+ move_stub = class_double("Issues::MoveService").as_stubbed_const
+ allow(Issues::MoveService).to receive(:new).and_return(move_stub)
+ allow(move_stub).to receive(:execute).with(issue, target_project).and_return(issue)
+
+ expect(move_stub).to receive(:execute).with(issue, target_project)
+
+ update_issue(target_project: target_project)
+ end
+ end
+ end
+
include_examples 'issuable update service' do
let(:open_issuable) { issue }
let(:closed_issuable) { create(:closed_issue, project: project) }
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 30fa0ee6873..6926ac85de3 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1147,5 +1147,15 @@ describe QuickActions::InterpretService do
expect(explanations).to eq(["Moves issue to ~#{bug.id} column in the board."])
end
end
+
+ describe 'move issue to another project command' do
+ let(:content) { '/move test/project' }
+
+ it 'includes the project name' do
+ _, explanations = service.explain(content, issue)
+
+ expect(explanations).to eq(["Moves this issue to test/project."])
+ end
+ end
end
end