Commit 2c46c452 authored by Vinnie Okada's avatar Vinnie Okada

Track projects in ReferenceExtractor

Store both the project and identifier of extracted references.  This
prevents `ReferenceExtractor` from returning objects in the wrong
project for cross-project references.
parent 7edc1439
...@@ -67,7 +67,7 @@ module Mentionable ...@@ -67,7 +67,7 @@ module Mentionable
def references(p = project, text = mentionable_text) def references(p = project, text = mentionable_text)
return [] if text.blank? return [] if text.blank?
ext = Gitlab::ReferenceExtractor.new ext = Gitlab::ReferenceExtractor.new
ext.analyze(text) ext.analyze(text, p)
(ext.issues_for(p) + ext.merge_requests_for(p) + ext.commits_for(p)).uniq - [local_reference] (ext.issues_for(p) + ext.merge_requests_for(p) + ext.commits_for(p)).uniq - [local_reference]
end end
......
...@@ -6,7 +6,7 @@ module Gitlab ...@@ -6,7 +6,7 @@ module Gitlab
md = ISSUE_CLOSING_REGEX.match(message) md = ISSUE_CLOSING_REGEX.match(message)
if md if md
extractor = Gitlab::ReferenceExtractor.new extractor = Gitlab::ReferenceExtractor.new
extractor.analyze(md[0]) extractor.analyze(md[0], project)
extractor.issues_for(project) extractor.issues_for(project)
else else
[] []
......
...@@ -9,51 +9,63 @@ module Gitlab ...@@ -9,51 +9,63 @@ module Gitlab
@users, @issues, @merge_requests, @snippets, @commits = [], [], [], [], [] @users, @issues, @merge_requests, @snippets, @commits = [], [], [], [], []
end end
def analyze(string) def analyze(string, project)
parse_references(string.dup) parse_references(string.dup, project)
end end
# Given a valid project, resolve the extracted identifiers of the requested type to # Given a valid project, resolve the extracted identifiers of the requested type to
# model objects. # model objects.
def users_for(project) def users_for(project)
users.map do |identifier| users.map do |entry|
project.users.where(username: identifier).first project.users.where(username: entry[:id]).first
end.reject(&:nil?) end.reject(&:nil?)
end end
def issues_for(project) def issues_for(project = nil)
issues.map do |identifier| issues.map do |entry|
project.issues.where(iid: identifier).first if should_lookup?(project, entry[:project])
entry[:project].issues.where(iid: entry[:id]).first
end
end.reject(&:nil?) end.reject(&:nil?)
end end
def merge_requests_for(project) def merge_requests_for(project = nil)
merge_requests.map do |identifier| merge_requests.map do |entry|
project.merge_requests.where(iid: identifier).first if should_lookup?(project, entry[:project])
entry[:project].merge_requests.where(iid: entry[:id]).first
end
end.reject(&:nil?) end.reject(&:nil?)
end end
def snippets_for(project) def snippets_for(project)
snippets.map do |identifier| snippets.map do |entry|
project.snippets.where(id: identifier).first project.snippets.where(id: entry[:id]).first
end.reject(&:nil?) end.reject(&:nil?)
end end
def commits_for(project) def commits_for(project = nil)
repo = project.repository commits.map do |entry|
return [] if repo.nil? repo = entry[:project].repository if entry[:project]
if should_lookup?(project, entry[:project])
commits.map do |identifier| repo.commit(entry[:id]) if repo
repo.commit(identifier) end
end.reject(&:nil?) end.reject(&:nil?)
end end
private private
def reference_link(type, identifier, _, _) def reference_link(type, identifier, project, _)
# Append identifier to the appropriate collection. # Append identifier to the appropriate collection.
send("#{type}s") << identifier send("#{type}s") << { project: project, id: identifier }
end
def should_lookup?(project, entry_project)
if entry_project.nil?
false
else
project.nil? || project.id == entry_project.id
end
end end
end end
end end
...@@ -2,45 +2,48 @@ require 'spec_helper' ...@@ -2,45 +2,48 @@ require 'spec_helper'
describe Gitlab::ReferenceExtractor do describe Gitlab::ReferenceExtractor do
it 'extracts username references' do it 'extracts username references' do
subject.analyze "this contains a @user reference" subject.analyze('this contains a @user reference', nil)
subject.users.should == ["user"] subject.users.should == [{ project: nil, id: 'user' }]
end end
it 'extracts issue references' do it 'extracts issue references' do
subject.analyze "this one talks about issue #1234" subject.analyze('this one talks about issue #1234', nil)
subject.issues.should == ["1234"] subject.issues.should == [{ project: nil, id: '1234' }]
end end
it 'extracts JIRA issue references' do it 'extracts JIRA issue references' do
Gitlab.config.gitlab.stub(:issues_tracker).and_return("jira") Gitlab.config.gitlab.stub(:issues_tracker).and_return('jira')
subject.analyze "this one talks about issue JIRA-1234" subject.analyze('this one talks about issue JIRA-1234', nil)
subject.issues.should == ["JIRA-1234"] subject.issues.should == [{ project: nil, id: 'JIRA-1234' }]
end end
it 'extracts merge request references' do it 'extracts merge request references' do
subject.analyze "and here's !43, a merge request" subject.analyze("and here's !43, a merge request", nil)
subject.merge_requests.should == ["43"] subject.merge_requests.should == [{ project: nil, id: '43' }]
end end
it 'extracts snippet ids' do it 'extracts snippet ids' do
subject.analyze "snippets like $12 get extracted as well" subject.analyze('snippets like $12 get extracted as well', nil)
subject.snippets.should == ["12"] subject.snippets.should == [{ project: nil, id: '12' }]
end end
it 'extracts commit shas' do it 'extracts commit shas' do
subject.analyze "commit shas 98cf0ae3 are pulled out as Strings" subject.analyze('commit shas 98cf0ae3 are pulled out as Strings', nil)
subject.commits.should == ["98cf0ae3"] subject.commits.should == [{ project: nil, id: '98cf0ae3' }]
end end
it 'extracts multiple references and preserves their order' do it 'extracts multiple references and preserves their order' do
subject.analyze "@me and @you both care about this" subject.analyze('@me and @you both care about this', nil)
subject.users.should == ["me", "you"] subject.users.should == [
{ project: nil, id: 'me' },
{ project: nil, id: 'you' }
]
end end
it 'leaves the original note unmodified' do it 'leaves the original note unmodified' do
text = "issue #123 is just the worst, @user" text = 'issue #123 is just the worst, @user'
subject.analyze text subject.analyze(text, nil)
text.should == "issue #123 is just the worst, @user" text.should == 'issue #123 is just the worst, @user'
end end
it 'handles all possible kinds of references' do it 'handles all possible kinds of references' do
...@@ -59,7 +62,7 @@ describe Gitlab::ReferenceExtractor do ...@@ -59,7 +62,7 @@ describe Gitlab::ReferenceExtractor do
project.team << [@u_foo, :reporter] project.team << [@u_foo, :reporter]
project.team << [@u_bar, :guest] project.team << [@u_bar, :guest]
subject.analyze "@foo, @baduser, @bar, and @offteam" subject.analyze('@foo, @baduser, @bar, and @offteam', project)
subject.users_for(project).should == [@u_foo, @u_bar] subject.users_for(project).should == [@u_foo, @u_bar]
end end
...@@ -67,7 +70,7 @@ describe Gitlab::ReferenceExtractor do ...@@ -67,7 +70,7 @@ describe Gitlab::ReferenceExtractor do
@i0 = create(:issue, project: project) @i0 = create(:issue, project: project)
@i1 = create(:issue, project: project) @i1 = create(:issue, project: project)
subject.analyze "##{@i0.iid}, ##{@i1.iid}, and #999." subject.analyze("##{@i0.iid}, ##{@i1.iid}, and #999.", project)
subject.issues_for(project).should == [@i0, @i1] subject.issues_for(project).should == [@i0, @i1]
end end
...@@ -75,7 +78,7 @@ describe Gitlab::ReferenceExtractor do ...@@ -75,7 +78,7 @@ describe Gitlab::ReferenceExtractor do
@m0 = create(:merge_request, source_project: project, target_project: project, source_branch: 'aaa') @m0 = create(:merge_request, source_project: project, target_project: project, source_branch: 'aaa')
@m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'bbb') @m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'bbb')
subject.analyze "!999, !#{@m1.iid}, and !#{@m0.iid}." subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.", project)
subject.merge_requests_for(project).should == [@m1, @m0] subject.merge_requests_for(project).should == [@m1, @m0]
end end
...@@ -84,14 +87,15 @@ describe Gitlab::ReferenceExtractor do ...@@ -84,14 +87,15 @@ describe Gitlab::ReferenceExtractor do
@s1 = create(:project_snippet, project: project) @s1 = create(:project_snippet, project: project)
@s2 = create(:project_snippet) @s2 = create(:project_snippet)
subject.analyze "$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}" subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}", project)
subject.snippets_for(project).should == [@s0, @s1] subject.snippets_for(project).should == [@s0, @s1]
end end
it 'accesses valid commits' do it 'accesses valid commits' do
commit = project.repository.commit("master") commit = project.repository.commit('master')
subject.analyze "this references commits #{commit.sha[0..6]} and 012345" subject.analyze("this references commits #{commit.sha[0..6]} and 012345",
project)
extracted = subject.commits_for(project) extracted = subject.commits_for(project)
extracted.should have(1).item extracted.should have(1).item
extracted[0].sha.should == commit.sha extracted[0].sha.should == commit.sha
......
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