Automatic closing of duplicate issues.
When closing an issue, all related issues marked as duplicates are now also closed. git-svn-id: http://redmine.rubyforge.org/svn/trunk@663 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
b96dc97d15
commit
4fa51992b5
|
@ -94,7 +94,19 @@ class Issue < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_save
|
def after_save
|
||||||
|
# Update start/due dates of following issues
|
||||||
relations_from.each(&:set_issue_to_dates)
|
relations_from.each(&:set_issue_to_dates)
|
||||||
|
|
||||||
|
# Close duplicates if the issue was closed
|
||||||
|
if @issue_before_change && !@issue_before_change.closed? && self.closed?
|
||||||
|
duplicates.each do |duplicate|
|
||||||
|
# Don't re-close it if it's already closed
|
||||||
|
next if duplicate.closed?
|
||||||
|
# Same user and notes
|
||||||
|
duplicate.init_journal(@current_journal.user, @current_journal.notes)
|
||||||
|
duplicate.update_attribute :status, self.status
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def custom_value_for(custom_field)
|
def custom_value_for(custom_field)
|
||||||
|
@ -110,6 +122,11 @@ class Issue < ActiveRecord::Base
|
||||||
@current_journal
|
@current_journal
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Return true if the issue is closed, otherwise false
|
||||||
|
def closed?
|
||||||
|
self.status.is_closed?
|
||||||
|
end
|
||||||
|
|
||||||
# Users the issue can be assigned to
|
# Users the issue can be assigned to
|
||||||
def assignable_users
|
def assignable_users
|
||||||
project.members.select {|m| m.role.assignable?}.collect {|m| m.user}
|
project.members.select {|m| m.role.assignable?}.collect {|m| m.user}
|
||||||
|
@ -132,6 +149,11 @@ class Issue < ActiveRecord::Base
|
||||||
dependencies
|
dependencies
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns an array of the duplicate issues
|
||||||
|
def duplicates
|
||||||
|
relations.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.other_issue(self)}
|
||||||
|
end
|
||||||
|
|
||||||
def duration
|
def duration
|
||||||
(start_date && due_date) ? due_date - start_date : 0
|
(start_date && due_date) ? due_date - start_date : 0
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,4 +24,29 @@ class IssueTest < Test::Unit::TestCase
|
||||||
issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => Enumeration.get_values('IPRI').first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1)
|
issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => Enumeration.get_values('IPRI').first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1)
|
||||||
assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
|
assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_close_duplicates
|
||||||
|
# Create 3 issues
|
||||||
|
issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => Enumeration.get_values('IPRI').first, :subject => 'Duplicates test', :description => 'Duplicates test')
|
||||||
|
assert issue1.save
|
||||||
|
issue2 = issue1.clone
|
||||||
|
assert issue2.save
|
||||||
|
issue3 = issue1.clone
|
||||||
|
assert issue3.save
|
||||||
|
|
||||||
|
# 2 is a dupe of 1
|
||||||
|
IssueRelation.create(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES)
|
||||||
|
# And 3 is a dupe of 2
|
||||||
|
IssueRelation.create(:issue_from => issue2, :issue_to => issue3, :relation_type => IssueRelation::TYPE_DUPLICATES)
|
||||||
|
|
||||||
|
assert issue1.reload.duplicates.include?(issue2)
|
||||||
|
|
||||||
|
# Closing issue 1
|
||||||
|
issue1.init_journal(User.find(:first), "Closing issue1")
|
||||||
|
issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true}
|
||||||
|
assert issue1.save
|
||||||
|
# 2 and 3 should be also closed
|
||||||
|
assert issue2.reload.closed?
|
||||||
|
assert issue3.reload.closed?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue