Commit f881e4367753075bbdbfaca1ea83a6ef80549b72

Authored by Dmitriy Zaporozhets
2 parents f82d0d8d 9c046fea

Merge pull request #7024 from skv-headless/linkto_issues_on_main_dashboard

links to issues on main dashboard
app/helpers/gitlab_markdown_helper.rb
@@ -19,7 +19,7 @@ module GitlabMarkdownHelper @@ -19,7 +19,7 @@ module GitlabMarkdownHelper
19 escape_once(body) 19 escape_once(body)
20 end 20 end
21 21
22 - gfm_body = gfm(escaped_body, html_options) 22 + gfm_body = gfm(escaped_body, @project, html_options)
23 23
24 gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match| 24 gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match|
25 "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1 25 "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1
app/helpers/issues_helper.rb
@@ -13,76 +13,80 @@ module IssuesHelper @@ -13,76 +13,80 @@ module IssuesHelper
13 OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned') 13 OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned')
14 end 14 end
15 15
16 - def url_for_project_issues  
17 - return "" if @project.nil? 16 + def url_for_project_issues(project = @project)
  17 + return '' if project.nil?
18 18
19 - if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?  
20 - project_issues_path(@project) 19 + if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
  20 + project_issues_path(project)
21 else 21 else
22 - url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"]  
23 - url.gsub(':project_id', @project.id.to_s)  
24 - .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) 22 + url = Gitlab.config.issues_tracker[project.issues_tracker]['project_url']
  23 + url.gsub(':project_id', project.id.to_s).
  24 + gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
25 end 25 end
26 end 26 end
27 27
28 - def url_for_new_issue  
29 - return "" if @project.nil? 28 + def url_for_new_issue(project = @project)
  29 + return '' if project.nil?
30 30
31 - if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?  
32 - url = new_project_issue_path project_id: @project 31 + if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
  32 + url = new_project_issue_path project_id: project
33 else 33 else
34 - url = Gitlab.config.issues_tracker[@project.issues_tracker]["new_issue_url"]  
35 - url.gsub(':project_id', @project.id.to_s)  
36 - .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) 34 + issues_tracker = Gitlab.config.issues_tracker[project.issues_tracker]
  35 + url = issues_tracker['new_issue_url']
  36 + url.gsub(':project_id', project.id.to_s).
  37 + gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
37 end 38 end
38 end 39 end
39 40
40 - def url_for_issue(issue_iid)  
41 - return "" if @project.nil? 41 + def url_for_issue(issue_iid, project = @project)
  42 + return '' if project.nil?
42 43
43 - if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?  
44 - url = project_issue_url project_id: @project, id: issue_iid 44 + if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
  45 + url = project_issue_url project_id: project, id: issue_iid
45 else 46 else
46 - url = Gitlab.config.issues_tracker[@project.issues_tracker]["issues_url"]  
47 - url.gsub(':id', issue_iid.to_s)  
48 - .gsub(':project_id', @project.id.to_s)  
49 - .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) 47 + url = Gitlab.config.issues_tracker[project.issues_tracker]['issues_url']
  48 + url.gsub(':id', issue_iid.to_s).
  49 + gsub(':project_id', project.id.to_s).
  50 + gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
50 end 51 end
51 end 52 end
52 53
53 - def title_for_issue(issue_iid)  
54 - return "" if @project.nil? 54 + def title_for_issue(issue_iid, project = @project)
  55 + return '' if project.nil?
55 56
56 - if @project.used_default_issues_tracker? && issue = @project.issues.where(iid: issue_iid).first  
57 - issue.title  
58 - else  
59 - "" 57 + if project.used_default_issues_tracker?
  58 + issue = project.issues.where(iid: issue_iid).first
  59 + return issue.title if issue
60 end 60 end
  61 +
  62 + ''
61 end 63 end
62 64
63 # Checks if issues_tracker setting exists in gitlab.yml 65 # Checks if issues_tracker setting exists in gitlab.yml
64 def external_issues_tracker_enabled? 66 def external_issues_tracker_enabled?
65 - if Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?  
66 - true  
67 - else  
68 - false  
69 - end 67 + Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
70 end 68 end
71 69
72 def bulk_update_milestone_options 70 def bulk_update_milestone_options
73 - options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]) 71 + options_for_select(['None (backlog)']) +
  72 + options_from_collection_for_select(project_active_milestones, 'id',
  73 + 'title', params[:milestone_id])
74 end 74 end
75 75
76 - def bulk_update_assignee_options  
77 - options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]) 76 + def bulk_update_assignee_options(project = @project)
  77 + options_for_select(['None (unassigned)']) +
  78 + options_from_collection_for_select(project.team.members, 'id',
  79 + 'name', params[:assignee_id])
78 end 80 end
79 81
80 - def assignee_options object  
81 - options_from_collection_for_select(@project.team.members.sort_by(&:name), 'id', 'name', object.assignee_id) 82 + def assignee_options(object, project = @project)
  83 + options_from_collection_for_select(project.team.members.sort_by(&:name),
  84 + 'id', 'name', object.assignee_id)
82 end 85 end
83 86
84 def milestone_options object 87 def milestone_options object
85 - options_from_collection_for_select(object.project.milestones.active, 'id', 'title', object.milestone_id) 88 + options_from_collection_for_select(object.project.milestones.active,
  89 + 'id', 'title', object.milestone_id)
86 end 90 end
87 91
88 def issue_box_class(item) 92 def issue_box_class(item)
app/views/events/_commit.html.haml
@@ -2,4 +2,4 @@ @@ -2,4 +2,4 @@
2 .commit-row-title 2 .commit-row-title
3 = link_to commit[:id][0..8], project_commit_path(project, commit[:id]), class: "commit_short_id", alt: '' 3 = link_to commit[:id][0..8], project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
4 &nbsp; 4 &nbsp;
5 - = gfm event_commit_title(commit[:message]) 5 + = gfm event_commit_title(commit[:message]), project
lib/gitlab/markdown.rb
@@ -33,10 +33,9 @@ module Gitlab @@ -33,10 +33,9 @@ module Gitlab
33 # Public: Parse the provided text with GitLab-Flavored Markdown 33 # Public: Parse the provided text with GitLab-Flavored Markdown
34 # 34 #
35 # text - the source text 35 # text - the source text
  36 + # project - extra options for the reference links as given to link_to
36 # html_options - extra options for the reference links as given to link_to 37 # html_options - extra options for the reference links as given to link_to
37 - #  
38 - # Note: reference links will only be generated if @project is set  
39 - def gfm(text, html_options = {}) 38 + def gfm(text, project = @project, html_options = {})
40 return text if text.nil? 39 return text if text.nil?
41 40
42 # Duplicate the string so we don't alter the original, then call to_str 41 # Duplicate the string so we don't alter the original, then call to_str
@@ -56,14 +55,19 @@ module Gitlab @@ -56,14 +55,19 @@ module Gitlab
56 55
57 # TODO: add popups with additional information 56 # TODO: add popups with additional information
58 57
59 - text = parse(text) 58 + text = parse(text, project)
60 59
61 # Insert pre block extractions 60 # Insert pre block extractions
62 text.gsub!(/\{gfm-extraction-(\h{32})\}/) do 61 text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
63 insert_piece($1) 62 insert_piece($1)
64 end 63 end
65 64
66 - sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class), tags: ActionView::Base.sanitized_allowed_tags + %w(table tr td th) 65 + allowed_attributes = ActionView::Base.sanitized_allowed_attributes
  66 + allowed_tags = ActionView::Base.sanitized_allowed_tags
  67 +
  68 + sanitize text.html_safe,
  69 + attributes: allowed_attributes + %w(id class),
  70 + tags: allowed_tags + %w(table tr td th)
67 end 71 end
68 72
69 private 73 private
@@ -84,11 +88,9 @@ module Gitlab @@ -84,11 +88,9 @@ module Gitlab
84 # 88 #
85 # text - Text to parse 89 # text - Text to parse
86 # 90 #
87 - # Note: reference links will only be generated if @project is set  
88 - #  
89 # Returns parsed text 91 # Returns parsed text
90 - def parse(text)  
91 - parse_references(text) if @project 92 + def parse(text, project = @project)
  93 + parse_references(text, project) if project
92 parse_emoji(text) 94 parse_emoji(text)
93 95
94 text 96 text
@@ -110,7 +112,7 @@ module Gitlab @@ -110,7 +112,7 @@ module Gitlab
110 112
111 TYPES = [:user, :issue, :merge_request, :snippet, :commit].freeze 113 TYPES = [:user, :issue, :merge_request, :snippet, :commit].freeze
112 114
113 - def parse_references(text) 115 + def parse_references(text, project = @project)
114 # parse reference links 116 # parse reference links
115 text.gsub!(REFERENCE_PATTERN) do |match| 117 text.gsub!(REFERENCE_PATTERN) do |match|
116 prefix = $~[:prefix] 118 prefix = $~[:prefix]
@@ -123,7 +125,7 @@ module Gitlab @@ -123,7 +125,7 @@ module Gitlab
123 # Avoid HTML entities 125 # Avoid HTML entities
124 if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';' 126 if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
125 match 127 match
126 - elsif ref_link = reference_link(type, identifier) 128 + elsif ref_link = reference_link(type, identifier, project)
127 "#{prefix}#{ref_link}#{suffix}" 129 "#{prefix}#{ref_link}#{suffix}"
128 else 130 else
129 match 131 match
@@ -153,7 +155,7 @@ module Gitlab @@ -153,7 +155,7 @@ module Gitlab
153 # 155 #
154 # Returns boolean 156 # Returns boolean
155 def valid_emoji?(emoji) 157 def valid_emoji?(emoji)
156 - Emoji.find_by_name emoji 158 + Emoji.find_by_name(emoji)
157 end 159 end
158 160
159 # Private: Dispatches to a dedicated processing method based on reference 161 # Private: Dispatches to a dedicated processing method based on reference
@@ -162,52 +164,77 @@ module Gitlab @@ -162,52 +164,77 @@ module Gitlab
162 # identifier - Object identifier (Issue ID, SHA hash, etc.) 164 # identifier - Object identifier (Issue ID, SHA hash, etc.)
163 # 165 #
164 # Returns string rendered by the processing method 166 # Returns string rendered by the processing method
165 - def reference_link(type, identifier)  
166 - send("reference_#{type}", identifier) 167 + def reference_link(type, identifier, project = @project)
  168 + send("reference_#{type}", identifier, project)
167 end 169 end
168 170
169 - def reference_user(identifier)  
170 - if user = User.find_by_username(identifier)  
171 - link_to("@#{identifier}", user_url(identifier), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) 171 + def reference_user(identifier, project = @project)
  172 + if user = User.find_by(username: identifier)
  173 + options = html_options.merge(
  174 + class: "gfm gfm-team_member #{html_options[:class]}"
  175 + )
  176 + link_to("@#{identifier}", user_url(identifier), options)
172 end 177 end
173 end 178 end
174 179
175 - def reference_issue(identifier)  
176 - if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?  
177 - if @project.issue_exists? identifier  
178 - url = url_for_issue(identifier) 180 + def reference_issue(identifier, project = @project)
  181 + if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
  182 + if project.issue_exists? identifier
  183 + url = url_for_issue(identifier, project)
179 title = title_for_issue(identifier) 184 title = title_for_issue(identifier)
  185 + options = html_options.merge(
  186 + title: "Issue: #{title}",
  187 + class: "gfm gfm-issue #{html_options[:class]}"
  188 + )
180 189
181 - link_to("##{identifier}", url, html_options.merge(title: "Issue: #{title}", class: "gfm gfm-issue #{html_options[:class]}")) 190 + link_to("##{identifier}", url, options)
182 end 191 end
183 - else  
184 - reference_jira_issue(identifier) if @project.issues_tracker == "jira" 192 + elsif project.issues_tracker == 'jira'
  193 + reference_jira_issue(identifier, project)
