Merge branch 'add-support-remove-milestone' into 'master'
Add support for destroying project milestones ### What does this MR do? This MR adds a "Remove" button to the project milestones page and the milestone page itself. ### Why was this MR needed? Because lots of people talked about needing to clean their toilets. :) ### What are the relevant issue numbers? Closes https://github.com/gitlabhq/gitlabhq/issues/1504 ### Screenshots ![image](https://gitlab.com/gitlab-org/gitlab-ce/uploads/ef8c7a3ea1db7b37cccae3869ac4de0a/image.png) ![image](https://gitlab.com/gitlab-org/gitlab-ce/uploads/33eb01c7bc30fb235de96db5efb8746d/image.png) See merge request !980
This commit is contained in:
commit
a84ed6eb23
|
@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
|
||||||
|
|
||||||
v 7.14.0 (unreleased)
|
v 7.14.0 (unreleased)
|
||||||
- Expire Rails cache entries after two weeks to prevent endless Redis growth
|
- Expire Rails cache entries after two weeks to prevent endless Redis growth
|
||||||
|
- Add support for destroying project milestones (Stan Hu)
|
||||||
|
|
||||||
v 7.13.0 (unreleased)
|
v 7.13.0 (unreleased)
|
||||||
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
|
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
|
||||||
|
|
|
@ -64,7 +64,12 @@ class Projects::MilestonesController < Projects::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
return access_denied! unless can?(current_user, :admin_milestone, @milestone)
|
return access_denied! unless can?(current_user, :admin_milestone, @project)
|
||||||
|
|
||||||
|
update_params = { milestone: nil }
|
||||||
|
@milestone.issues.each do |issue|
|
||||||
|
Issues::UpdateService.new(@project, current_user, update_params).execute(issue)
|
||||||
|
end
|
||||||
|
|
||||||
@milestone.destroy
|
@milestone.destroy
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
%i.fa.fa-pencil-square-o
|
%i.fa.fa-pencil-square-o
|
||||||
Edit
|
Edit
|
||||||
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-sm btn-close"
|
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-sm btn-close"
|
||||||
|
= link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-sm btn-remove" do
|
||||||
|
%i.fa.fa-trash-o
|
||||||
|
Remove
|
||||||
|
|
||||||
%h4
|
%h4
|
||||||
= link_to_gfm truncate(milestone.title, length: 100), namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
|
= link_to_gfm truncate(milestone.title, length: 100), namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
|
||||||
- if milestone.expired? and not milestone.closed?
|
- if milestone.expired? and not milestone.closed?
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
|
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
|
||||||
- else
|
- else
|
||||||
= link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
|
= link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
|
||||||
|
= link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-remove" do
|
||||||
|
%i.fa.fa-trash-o
|
||||||
|
Remove
|
||||||
|
|
||||||
%hr
|
%hr
|
||||||
- if @milestone.issues.any? && @milestone.can_be_closed?
|
- if @milestone.issues.any? && @milestone.can_be_closed?
|
||||||
|
|
|
@ -481,7 +481,7 @@ Gitlab::Application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
|
resources :milestones, constraints: { id: /\d+/ } do
|
||||||
member do
|
member do
|
||||||
put :sort_issues
|
put :sort_issues
|
||||||
put :sort_merge_requests
|
put :sort_merge_requests
|
||||||
|
|
|
@ -17,6 +17,10 @@ Feature: Project Issues Milestones
|
||||||
And I submit new milestone "v2.3"
|
And I submit new milestone "v2.3"
|
||||||
Then I should see milestone "v2.3"
|
Then I should see milestone "v2.3"
|
||||||
|
|
||||||
|
Scenario: I delete new milestone
|
||||||
|
Given I click link to remove milestone "v2.2"
|
||||||
|
And I should see no milestones
|
||||||
|
|
||||||
@javascript
|
@javascript
|
||||||
Scenario: Listing closed issues
|
Scenario: Listing closed issues
|
||||||
Given the milestone has open and closed issues
|
Given the milestone has open and closed issues
|
||||||
|
|
|
@ -56,4 +56,12 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
|
||||||
step 'I should see 3 issues' do
|
step 'I should see 3 issues' do
|
||||||
expect(page).to have_selector('#tab-issues li.issue-row', count: 4)
|
expect(page).to have_selector('#tab-issues li.issue-row', count: 4)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
step 'I click link to remove milestone "v2.2"' do
|
||||||
|
click_link 'Remove'
|
||||||
|
end
|
||||||
|
|
||||||
|
step 'I should see no milestones' do
|
||||||
|
expect(page).to have_content('No milestones to show')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Projects::MilestonesController do
|
||||||
|
let(:project) { create(:project) }
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:milestone) { create(:milestone, project: project) }
|
||||||
|
let(:issue) { create(:issue, project: project, milestone: milestone) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
sign_in(user)
|
||||||
|
project.team << [user, :master]
|
||||||
|
controller.instance_variable_set(:@project, project)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#destroy" do
|
||||||
|
it "should remove milestone" do
|
||||||
|
expect(issue.milestone_id).to eq(milestone.id)
|
||||||
|
delete :destroy, namespace_id: project.namespace.id, project_id: project.id, id: milestone.id, format: :js
|
||||||
|
expect(response).to be_success
|
||||||
|
expect { Milestone.find(milestone.id) }.to raise_exception(ActiveRecord::RecordNotFound)
|
||||||
|
issue.reload
|
||||||
|
expect(issue.milestone_id).to eq(nil)
|
||||||
|
# Check system note left for milestone removal
|
||||||
|
last_note = project.issues.find(issue.id).notes[-1].note
|
||||||
|
expect(last_note).to eq('Milestone removed')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue