diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-01-22 14:23:10 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-01-22 14:23:10 +0000 |
commit | f2e7aa596b4e9676d40019afbbdce6e0d944f442 (patch) | |
tree | ee7b3cbd47c90a1c8baf4e4bb33509dd54eaddab | |
parent | 13f28858baf5965502456d25142631744aa69ce0 (diff) | |
download | redmine-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.rb | 68 | ||||
-rw-r--r-- | public/help/wiki_syntax_detailed.html | 19 | ||||
-rw-r--r-- | test/unit/helpers/application_helper_test.rb | 67 |
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', { |