Project

General

Profile

Defect #34108 » fixed-34108-v3.patch

Yuichi HARADA, 2020-12-23 03:56

View differences:

app/models/issue.rb
1930 1930
  # Closes duplicates if the issue is being closed
1931 1931
  def close_duplicates
1932 1932
    if Setting.close_duplicate_issues? && closing?
1933
      # Check that there are no circular dependency of relationships
1934
      duplicate_issue_ids = circular_dependency_duplicate_issue_ids(duplicates)
1935
      if duplicate_issue_ids.include?(self.id)
1936
        self.errors.add :base, :circular_dependency
1937
        throw :abort
1938
      end
1939

  
1933 1940
      duplicates.each do |duplicate|
1934 1941
        # Reload is needed in case the duplicate was updated by a previous duplicate
1935 1942
        duplicate.reload
......
1946 1953
    end
1947 1954
  end
1948 1955

  
1956
  def circular_dependency_duplicate_issue_ids(issues, duplicate_ids = [])
1957
    issues.each do |issue|
1958
      next if duplicate_ids.include?(issue.id)
1959

  
1960
      duplicate_ids << issue.id
1961
      duplicate_ids.concat(circular_dependency_duplicate_issue_ids(issue.duplicates, duplicate_ids))
1962
      duplicate_ids.uniq!
1963
    end
1964
    duplicate_ids
1965
  end
1966

  
1949 1967
  # Make sure updated_on is updated when adding a note and set updated_on now
1950 1968
  # so we can set closed_on with the same value on closing
1951 1969
  def force_updated_on_change
app/models/issue_relation.rb
238 238
      issue_from.blocks? issue_to
239 239
    when 'blocks'
240 240
      issue_to.blocks? issue_from
241
    when 'duplicated'
242
      self.class.exists?(issue_from_id: issue_from, issue_to_id: issue_to, relation_type: TYPE_DUPLICATES)
243
    when 'duplicates'
244
      self.class.exists?(issue_from_id: issue_to, issue_to_id: issue_from, relation_type: TYPE_DUPLICATES)
241 245
    when 'relates'
242 246
      self.class.where(issue_from_id: issue_to, issue_to_id: issue_from).present?
243 247
    else
test/unit/issue_relation_test.rb
199 199
    assert_not_equal [], r.errors[:base]
200 200
  end
201 201

  
202
  def test_validates_circular_dependency_on_reverse_relations_using_duplicates
203
    with_locale 'en' do
204
      IssueRelation.delete_all
205
      issue1 = issues(:issues_001)
206
      issue2 = issues(:issues_002)
207
      assert(
208
        IssueRelation.create!(
209
          :issue_from => issue1, :issue_to => issue2,
210
          :relation_type => IssueRelation::TYPE_DUPLICATES
211
        )
212
      )
213
      r =
214
        IssueRelation.new(
215
          :issue_from => issue2, :issue_to => issue1,
216
          :relation_type => IssueRelation::TYPE_DUPLICATES
217
        )
218
      assert !r.save
219
      assert_include 'This relation would create a circular dependency', r.errors.full_messages
220
    end
221
  end
222

  
202 223
  def test_create_with_initialized_journals_should_create_journals
203 224
    from = Issue.find(1)
204 225
    to   = Issue.find(2)
test/unit/issue_test.rb
1615 1615
    assert !issue1.reload.closed?
1616 1616
  end
1617 1617

  
1618
  def test_should_not_close_duplicated_issue_with_multiple_circular_dependencies
1619
    IssueRelation.delete_all
1620
    issue1 = Issue.generate!
1621
    issue2 = Issue.generate!
1622
    issue3 = Issue.generate!
1623

  
1624
    IssueRelation.create(:issue_from => issue1, :issue_to => issue2,
1625
                         :relation_type => IssueRelation::TYPE_DUPLICATES).save!(:validate => false)
1626
    IssueRelation.create(:issue_from => issue2, :issue_to => issue3,
1627
                         :relation_type => IssueRelation::TYPE_DUPLICATES).save!(:validate => false)
1628
    IssueRelation.create(:issue_from => issue3, :issue_to => issue1,
1629
                         :relation_type => IssueRelation::TYPE_DUPLICATES).save!(:validate => false)
1630

  
1631
    issue2_a = Issue.generate!
1632
    issue2_b = Issue.generate!
1633

  
1634
    IssueRelation.create(:issue_from => issue2, :issue_to => issue2_a,
1635
                         :relation_type => IssueRelation::TYPE_DUPLICATES).save!(:validate => false)
1636
    IssueRelation.create(:issue_from => issue2_a, :issue_to => issue2_b,
1637
                         :relation_type => IssueRelation::TYPE_DUPLICATES).save!(:validate => false)
1638
    IssueRelation.create(:issue_from => issue2_b, :issue_to => issue2,
1639
                         :relation_type => IssueRelation::TYPE_DUPLICATES).save!(:validate => false)
1640

  
1641
    assert_equal 1, issue1.duplicates.count
1642
    assert_equal [issue3], issue1.duplicates
1643
    assert_equal 1, issue3.duplicates.count
1644
    assert_equal [issue2], issue3.duplicates
1645
    assert_equal 2, issue2.duplicates.count
1646
    assert_equal [issue1, issue2_b], issue2.duplicates.sort
1647

  
1648
    issue1.init_journal(users(:users_002), "Closing issue")
1649
    issue1.status = IssueStatus.where(:is_closed => true).first
1650
    assert !issue1.save
1651
    assert_include 'This relation would create a circular dependency', issue1.errors.full_messages
1652
  end
1653

  
1618 1654
  def test_assignable_versions
1619 1655
    issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
1620 1656
                      :status_id => 1, :fixed_version_id => 1,
(4-4/4)