summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2012-01-22 14:23:10 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2012-01-22 14:23:10 +0000
commitf2e7aa596b4e9676d40019afbbdce6e0d944f442 (patch)
treeee7b3cbd47c90a1c8baf4e4bb33509dd54eaddab
parent13f28858baf5965502456d25142631744aa69ce0 (diff)
downloadredmine-f2e7aa596b4e9676d40019afbbdce6e0d944f442.tar.gz
redmine-f2e7aa596b4e9676d40019afbbdce6e0d944f442.zip
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
-rw-r--r--app/helpers/application_helper.rb68
-rw-r--r--public/help/wiki_syntax_detailed.html19
-rw-r--r--test/unit/helpers/application_helper_test.rb67
3 files changed, 125 insertions, 29 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index c3f0d4876..fcfb2e781 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -655,19 +655,27 @@ module ApplicationHelper
# identifier:version:1.0.0
# identifier:source:some/file
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|
- leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
+ 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, repo_prefix, repo_identifier, sep, identifier = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $14, $13 || $15
link = nil
if project_identifier
project = Project.visible.find_by_identifier(project_identifier)
end
if esc.nil?
if prefix.nil? && sep == 'r'
- # 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))
- link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
- :class => 'changeset',
- :title => truncate_single_line(changeset.comments, :length => 100))
+ 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
+ if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier))
+ 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',
+ :title => truncate_single_line(changeset.comments, :length => 100))
+ end
end
elsif sep == '#'
oid = identifier.to_i
@@ -731,22 +739,34 @@ module ApplicationHelper
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
:class => 'news'
end
- when 'commit'
- if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
- link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
- :class => 'changeset',
- :title => truncate_single_line(h(changeset.comments), :length => 100)
- end
- when 'source', 'export'
- if project && project.repository && User.current.allowed_to?(:browse_repository, project)
- name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
- path, rev, anchor = $1, $3, $5
- link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
- :path => to_path_param(path),
- :rev => rev,
- :anchor => anchor,
- :format => (prefix == 'export' ? 'raw' : nil)},
- :class => (prefix == 'export' ? 'source download' : 'source')
+ when 'commit', 'source', 'export'
+ if project
+ 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',
+ :title => truncate_single_line(h(changeset.comments), :length => 100)
+ end
+ else
+ if repository && User.current.allowed_to?(:browse_repository, project)
+ name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
+ path, rev, anchor = $1, $3, $5
+ 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),
+ :rev => rev,
+ :anchor => anchor,
+ :format => (prefix == 'export' ? 'raw' : nil)},
+ :class => (prefix == 'export' ? 'source download' : 'source')
+ end
+ end
+ repo_prefix = nil
end
when 'attachment'
attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
@@ -761,7 +781,7 @@ module ApplicationHelper
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
diff --git a/public/help/wiki_syntax_detailed.html b/public/help/wiki_syntax_detailed.html
index 048edbd3a..18a822c58 100644
--- a/public/help/wiki_syntax_detailed.html
+++ b/public/help/wiki_syntax_detailed.html
@@ -44,13 +44,9 @@
<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>
<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>
<p>Wiki links:</p>
@@ -101,6 +97,18 @@
</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>
<li>Repository files:
<ul>
<li><strong>source:some/file</strong> (link to the file located at /some/file in the project's repository)</li>
@@ -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> (use double quotes when the URL contains spaces</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:export:some/file</strong> (force the download of the file)</li>
</ul></li>
diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb
index 3d98aafe8..20e458b7b 100644
--- a/test/unit/helpers/application_helper_test.rb
+++ b/test/unit/helpers/application_helper_test.rb
@@ -267,6 +267,7 @@ RAW
'version:1.0' => version_link,
'version:"1.0"' => version_link,
# 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') + ".",
@@ -341,6 +342,72 @@ RAW
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
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
changeset_link = link_to('abcd',
{