185 end 194 end
186 end 195 end
187 196
188 - def reference_merge_request(identifier)  
189 - if merge_request = @project.merge_requests.where(iid: identifier).first  
190 - link_to("!#{identifier}", project_merge_request_url(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) 197 + def reference_merge_request(identifier, project = @project)
  198 + if merge_request = project.merge_requests.find_by(iid: identifier)
  199 + options = html_options.merge(
  200 + title: "Merge Request: #{merge_request.title}",
  201 + class: "gfm gfm-merge_request #{html_options[:class]}"
  202 + )
  203 + url = project_merge_request_url(project, merge_request)
  204 + link_to("!#{identifier}", url, options)
191 end 205 end
192 end 206 end
193 207
194 - def reference_snippet(identifier)  
195 - if snippet = @project.snippets.where(id: identifier).first  
196 - link_to("$#{identifier}", project_snippet_url(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) 208 + def reference_snippet(identifier, project = @project)
  209 + if snippet = project.snippets.find_by(id: identifier)
  210 + options = html_options.merge(
  211 + title: "Snippet: #{snippet.title}",
  212 + class: "gfm gfm-snippet #{html_options[:class]}"
  213 + )
  214 + link_to("$#{identifier}", project_snippet_url(project, snippet),
  215 + options)
197 end 216 end
198 end 217 end
199 218
200 - def reference_commit(identifier)  
201 - if @project.valid_repo? && commit = @project.repository.commit(identifier)  
202 - link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: commit.link_title, class: "gfm gfm-commit #{html_options[:class]}")) 219 + def reference_commit(identifier, project = @project)
  220 + if project.valid_repo? && commit = project.repository.commit(identifier)
  221 + options = html_options.merge(
  222 + title: commit.link_title,
  223 + class: "gfm gfm-commit #{html_options[:class]}"
  224 + )
  225 + link_to(identifier, project_commit_url(project, commit), options)
203 end 226 end
204 end 227 end
205 228
206 - def reference_jira_issue(identifier) 229 + def reference_jira_issue(identifier, project = @project)
207 url = url_for_issue(identifier) 230 url = url_for_issue(identifier)
208 title = Gitlab.config.issues_tracker[@project.issues_tracker]["title"] 231 title = Gitlab.config.issues_tracker[@project.issues_tracker]["title"]
209 232
210 - link_to("#{identifier}", url, html_options.merge(title: "Issue in #{title}", class: "gfm gfm-issue #{html_options[:class]}")) 233 + options = html_options.merge(
  234 + title: "Issue in #{title}",
  235 + class: "gfm gfm-issue #{html_options[:class]}"
  236 + )
  237 + link_to("#{identifier}", url, options)
211 end 238 end
212 end 239 end
213 end 240 end
lib/gitlab/reference_extractor.rb
@@ -51,7 +51,7 @@ module Gitlab @@ -51,7 +51,7 @@ module Gitlab
51 51
52 private 52 private
53 53
54 - def reference_link type, identifier 54 + def reference_link(type, identifier, project)
55 # Append identifier to the appropriate collection. 55 # Append identifier to the appropriate collection.
56 send("#{type}s") << identifier 56 send("#{type}s") << identifier
57 end 57 end
spec/helpers/gitlab_markdown_helper_spec.rb
@@ -41,7 +41,8 @@ describe GitlabMarkdownHelper do @@ -41,7 +41,8 @@ describe GitlabMarkdownHelper do
41 end 41 end
42 42
43 it "should forward HTML options to links" do 43 it "should forward HTML options to links" do
44 - gfm("Fixed in #{commit.id}", class: "foo").should have_selector("a.gfm.foo") 44 + gfm("Fixed in #{commit.id}", @project, class: 'foo').
  45 + should have_selector('a.gfm.foo')
45 end 46 end
46 47
47 describe "referencing a commit" do 48 describe "referencing a commit" do