From 1a8f43ff3e5481d65f547ac01c03e2d64e14fff0 Mon Sep 17 00:00:00 2001
From: Gabriel Gizotti <gabriel@gizotti.com>
Date: Thu, 24 Nov 2016 07:50:49 +1000
Subject: [PATCH] introduce MergeRequest#issues_mentioned_but_not_closing

---
 app/models/merge_request.rb       | 16 +++++++++++
 spec/models/merge_request_spec.rb | 45 ++++++++++++++++++++-----------
 2 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 62dd02936e2..6f660bf0e77 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -568,6 +568,22 @@ class MergeRequest < ActiveRecord::Base
     end
   end
 
+  def issues_mentioned_but_not_closing(current_user = self.author)
+    issues = []
+
+    if target_branch == project.default_branch
+      messages = [description]
+      messages.concat(commits.map(&:safe_message)) if merge_request_diff
+
+      ext = Gitlab::ReferenceExtractor.new(project, current_user)
+      ext.analyze(messages.join("\n"))
+
+      issues = ext.issues
+    end
+
+    issues - closes_issues
+  end
+
   def target_project_path
     if target_project
       target_project.path_with_namespace
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index e1f9d66714d..688c78fb404 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -252,7 +252,7 @@ describe MergeRequest, models: true do
     end
   end
 
-  describe 'detection of issues to be closed' do
+  describe 'detection of issues' do
     let(:issue0) { create :issue, project: subject.project }
     let(:issue1) { create :issue, project: subject.project }
 
@@ -265,29 +265,44 @@ describe MergeRequest, models: true do
       allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
     end
 
-    it 'accesses the set of issues that will be closed on acceptance' do
-      allow(subject.project).to receive(:default_branch).
-        and_return(subject.target_branch)
+    describe 'detection of issues to be closed' do
+      it 'accesses the set of issues that will be closed on acceptance' do
+        allow(subject.project).to receive(:default_branch).
+          and_return(subject.target_branch)
 
-      closed = subject.closes_issues
+        closed = subject.closes_issues
 
-      expect(closed).to include(issue0, issue1)
-    end
+        expect(closed).to include(issue0, issue1)
+      end
+
+      it 'only lists issues as to be closed if it targets the default branch' do
+        allow(subject.project).to receive(:default_branch).and_return('master')
+        subject.target_branch = 'something-else'
+
+        expect(subject.closes_issues).to be_empty
+      end
+
+      it 'detects issues mentioned in the description' do
+        issue2 = create(:issue, project: subject.project)
+
+        subject.description = "Closes #{issue2.to_reference}"
 
-    it 'only lists issues as to be closed if it targets the default branch' do
-      allow(subject.project).to receive(:default_branch).and_return('master')
-      subject.target_branch = 'something-else'
+        allow(subject.project).to receive(:default_branch).
+          and_return(subject.target_branch)
 
-      expect(subject.closes_issues).to be_empty
+        expect(subject.closes_issues).to include(issue2)
+      end
     end
 
-    it 'detects issues mentioned in the description' do
-      issue2 = create(:issue, project: subject.project)
-      subject.description = "Closes #{issue2.to_reference}"
+    it 'detects issues mentioned but not closed' do
+      mentioned_issue = create(:issue, project: subject.project)
+
+      subject.description = "Is related to #{mentioned_issue.to_reference}"
+
       allow(subject.project).to receive(:default_branch).
         and_return(subject.target_branch)
 
-      expect(subject.closes_issues).to include(issue2)
+      expect(subject.issues_mentioned_but_not_closing).to match_array([mentioned_issue])
     end
   end
 
-- 
GitLab