diff options
author | Douwe Maan <douwe@gitlab.com> | 2016-08-30 20:43:15 +0300 |
---|---|---|
committer | Douwe Maan <douwe@gitlab.com> | 2016-08-30 20:43:15 +0300 |
commit | 4bbe5ce622eafc886c3c6732bb5e7b39d1d7a351 (patch) | |
tree | 26140eea3f8060f8cf6a2a15a71ae4aa8a6ab802 | |
parent | f81e527677ae74373ae2f00c37a84120d4e40dd9 (diff) | |
parent | 2d8d94a788eb0bf3885ee67bda9638556425fa4b (diff) |
Merge branch '19315-can-edit-merge-request-with-deleted-fork' into 'master'
User can edit closed MR with deleted fork
## What does this MR do?
User can edit closed MR with deleted fork (can't change "Target branch"). When fork is deleted "Reopen" button is hidden.
## What are the relevant issue numbers?
Closes #19315
## Screenshots (if relevant)
* hidden Reopen button and information about deleted fork
![Zrzut_ekranu_2016-08-12_o_13.19.24](/uploads/d288c5625e788382e31b2979acb601df/Zrzut_ekranu_2016-08-12_o_13.19.24.png)
* editable fields for closed MR without fork
![Zrzut_ekranu_2016-08-05_o_12.24.38](/uploads/1549e54d4bc2a9939ef296ce66139706/Zrzut_ekranu_2016-08-05_o_12.24.38.png)
## Does this MR meet the acceptance criteria?
- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- Tests
- [x] Added for this feature/bug
- [x] All builds are passing
- [x] Branch has no merge conflicts with `master` (if you do - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
cc @ubudzisz @yorickpeterse @grzesiek @tmaczukin
See merge request !5496
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | app/helpers/merge_requests_helper.rb | 2 | ||||
-rw-r--r-- | app/models/merge_request.rb | 33 | ||||
-rw-r--r-- | app/services/merge_requests/update_service.rb | 4 | ||||
-rw-r--r-- | app/views/projects/merge_requests/show/_mr_title.html.haml | 4 | ||||
-rw-r--r-- | app/views/shared/issuable/_form.html.haml | 4 | ||||
-rw-r--r-- | spec/controllers/projects/merge_requests_controller_spec.rb | 29 | ||||
-rw-r--r-- | spec/models/merge_request_spec.rb | 76 | ||||
-rw-r--r-- | spec/views/projects/merge_requests/edit.html.haml_spec.rb | 53 | ||||
-rw-r--r-- | spec/views/projects/merge_requests/show.html.haml_spec.rb | 44 |
10 files changed, 232 insertions, 18 deletions
diff --git a/CHANGELOG b/CHANGELOG index 76f05d9123e..c7559c17605 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -43,6 +43,7 @@ v 8.12.0 (unreleased) - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) - Adds response mime type to transaction metric action when it's not HTML - Fix hover leading space bug in pipeline graph !5980 + - User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496 v 8.11.4 (unreleased) - Fix broken gitlab:backup:restore because of bad permissions on repo storage !6098 (Dirk Hörner) diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index db6e731c744..a9e175c3f5c 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -98,6 +98,6 @@ module MergeRequestsHelper end def merge_request_button_visibility(merge_request, closed) - return 'hidden' if merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) + return 'hidden' if merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_without_fork? end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 1d05e4a85d1..a8dd4a306cf 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -91,13 +91,13 @@ class MergeRequest < ActiveRecord::Base end end - validates :source_project, presence: true, unless: [:allow_broken, :importing?] + validates :source_project, presence: true, unless: [:allow_broken, :importing?, :closed_without_fork?] validates :source_branch, presence: true validates :target_project, presence: true validates :target_branch, presence: true validates :merge_user, presence: true, if: :merge_when_build_succeeds? - validate :validate_branches, unless: [:allow_broken, :importing?] - validate :validate_fork + validate :validate_branches, unless: [:allow_broken, :importing?, :closed_without_fork?] + validate :validate_fork, unless: :closed_without_fork? scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) } scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } @@ -305,19 +305,22 @@ class MergeRequest < ActiveRecord::Base def validate_fork return true unless target_project && source_project + return true if target_project == source_project + return true unless forked_source_project_missing? - if target_project == source_project - true - else - # If source and target projects are different - # we should check if source project is actually a fork of target project - if source_project.forked_from?(target_project) - true - else - errors.add :validate_fork, - 'Source project is not a fork of target project' - end - end + errors.add :validate_fork, + 'Source project is not a fork of the target project' + end + + def closed_without_fork? + closed? && forked_source_project_missing? + end + + def forked_source_project_missing? + return false unless for_fork? + return true unless source_project + + !source_project.forked_from?(target_project) end def ensure_merge_request_diff diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index 30c5f24988c..398ec47f0ea 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -11,6 +11,10 @@ module MergeRequests params.except!(:target_project_id) params.except!(:source_branch) + if merge_request.closed_without_fork? + params.except!(:target_branch, :force_remove_source_branch) + end + merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch) update(merge_request) diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 098ce19da21..e35291dff7d 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,3 +1,7 @@ +- if @merge_request.closed_without_fork? + .alert.alert-danger + %p The source project of this merge request has been removed. + .clearfix.detail-page-header .issuable-header .issuable-status-box.status-box{ class: status_box_class(@merge_request) } diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 22594b46443..3856a4917b4 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -134,7 +134,7 @@ title: 'Moving an issue will copy the discussion to a different project and close it here. All participants will be notified of the new location.' } = icon('question-circle') -- if issuable.is_a?(MergeRequest) +- if issuable.is_a?(MergeRequest) && !issuable.closed_without_fork? %hr - if @merge_request.new_record? .form-group @@ -175,7 +175,7 @@ = link_to 'Cancel', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable.class]), class: 'btn btn-cancel' - else .pull-right - - if current_user.can?(:"destroy_#{issuable.to_ability_name}", @project) + - if can?(current_user, :"destroy_#{issuable.to_ability_name}", @project) = link_to 'Delete', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), data: { confirm: "#{issuable.class.name.titleize} will be removed! Are you sure?" }, method: :delete, class: 'btn btn-danger btn-grouped' = link_to 'Cancel', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), class: 'btn btn-grouped btn-cancel' diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index c64c2b075c5..a219400d75f 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -170,6 +170,35 @@ describe Projects::MergeRequestsController do expect(response).to redirect_to([merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request]) expect(merge_request.reload.closed?).to be_truthy end + + it 'allows editing of a closed merge request' do + merge_request.close! + + put :update, + namespace_id: project.namespace.path, + project_id: project.path, + id: merge_request.iid, + merge_request: { + title: 'New title' + } + + expect(response).to redirect_to([merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request]) + expect(merge_request.reload.title).to eq 'New title' + end + + it 'does not allow to update target branch closed merge request' do + merge_request.close! + + put :update, + namespace_id: project.namespace.path, + project_id: project.path, + id: merge_request.iid, + merge_request: { + target_branch: 'new_branch' + } + + expect { merge_request.reload.target_branch }.not_to change { merge_request.target_branch } + end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index d67f71bbb9c..901b7bad007 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -962,4 +962,80 @@ describe MergeRequest, models: true do expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_truthy end end + + describe "#forked_source_project_missing?" do + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } + let(:user) { create(:user) } + let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } + + context "when the fork exists" do + let(:merge_request) do + create(:merge_request, + source_project: fork_project, + target_project: project) + end + + it { expect(merge_request.forked_source_project_missing?).to be_falsey } + end + + context "when the source project is the same as the target project" do + let(:merge_request) { create(:merge_request, source_project: project) } + + it { expect(merge_request.forked_source_project_missing?).to be_falsey } + end + + context "when the fork does not exist" do + let(:merge_request) do + create(:merge_request, + source_project: fork_project, + target_project: project) + end + + it "returns true" do + unlink_project.execute + merge_request.reload + + expect(merge_request.forked_source_project_missing?).to be_truthy + end + end + end + + describe "#closed_without_fork?" do + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } + let(:user) { create(:user) } + let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } + + context "when the merge request is closed" do + let(:closed_merge_request) do + create(:closed_merge_request, + source_project: fork_project, + target_project: project) + end + + it "returns false if the fork exist" do + expect(closed_merge_request.closed_without_fork?).to be_falsey + end + + it "returns true if the fork does not exist" do + unlink_project.execute + closed_merge_request.reload + + expect(closed_merge_request.closed_without_fork?).to be_truthy + end + end + + context "when the merge request is open" do + let(:open_merge_request) do + create(:merge_request, + source_project: fork_project, + target_project: project) + end + + it "returns false" do + expect(open_merge_request.closed_without_fork?).to be_falsey + end + end + end end diff --git a/spec/views/projects/merge_requests/edit.html.haml_spec.rb b/spec/views/projects/merge_requests/edit.html.haml_spec.rb new file mode 100644 index 00000000000..31bbb150698 --- /dev/null +++ b/spec/views/projects/merge_requests/edit.html.haml_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe 'projects/merge_requests/edit.html.haml' do + include Devise::TestHelpers + + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } + let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } + + let(:closed_merge_request) do + create(:closed_merge_request, + source_project: fork_project, + target_project: project, + author: user) + end + + before do + assign(:project, project) + assign(:merge_request, closed_merge_request) + + allow(view).to receive(:can?).and_return(true) + allow(view).to receive(:current_user) + .and_return(User.find(closed_merge_request.author_id)) + end + + context 'when a merge request without fork' do + it "shows editable fields" do + unlink_project.execute + closed_merge_request.reload + + render + + expect(rendered).to have_field('merge_request[title]') + expect(rendered).to have_field('merge_request[description]') + expect(rendered).to have_selector('#merge_request_assignee_id', visible: false) + expect(rendered).to have_selector('#merge_request_milestone_id', visible: false) + expect(rendered).not_to have_selector('#merge_request_target_branch', visible: false) + end + end + + context 'when a merge request with an existing source project is closed' do + it "shows editable fields" do + render + + expect(rendered).to have_field('merge_request[title]') + expect(rendered).to have_field('merge_request[description]') + expect(rendered).to have_selector('#merge_request_assignee_id', visible: false) + expect(rendered).to have_selector('#merge_request_milestone_id', visible: false) + expect(rendered).to have_selector('#merge_request_target_branch', visible: false) + end + end +end diff --git a/spec/views/projects/merge_requests/show.html.haml_spec.rb b/spec/views/projects/merge_requests/show.html.haml_spec.rb new file mode 100644 index 00000000000..fe0780e72df --- /dev/null +++ b/spec/views/projects/merge_requests/show.html.haml_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe 'projects/merge_requests/show.html.haml' do + include Devise::TestHelpers + + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } + let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } + + let(:closed_merge_request) do + create(:closed_merge_request, + source_project: fork_project, + target_project: project, + author: user) + end + + before do + assign(:project, project) + assign(:merge_request, closed_merge_request) + assign(:commits_count, 0) + + allow(view).to receive(:can?).and_return(true) + end + + context 'when the merge request is closed' do + it 'shows the "Reopen" button' do + render + + expect(rendered).to have_css('a', visible: true, text: 'Reopen') + expect(rendered).to have_css('a', visible: false, text: 'Close') + end + + it 'does not show the "Reopen" button when the source project does not exist' do + unlink_project.execute + closed_merge_request.reload + + render + + expect(rendered).to have_css('a', visible: false, text: 'Reopen') + expect(rendered).to have_css('a', visible: false, text: 'Close') + end + end +end |