Adds support for multiple repositories to redmine links (#779).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@8694 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
13f28858ba
commit
f2e7aa596b
|
@ -655,20 +655,28 @@ module ApplicationHelper
|
||||||
# identifier:version:1.0.0
|
# identifier:version:1.0.0
|
||||||
# identifier:source:some/file
|
# identifier:source:some/file
|
||||||
def parse_redmine_links(text, project, obj, attr, only_path, options)
|
def parse_redmine_links(text, project, obj, attr, only_path, options)
|
||||||
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|forum|news|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m|
|
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-]+)\|)?(r)))(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m|
|
||||||
leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
|
leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $14, $13 || $15
|
||||||
link = nil
|
link = nil
|
||||||
if project_identifier
|
if project_identifier
|
||||||
project = Project.visible.find_by_identifier(project_identifier)
|
project = Project.visible.find_by_identifier(project_identifier)
|
||||||
end
|
end
|
||||||
if esc.nil?
|
if esc.nil?
|
||||||
if prefix.nil? && sep == 'r'
|
if prefix.nil? && sep == 'r'
|
||||||
|
if project
|
||||||
|
repository = nil
|
||||||
|
if repo_identifier
|
||||||
|
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
|
||||||
|
else
|
||||||
|
repository = project.repository
|
||||||
|
end
|
||||||
# project.changesets.visible raises an SQL error because of a double join on repositories
|
# project.changesets.visible raises an SQL error because of a double join on repositories
|
||||||
if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier))
|
if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier))
|
||||||
link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
|
link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.revision},
|
||||||
:class => 'changeset',
|
:class => 'changeset',
|
||||||
:title => truncate_single_line(changeset.comments, :length => 100))
|
:title => truncate_single_line(changeset.comments, :length => 100))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
elsif sep == '#'
|
elsif sep == '#'
|
||||||
oid = identifier.to_i
|
oid = identifier.to_i
|
||||||
case prefix
|
case prefix
|
||||||
|
@ -731,23 +739,35 @@ module ApplicationHelper
|
||||||
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
||||||
:class => 'news'
|
:class => 'news'
|
||||||
end
|
end
|
||||||
when 'commit'
|
when 'commit', 'source', 'export'
|
||||||
if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
|
if project
|
||||||
link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
|
repository = nil
|
||||||
|
if name =~ %r{^(([a-z0-9\-]+)\|)(.+)$}
|
||||||
|
repo_prefix, repo_identifier, name = $1, $2, $3
|
||||||
|
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
|
||||||
|
else
|
||||||
|
repository = project.repository
|
||||||
|
end
|
||||||
|
if prefix == 'commit'
|
||||||
|
if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"]))
|
||||||
|
link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
|
||||||
:class => 'changeset',
|
:class => 'changeset',
|
||||||
:title => truncate_single_line(h(changeset.comments), :length => 100)
|
:title => truncate_single_line(h(changeset.comments), :length => 100)
|
||||||
end
|
end
|
||||||
when 'source', 'export'
|
else
|
||||||
if project && project.repository && User.current.allowed_to?(:browse_repository, project)
|
if repository && User.current.allowed_to?(:browse_repository, project)
|
||||||
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
|
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
|
||||||
path, rev, anchor = $1, $3, $5
|
path, rev, anchor = $1, $3, $5
|
||||||
link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
|
link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, :repository_id => repository.identifier_param,
|
||||||
:path => to_path_param(path),
|
:path => to_path_param(path),
|
||||||
:rev => rev,
|
:rev => rev,
|
||||||
:anchor => anchor,
|
:anchor => anchor,
|
||||||
:format => (prefix == 'export' ? 'raw' : nil)},
|
:format => (prefix == 'export' ? 'raw' : nil)},
|
||||||
:class => (prefix == 'export' ? 'source download' : 'source')
|
:class => (prefix == 'export' ? 'source download' : 'source')
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
repo_prefix = nil
|
||||||
|
end
|
||||||
when 'attachment'
|
when 'attachment'
|
||||||
attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
|
attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
|
||||||
if attachments && attachment = attachments.detect {|a| a.filename == name }
|
if attachments && attachment = attachments.detect {|a| a.filename == name }
|
||||||
|
@ -761,7 +781,7 @@ module ApplicationHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
(leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")).html_safe
|
(leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}")).html_safe
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -44,13 +44,9 @@
|
||||||
|
|
||||||
<h3><a name="3" class="wiki-page"></a>Redmine links</h3>
|
<h3><a name="3" class="wiki-page"></a>Redmine links</h3>
|
||||||
|
|
||||||
<p>Redmine allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.</p>
|
<p>Redmine allows hyperlinking between resources (issues, changesets, wiki pages...) from anywhere wiki formatting is used.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Link to an issue: <strong>#124</strong> (displays <del><a href="#" class="issue" title="bulk edit doesn't change the category or fixed version properties (Closed)">#124</a></del>, link is striked-through if the issue is closed)</li>
|
<li>Link to an issue: <strong>#124</strong> (displays <del><a href="#" class="issue" title="bulk edit doesn't change the category or fixed version properties (Closed)">#124</a></del>, link is striked-through if the issue is closed)</li>
|
||||||
<li>Link to a changeset: <strong>r758</strong> (displays <a href="#" class="changeset" title="Search engine now only searches objects the user is allowed to view.">r758</a>)</li>
|
|
||||||
<li>Link to a changeset with a non-numeric hash: <strong>commit:c6f4d0fd</strong> (displays <a href="#" class="changeset">c6f4d0fd</a>).</li>
|
|
||||||
<li>Link to a changeset of another project: <strong>sandbox:r758</strong> (displays <a href="#" class="changeset" title="Search engine now only searches objects the user is allowed to view.">sandbox:r758</a>)</li>
|
|
||||||
<li>Link to a changeset with a non-numeric hash: <strong>sandbox:c6f4d0fd</strong> (displays <a href="#" class="changeset">sandbox:c6f4d0fd</a>).</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Wiki links:</p>
|
<p>Wiki links:</p>
|
||||||
|
@ -100,6 +96,18 @@
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Changesets:
|
||||||
|
<ul>
|
||||||
|
<li><strong>r758</strong> (link to a changeset)</li>
|
||||||
|
<li><strong>commit:c6f4d0fd</strong> (link to a changeset with a non-numeric hash)</li>
|
||||||
|
<li><strong>svn1|r758</strong> (link to a changeset of a specific repository, for projects with multiple repositories)</li>
|
||||||
|
<li><strong>commit:hg|c6f4d0fd</strong> (link to a changeset with a non-numeric hash of a specific repository)</li>
|
||||||
|
<li><strong>sandbox:r758</strong> (link to a changeset of another project)</li>
|
||||||
|
<li><strong>sandbox:commit:c6f4d0fd</strong> (link to a changeset with a non-numeric hash of another project)</li>
|
||||||
|
</ul></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Repository files:
|
<li>Repository files:
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -109,6 +117,7 @@
|
||||||
<li><strong>source:some/file@52#L120</strong> (link to line 120 of the file's revision 52)</li>
|
<li><strong>source:some/file@52#L120</strong> (link to line 120 of the file's revision 52)</li>
|
||||||
<li><strong>source:"some file@52#L120"</strong> (use double quotes when the URL contains spaces</li>
|
<li><strong>source:"some file@52#L120"</strong> (use double quotes when the URL contains spaces</li>
|
||||||
<li><strong>export:some/file</strong> (force the download of the file)</li>
|
<li><strong>export:some/file</strong> (force the download of the file)</li>
|
||||||
|
<li><strong>source:svn1|some/file</strong> (link to a file of a specific repository, for projects with multiple repositories)</li>
|
||||||
<li><strong>sandbox:source:some/file</strong> (link to the file located at /some/file in the repository of the project "sandbox")</li>
|
<li><strong>sandbox:source:some/file</strong> (link to the file located at /some/file in the repository of the project "sandbox")</li>
|
||||||
<li><strong>sandbox:export:some/file</strong> (force the download of the file)</li>
|
<li><strong>sandbox:export:some/file</strong> (force the download of the file)</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
|
|
|
@ -267,6 +267,7 @@ RAW
|
||||||
'version:1.0' => version_link,
|
'version:1.0' => version_link,
|
||||||
'version:"1.0"' => version_link,
|
'version:"1.0"' => version_link,
|
||||||
# source
|
# source
|
||||||
|
'source:some/file' => link_to('source:some/file', source_url, :class => 'source'),
|
||||||
'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
|
'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
|
||||||
'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
|
'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
|
||||||
'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
|
'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
|
||||||
|
@ -341,6 +342,72 @@ RAW
|
||||||
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
|
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_multiple_repositories_redmine_links
|
||||||
|
svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg')
|
||||||
|
Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
|
||||||
|
hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
|
||||||
|
Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
|
||||||
|
|
||||||
|
changeset_link = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
|
||||||
|
:class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
|
||||||
|
svn_changeset_link = link_to('svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123},
|
||||||
|
:class => 'changeset', :title => '')
|
||||||
|
hg_changeset_link = link_to('hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
|
||||||
|
:class => 'changeset', :title => '')
|
||||||
|
|
||||||
|
source_link = link_to('source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
|
||||||
|
hg_source_link = link_to('source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
|
||||||
|
|
||||||
|
to_test = {
|
||||||
|
'r2' => changeset_link,
|
||||||
|
'svn1|r123' => svn_changeset_link,
|
||||||
|
'invalid|r123' => 'invalid|r123',
|
||||||
|
'commit:hg1|abcd' => hg_changeset_link,
|
||||||
|
'commit:invalid|abcd' => 'commit:invalid|abcd',
|
||||||
|
# source
|
||||||
|
'source:some/file' => source_link,
|
||||||
|
'source:hg1|some/file' => hg_source_link,
|
||||||
|
'source:invalid|some/file' => 'source:invalid|some/file',
|
||||||
|
}
|
||||||
|
|
||||||
|
@project = Project.find(1)
|
||||||
|
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cross_project_multiple_repositories_redmine_links
|
||||||
|
svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg')
|
||||||
|
Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
|
||||||
|
hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
|
||||||
|
Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
|
||||||
|
|
||||||
|
changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
|
||||||
|
:class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
|
||||||
|
svn_changeset_link = link_to('ecookbook:svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123},
|
||||||
|
:class => 'changeset', :title => '')
|
||||||
|
hg_changeset_link = link_to('ecookbook:hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
|
||||||
|
:class => 'changeset', :title => '')
|
||||||
|
|
||||||
|
source_link = link_to('ecookbook:source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
|
||||||
|
hg_source_link = link_to('ecookbook:source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
|
||||||
|
|
||||||
|
to_test = {
|
||||||
|
'ecookbook:r2' => changeset_link,
|
||||||
|
'ecookbook:svn1|r123' => svn_changeset_link,
|
||||||
|
'ecookbook:invalid|r123' => 'ecookbook:invalid|r123',
|
||||||
|
'ecookbook:commit:hg1|abcd' => hg_changeset_link,
|
||||||
|
'ecookbook:commit:invalid|abcd' => 'ecookbook:commit:invalid|abcd',
|
||||||
|
'invalid:commit:invalid|abcd' => 'invalid:commit:invalid|abcd',
|
||||||
|
# source
|
||||||
|
'ecookbook:source:some/file' => source_link,
|
||||||
|
'ecookbook:source:hg1|some/file' => hg_source_link,
|
||||||
|
'ecookbook:source:invalid|some/file' => 'ecookbook:source:invalid|some/file',
|
||||||
|
'invalid:source:invalid|some/file' => 'invalid:source:invalid|some/file',
|
||||||
|
}
|
||||||
|
|
||||||
|
@project = Project.find(3)
|
||||||
|
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
|
||||||
|
end
|
||||||
|
|
||||||
def test_redmine_links_git_commit
|
def test_redmine_links_git_commit
|
||||||
changeset_link = link_to('abcd',
|
changeset_link = link_to('abcd',
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue