##// END OF EJS Templates
Adds support for multiple repositories to redmine links (#779)....
Jean-Philippe Lang -
r8574:f2e7aa596b4e
parent child
Show More
@@ -655,19 +655,27 module ApplicationHelper
655 # identifier:version:1.0.0
655 # identifier:version:1.0.0
656 # identifier:source:some/file
656 # identifier:source:some/file
657 def parse_redmine_links(text, project, obj, attr, only_path, options)
657 def parse_redmine_links(text, project, obj, attr, only_path, options)
658 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|
658 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|
659 leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
659 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
660 link = nil
660 link = nil
661 if project_identifier
661 if project_identifier
662 project = Project.visible.find_by_identifier(project_identifier)
662 project = Project.visible.find_by_identifier(project_identifier)
663 end
663 end
664 if esc.nil?
664 if esc.nil?
665 if prefix.nil? && sep == 'r'
665 if prefix.nil? && sep == 'r'
666 # project.changesets.visible raises an SQL error because of a double join on repositories
666 if project
667 if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier))
667 repository = nil
668 link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
668 if repo_identifier
669 :class => 'changeset',
669 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
670 :title => truncate_single_line(changeset.comments, :length => 100))
670 else
671 repository = project.repository
672 end
673 # project.changesets.visible raises an SQL error because of a double join on repositories
674 if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier))
675 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},
676 :class => 'changeset',
677 :title => truncate_single_line(changeset.comments, :length => 100))
678 end
671 end
679 end
672 elsif sep == '#'
680 elsif sep == '#'
673 oid = identifier.to_i
681 oid = identifier.to_i
@@ -731,22 +739,34 module ApplicationHelper
731 link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
739 link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
732 :class => 'news'
740 :class => 'news'
733 end
741 end
734 when 'commit'
742 when 'commit', 'source', 'export'
735 if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
743 if project
736 link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
744 repository = nil
737 :class => 'changeset',
745 if name =~ %r{^(([a-z0-9\-]+)\|)(.+)$}
738 :title => truncate_single_line(h(changeset.comments), :length => 100)
746 repo_prefix, repo_identifier, name = $1, $2, $3
739 end
747 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
740 when 'source', 'export'
748 else
741 if project && project.repository && User.current.allowed_to?(:browse_repository, project)
749 repository = project.repository
742 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
750 end
743 path, rev, anchor = $1, $3, $5
751 if prefix == 'commit'
744 link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
752 if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"]))
745 :path => to_path_param(path),
753 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},
746 :rev => rev,
754 :class => 'changeset',
747 :anchor => anchor,
755 :title => truncate_single_line(h(changeset.comments), :length => 100)
748 :format => (prefix == 'export' ? 'raw' : nil)},
756 end
749 :class => (prefix == 'export' ? 'source download' : 'source')
757 else
758 if repository && User.current.allowed_to?(:browse_repository, project)
759 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
760 path, rev, anchor = $1, $3, $5
761 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, :repository_id => repository.identifier_param,
762 :path => to_path_param(path),
763 :rev => rev,
764 :anchor => anchor,
765 :format => (prefix == 'export' ? 'raw' : nil)},
766 :class => (prefix == 'export' ? 'source download' : 'source')
767 end
768 end
769 repo_prefix = nil
750 end
770 end
751 when 'attachment'
771 when 'attachment'
752 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
772 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
@@ -761,7 +781,7 module ApplicationHelper
761 end
781 end
762 end
782 end
763 end
783 end
764 (leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")).html_safe
784 (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}")).html_safe
765 end
785 end
766 end
786 end
767
787
@@ -44,13 +44,9
44
44
45 <h3><a name="3" class="wiki-page"></a>Redmine links</h3>
45 <h3><a name="3" class="wiki-page"></a>Redmine links</h3>
46
46
47 <p>Redmine allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.</p>
47 <p>Redmine allows hyperlinking between resources (issues, changesets, wiki pages...) from anywhere wiki formatting is used.</p>
48 <ul>
48 <ul>
49 <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>
49 <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>
50 <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>
51 <li>Link to a changeset with a non-numeric hash: <strong>commit:c6f4d0fd</strong> (displays <a href="#" class="changeset">c6f4d0fd</a>).</li>
52 <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>
53 <li>Link to a changeset with a non-numeric hash: <strong>sandbox:c6f4d0fd</strong> (displays <a href="#" class="changeset">sandbox:c6f4d0fd</a>).</li>
54 </ul>
50 </ul>
55
51
56 <p>Wiki links:</p>
52 <p>Wiki links:</p>
@@ -101,6 +97,18
101 </ul>
97 </ul>
102
98
103 <ul>
99 <ul>
100 <li>Changesets:
101 <ul>
102 <li><strong>r758</strong> (link to a changeset)</li>
103 <li><strong>commit:c6f4d0fd</strong> (link to a changeset with a non-numeric hash)</li>
104 <li><strong>svn1|r758</strong> (link to a changeset of a specific repository, for projects with multiple repositories)</li>
105 <li><strong>commit:hg|c6f4d0fd</strong> (link to a changeset with a non-numeric hash of a specific repository)</li>
106 <li><strong>sandbox:r758</strong> (link to a changeset of another project)</li>
107 <li><strong>sandbox:commit:c6f4d0fd</strong> (link to a changeset with a non-numeric hash of another project)</li>
108 </ul></li>
109 </ul>
110
111 <ul>
104 <li>Repository files:
112 <li>Repository files:
105 <ul>
113 <ul>
106 <li><strong>source:some/file</strong> (link to the file located at /some/file in the project's repository)</li>
114 <li><strong>source:some/file</strong> (link to the file located at /some/file in the project's repository)</li>
@@ -109,6 +117,7
109 <li><strong>source:some/file@52#L120</strong> (link to line 120 of the file's revision 52)</li>
117 <li><strong>source:some/file@52#L120</strong> (link to line 120 of the file's revision 52)</li>
110 <li><strong>source:"some file@52#L120"</strong> (use double quotes when the URL contains spaces</li>
118 <li><strong>source:"some file@52#L120"</strong> (use double quotes when the URL contains spaces</li>
111 <li><strong>export:some/file</strong> (force the download of the file)</li>
119 <li><strong>export:some/file</strong> (force the download of the file)</li>
120 <li><strong>source:svn1|some/file</strong> (link to a file of a specific repository, for projects with multiple repositories)</li>
112 <li><strong>sandbox:source:some/file</strong> (link to the file located at /some/file in the repository of the project "sandbox")</li>
121 <li><strong>sandbox:source:some/file</strong> (link to the file located at /some/file in the repository of the project "sandbox")</li>
113 <li><strong>sandbox:export:some/file</strong> (force the download of the file)</li>
122 <li><strong>sandbox:export:some/file</strong> (force the download of the file)</li>
114 </ul></li>
123 </ul></li>
@@ -267,6 +267,7 RAW
267 'version:1.0' => version_link,
267 'version:1.0' => version_link,
268 'version:"1.0"' => version_link,
268 'version:"1.0"' => version_link,
269 # source
269 # source
270 'source:some/file' => link_to('source:some/file', source_url, :class => 'source'),
270 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
271 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
271 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
272 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
272 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
273 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
@@ -341,6 +342,72 RAW
341 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
342 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
342 end
343 end
343
344
345 def test_multiple_repositories_redmine_links
346 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg')
347 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
348 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
349 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
350
351 changeset_link = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
352 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
353 svn_changeset_link = link_to('svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123},
354 :class => 'changeset', :title => '')
355 hg_changeset_link = link_to('hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
356 :class => 'changeset', :title => '')
357
358 source_link = link_to('source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
359 hg_source_link = link_to('source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
360
361 to_test = {
362 'r2' => changeset_link,
363 'svn1|r123' => svn_changeset_link,
364 'invalid|r123' => 'invalid|r123',
365 'commit:hg1|abcd' => hg_changeset_link,
366 'commit:invalid|abcd' => 'commit:invalid|abcd',
367 # source
368 'source:some/file' => source_link,
369 'source:hg1|some/file' => hg_source_link,
370 'source:invalid|some/file' => 'source:invalid|some/file',
371 }
372
373 @project = Project.find(1)
374 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
375 end
376
377 def test_cross_project_multiple_repositories_redmine_links
378 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg')
379 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
380 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
381 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
382
383 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
384 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
385 svn_changeset_link = link_to('ecookbook:svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123},
386 :class => 'changeset', :title => '')
387 hg_changeset_link = link_to('ecookbook:hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
388 :class => 'changeset', :title => '')
389
390 source_link = link_to('ecookbook:source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
391 hg_source_link = link_to('ecookbook:source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
392
393 to_test = {
394 'ecookbook:r2' => changeset_link,
395 'ecookbook:svn1|r123' => svn_changeset_link,
396 'ecookbook:invalid|r123' => 'ecookbook:invalid|r123',
397 'ecookbook:commit:hg1|abcd' => hg_changeset_link,
398 'ecookbook:commit:invalid|abcd' => 'ecookbook:commit:invalid|abcd',
399 'invalid:commit:invalid|abcd' => 'invalid:commit:invalid|abcd',
400 # source
401 'ecookbook:source:some/file' => source_link,
402 'ecookbook:source:hg1|some/file' => hg_source_link,
403 'ecookbook:source:invalid|some/file' => 'ecookbook:source:invalid|some/file',
404 'invalid:source:invalid|some/file' => 'invalid:source:invalid|some/file',
405 }
406
407 @project = Project.find(3)
408 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
409 end
410
344 def test_redmine_links_git_commit
411 def test_redmine_links_git_commit
345 changeset_link = link_to('abcd',
412 changeset_link = link_to('abcd',
346 {
413 {
General Comments 0
You need to be logged in to leave comments. Login now