diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb index 71dd2f8c6973d9fea0bbe52a7f5e7fdd5fe393f4..8c31cdd12d01a2319baa2a7ebfc022a6daa11e58 100644 --- a/app/models/concerns/mentionable.rb +++ b/app/models/concerns/mentionable.rb @@ -67,7 +67,7 @@ module Mentionable def references(p = project, text = mentionable_text) return [] if text.blank? 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] end diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb index 90f1370c209e4e06f9f5f6e34527327137863d38..401e6e047b16115f61a00901daac460e282ac4bd 100644 --- a/lib/gitlab/closing_issue_extractor.rb +++ b/lib/gitlab/closing_issue_extractor.rb @@ -6,7 +6,7 @@ module Gitlab md = ISSUE_CLOSING_REGEX.match(message) if md extractor = Gitlab::ReferenceExtractor.new - extractor.analyze(md[0]) + extractor.analyze(md[0], project) extractor.issues_for(project) else [] diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index d2f02f712ce43ad71d356da9dc3d858c9c4b8576..99165950aef447e8cca812727513ae7a653c6928 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -9,51 +9,63 @@ module Gitlab @users, @issues, @merge_requests, @snippets, @commits = [], [], [], [], [] end - def analyze(string) - parse_references(string.dup) + def analyze(string, project) + parse_references(string.dup, project) end # Given a valid project, resolve the extracted identifiers of the requested type to # model objects. def users_for(project) - users.map do |identifier| - project.users.where(username: identifier).first + users.map do |entry| + project.users.where(username: entry[:id]).first end.reject(&:nil?) end - def issues_for(project) - issues.map do |identifier| - project.issues.where(iid: identifier).first + def issues_for(project = nil) + issues.map do |entry| + if should_lookup?(project, entry[:project]) + entry[:project].issues.where(iid: entry[:id]).first + end end.reject(&:nil?) end - def merge_requests_for(project) - merge_requests.map do |identifier| - project.merge_requests.where(iid: identifier).first + def merge_requests_for(project = nil) + merge_requests.map do |entry| + if should_lookup?(project, entry[:project]) + entry[:project].merge_requests.where(iid: entry[:id]).first + end end.reject(&:nil?) end def snippets_for(project) - snippets.map do |identifier| - project.snippets.where(id: identifier).first + snippets.map do |entry| + project.snippets.where(id: entry[:id]).first end.reject(&:nil?) end - def commits_for(project) - repo = project.repository - return [] if repo.nil? - - commits.map do |identifier| - repo.commit(identifier) + def commits_for(project = nil) + commits.map do |entry| + repo = entry[:project].repository if entry[:project] + if should_lookup?(project, entry[:project]) + repo.commit(entry[:id]) if repo + end end.reject(&:nil?) end private - def reference_link(type, identifier, _, _) + def reference_link(type, identifier, project, _) # 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 diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 99fed27c796fa876180f0c5781ace5cbd8f9b12b..23867df39dda8f7e7f32e452eecd830863308c1c 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -2,45 +2,48 @@ require 'spec_helper' describe Gitlab::ReferenceExtractor do it 'extracts username references' do - subject.analyze "this contains a @user reference" - subject.users.should == ["user"] + subject.analyze('this contains a @user reference', nil) + subject.users.should == [{ project: nil, id: 'user' }] end it 'extracts issue references' do - subject.analyze "this one talks about issue #1234" - subject.issues.should == ["1234"] + subject.analyze('this one talks about issue #1234', nil) + subject.issues.should == [{ project: nil, id: '1234' }] end it 'extracts JIRA issue references' do - Gitlab.config.gitlab.stub(:issues_tracker).and_return("jira") - subject.analyze "this one talks about issue JIRA-1234" - subject.issues.should == ["JIRA-1234"] + Gitlab.config.gitlab.stub(:issues_tracker).and_return('jira') + subject.analyze('this one talks about issue JIRA-1234', nil) + subject.issues.should == [{ project: nil, id: 'JIRA-1234' }] end it 'extracts merge request references' do - subject.analyze "and here's !43, a merge request" - subject.merge_requests.should == ["43"] + subject.analyze("and here's !43, a merge request", nil) + subject.merge_requests.should == [{ project: nil, id: '43' }] end it 'extracts snippet ids' do - subject.analyze "snippets like $12 get extracted as well" - subject.snippets.should == ["12"] + subject.analyze('snippets like $12 get extracted as well', nil) + subject.snippets.should == [{ project: nil, id: '12' }] end it 'extracts commit shas' do - subject.analyze "commit shas 98cf0ae3 are pulled out as Strings" - subject.commits.should == ["98cf0ae3"] + subject.analyze('commit shas 98cf0ae3 are pulled out as Strings', nil) + subject.commits.should == [{ project: nil, id: '98cf0ae3' }] end it 'extracts multiple references and preserves their order' do - subject.analyze "@me and @you both care about this" - subject.users.should == ["me", "you"] + subject.analyze('@me and @you both care about this', nil) + subject.users.should == [ + { project: nil, id: 'me' }, + { project: nil, id: 'you' } + ] end it 'leaves the original note unmodified' do - text = "issue #123 is just the worst, @user" - subject.analyze text - text.should == "issue #123 is just the worst, @user" + text = 'issue #123 is just the worst, @user' + subject.analyze(text, nil) + text.should == 'issue #123 is just the worst, @user' end it 'handles all possible kinds of references' do @@ -59,7 +62,7 @@ describe Gitlab::ReferenceExtractor do project.team << [@u_foo, :reporter] 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] end @@ -67,7 +70,7 @@ describe Gitlab::ReferenceExtractor do @i0 = 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] end @@ -75,7 +78,7 @@ describe Gitlab::ReferenceExtractor do @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') - 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] end @@ -84,14 +87,15 @@ describe Gitlab::ReferenceExtractor do @s1 = create(:project_snippet, project: project) @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] end 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.should have(1).item extracted[0].sha.should == commit.sha