Merge branch 'move-action' into 'master'
Merge request to address /move functionality. See merge request !13436
This commit is contained in:
commit
10854ad825
8 changed files with 175 additions and 1 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
4
changelogs/unreleased/move-action.yml
Normal file
4
changelogs/unreleased/move-action.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Allow users to move issues to other projects using a / command
|
||||
merge_request: 13436
|
||||
author: Manolis Mavrofidis
|
|
@ -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 |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue