diff options
author | Douwe Maan <douwe@selenight.nl> | 2016-03-21 23:22:21 +0100 |
---|---|---|
committer | Douwe Maan <douwe@selenight.nl> | 2016-03-21 23:22:21 +0100 |
commit | ae7b2ef62cdf61c990f914d776a6fdfc2bc49fa2 (patch) | |
tree | 6f0022bf04b1b566fa79b979cc9cc373cd0ebaa1 /lib/gitlab | |
parent | 8d544645f0ef114586212835cf011a3e268c9ec1 (diff) | |
parent | 0305dd98b32b5a989f2b84e0810cf5ddc14abd7f (diff) | |
download | gitlab-ce-ae7b2ef62cdf61c990f914d776a6fdfc2bc49fa2.tar.gz |
Merge branch 'master' into issue_12658
# Conflicts:
# app/models/issue.rb
# app/views/projects/_home_panel.html.haml
# app/views/shared/projects/_project.html.haml
# db/schema.rb
# spec/models/project_spec.rb
Diffstat (limited to 'lib/gitlab')
-rw-r--r-- | lib/gitlab/gfm/reference_rewriter.rb | 79 | ||||
-rw-r--r-- | lib/gitlab/reference_extractor.rb | 18 |
2 files changed, 96 insertions, 1 deletions
diff --git a/lib/gitlab/gfm/reference_rewriter.rb b/lib/gitlab/gfm/reference_rewriter.rb new file mode 100644 index 00000000000..a1c6ee7bd69 --- /dev/null +++ b/lib/gitlab/gfm/reference_rewriter.rb @@ -0,0 +1,79 @@ +module Gitlab + module Gfm + ## + # Class that unfolds local references in text. + # + # The initializer takes text in Markdown and project this text is valid + # in context of. + # + # `unfold` method tries to find all local references and unfold each of + # those local references to cross reference format, assuming that the + # argument passed to this method is a project that references will be + # viewed from (see `Referable#to_reference method). + # + # Examples: + # + # 'Hello, this issue is related to #123 and + # other issues labeled with ~"label"', will be converted to: + # + # 'Hello, this issue is related to gitlab-org/gitlab-ce#123 and + # other issue labeled with gitlab-org/gitlab-ce~"label"'. + # + # It does respect markdown lexical rules, so text in code block will not be + # replaced, see another example: + # + # 'Merge request for issue #1234, see also link: + # http://gitlab.com/some/link/#1234, and code `puts #1234`' => + # + # 'Merge request for issue gitlab-org/gitlab-ce#1234, se also link: + # http://gitlab.com/some/link/#1234, and code `puts #1234`' + # + class ReferenceRewriter + def initialize(text, source_project, current_user) + @text = text + @source_project = source_project + @current_user = current_user + @original_html = markdown(text) + end + + def rewrite(target_project) + pattern = Gitlab::ReferenceExtractor.references_pattern + + @text.gsub(pattern) do |reference| + unfold_reference(reference, Regexp.last_match, target_project) + end + end + + private + + def unfold_reference(reference, match, target_project) + before = @text[0...match.begin(0)] + after = @text[match.end(0)..-1] + + referable = find_referable(reference) + return reference unless referable + + cross_reference = referable.to_reference(target_project) + return reference if reference == cross_reference + + new_text = before + cross_reference + after + substitution_valid?(new_text) ? cross_reference : reference + end + + def find_referable(reference) + extractor = Gitlab::ReferenceExtractor.new(@source_project, + @current_user) + extractor.analyze(reference) + extractor.all.first + end + + def substitution_valid?(substituted) + @original_html == markdown(substituted) + end + + def markdown(text) + Banzai.render(text, project: @source_project, no_original_data: true) + end + end + end +end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 4d830aa45e1..13c4d64c99b 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -1,6 +1,7 @@ module Gitlab # Extract possible GFM references from an arbitrary String for further processing. class ReferenceExtractor < Banzai::ReferenceExtractor + REFERABLES = %i(user issue label milestone merge_request snippet commit commit_range) attr_accessor :project, :current_user, :author def initialize(project, current_user = nil, author = nil) @@ -17,7 +18,7 @@ module Gitlab super(text, context.merge(project: project)) end - %i(user label milestone merge_request snippet commit commit_range).each do |type| + REFERABLES.each do |type| define_method("#{type}s") do @references[type] ||= references(type, reference_context) end @@ -31,6 +32,21 @@ module Gitlab end end + def all + REFERABLES.each { |referable| send(referable.to_s.pluralize) } + @references.values.flatten + end + + def self.references_pattern + return @pattern if @pattern + + patterns = REFERABLES.map do |ref| + ref.to_s.classify.constantize.try(:reference_pattern) + end + + @pattern = Regexp.union(patterns.compact) + end + private def reference_context |