Commit f4816372 authored by Stan Hu's avatar Stan Hu

Merge branch 'fix-issue-2382' into 'master'

Create a "destroyed Milestone" event and keep Milestone events around in the DB for posterity

Also fix issue where destroying a Milestone would cause odd, transient messages like "created milestone" or "imported milestone".

Now if a milestone is destroyed, at least it will indicate in the activity feed even if it's not clear which milestone was destroyed:

![image](https://gitlab.com/gitlab-org/gitlab-ce/uploads/c89cc8a0a9fa549deac433f17b890913/image.png)

Closes #2382

See merge request !1227
parents 2e9a7032 d3d03d13
...@@ -66,12 +66,7 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -66,12 +66,7 @@ class Projects::MilestonesController < Projects::ApplicationController
def destroy def destroy
return access_denied! unless can?(current_user, :admin_milestone, @project) return access_denied! unless can?(current_user, :admin_milestone, @project)
update_params = { milestone: nil } Milestones::DestroyService.new(project, current_user).execute(milestone)
@milestone.issues.each do |issue|
Issues::UpdateService.new(@project, current_user, update_params).execute(issue)
end
@milestone.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to namespace_project_milestones_path } format.html { redirect_to namespace_project_milestones_path }
......
...@@ -46,6 +46,14 @@ module EventsHelper ...@@ -46,6 +46,14 @@ module EventsHelper
} }
end end
def event_preposition(event)
if event.push? || event.commented? || event.target
"at"
elsif event.milestone?
"in"
end
end
def event_feed_title(event) def event_feed_title(event)
words = [] words = []
words << event.author_name words << event.author_name
...@@ -62,6 +70,9 @@ module EventsHelper ...@@ -62,6 +70,9 @@ module EventsHelper
words << "##{truncate event.note_target_iid}" words << "##{truncate event.note_target_iid}"
end end
words << "at" words << "at"
elsif event.milestone?
words << "##{event.target_iid}" if event.target_iid
words << "in"
elsif event.target elsif event.target
words << "##{event.target_iid}:" words << "##{event.target_iid}:"
words << event.target.title if event.target.respond_to?(:title) words << event.target.title if event.target.respond_to?(:title)
......
...@@ -27,6 +27,7 @@ class Event < ActiveRecord::Base ...@@ -27,6 +27,7 @@ class Event < ActiveRecord::Base
MERGED = 7 MERGED = 7
JOINED = 8 # User joined project JOINED = 8 # User joined project
LEFT = 9 # User left project LEFT = 9 # User left project
DESTROYED = 10
delegate :name, :email, to: :author, prefix: true, allow_nil: true delegate :name, :email, to: :author, prefix: true, allow_nil: true
delegate :title, to: :issue, prefix: true, allow_nil: true delegate :title, to: :issue, prefix: true, allow_nil: true
...@@ -48,6 +49,7 @@ class Event < ActiveRecord::Base ...@@ -48,6 +49,7 @@ class Event < ActiveRecord::Base
scope :code_push, -> { where(action: PUSHED) } scope :code_push, -> { where(action: PUSHED) }
scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
scope :with_associations, -> { includes(project: :namespace) } scope :with_associations, -> { includes(project: :namespace) }
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
class << self class << self
def reset_event_cache_for(target) def reset_event_cache_for(target)
...@@ -71,7 +73,7 @@ class Event < ActiveRecord::Base ...@@ -71,7 +73,7 @@ class Event < ActiveRecord::Base
elsif created_project? elsif created_project?
true true
else else
(issue? || merge_request? || note? || milestone?) && target ((issue? || merge_request? || note?) && target) || milestone?
end end
end end
...@@ -115,6 +117,10 @@ class Event < ActiveRecord::Base ...@@ -115,6 +117,10 @@ class Event < ActiveRecord::Base
action == LEFT action == LEFT
end end
def destroyed?
action == DESTROYED
end
def commented? def commented?
action == COMMENTED action == COMMENTED
end end
...@@ -124,7 +130,7 @@ class Event < ActiveRecord::Base ...@@ -124,7 +130,7 @@ class Event < ActiveRecord::Base
end end
def created_project? def created_project?
created? && !target created? && !target && target_type.nil?
end end
def created_target? def created_target?
...@@ -180,6 +186,8 @@ class Event < ActiveRecord::Base ...@@ -180,6 +186,8 @@ class Event < ActiveRecord::Base
'joined' 'joined'
elsif left? elsif left?
'left' 'left'
elsif destroyed?
'destroyed'
elsif commented? elsif commented?
"commented on" "commented on"
elsif created_project? elsif created_project?
......
...@@ -61,7 +61,7 @@ class Milestone < ActiveRecord::Base ...@@ -61,7 +61,7 @@ class Milestone < ActiveRecord::Base
false false
end end
end end
def open_items_count def open_items_count
self.issues.opened.count + self.merge_requests.opened.count self.issues.opened.count + self.merge_requests.opened.count
end end
......
...@@ -46,6 +46,10 @@ class EventCreateService ...@@ -46,6 +46,10 @@ class EventCreateService
create_record_event(milestone, current_user, Event::REOPENED) create_record_event(milestone, current_user, Event::REOPENED)
end end
def destroy_milestone(milestone, current_user)
create_record_event(milestone, current_user, Event::DESTROYED)
end
def leave_note(note, current_user) def leave_note(note, current_user)
create_record_event(note, current_user, Event::COMMENTED) create_record_event(note, current_user, Event::COMMENTED)
end end
......
module Milestones
class DestroyService < Milestones::BaseService
def execute(milestone)
Milestone.transaction do
update_params = { milestone: nil }
milestone.issues.each do |issue|
Issues::UpdateService.new(project, current_user, update_params).execute(issue)
end
event_service.destroy_milestone(milestone, current_user)
Event.for_milestone_id(milestone.id).each do |event|
event.target_id = nil
event.save
end
milestone.destroy
end
end
end
end
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
- if event.target - if event.target
%strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target] %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
at
= event_preposition(event)
- if event.project - if event.project
= link_to_project event.project = link_to_project event.project
- else - else
= event.project_name = event.project_name
- if event.target.respond_to?(:title) - if event.target.respond_to?(:title)
.event-body .event-body
.event-note .event-note
......
...@@ -12,13 +12,17 @@ Feature: Project Issues Milestones ...@@ -12,13 +12,17 @@ Feature: Project Issues Milestones
Given I click link "v2.2" Given I click link "v2.2"
Then I should see milestone "v2.2" Then I should see milestone "v2.2"
Scenario: I create new milestone @javascript
Scenario: I create and delete new milestone
Given I click link "New Milestone" Given I click link "New Milestone"
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"
Given I click link to remove milestone
When I visit project "Shop" activity page
Then I should see deleted milestone activity
Scenario: I delete new milestone Scenario: I delete new milestone
Given I click link to remove milestone "v2.2" Given I click link to remove milestone
And I should see no milestones And I should see no milestones
@javascript @javascript
......
...@@ -49,6 +49,11 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps ...@@ -49,6 +49,11 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
create(:closed_issue, project: project, milestone: milestone) create(:closed_issue, project: project, milestone: milestone)
end end
step 'I should see deleted milestone activity' do
expect(page).to have_content('opened milestone in')
expect(page).to have_content('destroyed milestone in')
end
When 'I click link "All Issues"' do When 'I click link "All Issues"' do
click_link 'All Issues' click_link 'All Issues'
end end
...@@ -57,7 +62,7 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps ...@@ -57,7 +62,7 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
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 step 'I click link to remove milestone' do
click_link 'Remove' click_link 'Remove'
end end
......
...@@ -51,6 +51,11 @@ module SharedProject ...@@ -51,6 +51,11 @@ module SharedProject
visit namespace_project_path(project.namespace, project) visit namespace_project_path(project.namespace, project)
end end
step 'I visit project "Shop" activity page' do
project = Project.find_by(name: 'Shop')
visit namespace_project_path(project.namespace, project)
end
step 'project "Shop" has push event' do step 'project "Shop" has push event' do
@project = Project.find_by(name: "Shop") @project = Project.find_by(name: "Shop")
......
...@@ -15,8 +15,12 @@ describe Projects::MilestonesController do ...@@ -15,8 +15,12 @@ describe Projects::MilestonesController do
describe "#destroy" do describe "#destroy" do
it "should remove milestone" do it "should remove milestone" do
expect(issue.milestone_id).to eq(milestone.id) expect(issue.milestone_id).to eq(milestone.id)
delete :destroy, namespace_id: project.namespace.id, project_id: project.id, id: milestone.id, format: :js delete :destroy, namespace_id: project.namespace.id, project_id: project.id, id: milestone.id, format: :js
expect(response).to be_success expect(response).to be_success
expect(Event.first.action).to eq(Event::DESTROYED)
expect { Milestone.find(milestone.id) }.to raise_exception(ActiveRecord::RecordNotFound) expect { Milestone.find(milestone.id) }.to raise_exception(ActiveRecord::RecordNotFound)
issue.reload issue.reload
expect(issue.milestone_id).to eq(nil) expect(issue.milestone_id).to eq(nil)
......
...@@ -99,5 +99,15 @@ describe EventCreateService do ...@@ -99,5 +99,15 @@ describe EventCreateService do
expect { service.close_milestone(milestone, user) }.to change { Event.count } expect { service.close_milestone(milestone, user) }.to change { Event.count }
end end
end end
describe :destroy_mr do
let(:milestone) { create(:milestone) }
it { expect(service.destroy_milestone(milestone, user)).to be_truthy }
it "should create new event" do
expect { service.destroy_milestone(milestone, user) }.to change { Event.count }
end
end
end end
end end
Markdown is supported
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