Commit 7d3f2d6c authored by Stan Hu's avatar Stan Hu
Browse files

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?


### Screenshots



See merge request !980
......@@ -2,6 +2,7 @@
v 7.14.0 (unreleased)
- 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)
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
......@@ -64,7 +64,12 @@
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|, current_user, update_params).execute(issue)
......@@ -5,6 +5,10 @@
= 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
= 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?
......@@ -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"
- 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 namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-remove" do
- if @milestone.issues.any? && @milestone.can_be_closed?
......@@ -481,7 +481,7 @@
resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
resources :milestones, constraints: { id: /\d+/ } do
member do
put :sort_issues
put :sort_merge_requests
......@@ -17,6 +17,10 @@
And I submit new 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
Scenario: Listing closed issues
Given the milestone has open and closed issues
......@@ -56,4 +56,12 @@
step 'I should see 3 issues' do
expect(page).to have_selector('#tab-issues li.issue-row', count: 4)
step 'I click link to remove milestone "v2.2"' do
click_link 'Remove'
step 'I should see no milestones' do
expect(page).to have_content('No milestones to show')
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) << [user, :master]
controller.instance_variable_set(:@project, project)
describe "#destroy" do
it "should remove milestone" do
expect(issue.milestone_id).to eq(
delete :destroy, namespace_id:, project_id:, id:, format: :js
expect(response).to be_success
expect { Milestone.find( }.to raise_exception(ActiveRecord::RecordNotFound)
expect(issue.milestone_id).to eq(nil)
# Check system note left for milestone removal
last_note = project.issues.find([-1].note
expect(last_note).to eq('Milestone removed')
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment