diff options
-rw-r--r-- | app/services/issues/move_service.rb | 7 | ||||
-rw-r--r-- | lib/banzai/filter/reference_unfold_filter.rb | 42 | ||||
-rw-r--r-- | lib/banzai/pipeline/reference_unfold_pipeline.rb | 21 | ||||
-rw-r--r-- | lib/gitlab/gfm/reference_unfolder.rb | 31 | ||||
-rw-r--r-- | lib/gitlab/reference_extractor.rb | 8 | ||||
-rw-r--r-- | spec/lib/banzai/pipeline/reference_unfold_pipeline_spec.rb | 62 | ||||
-rw-r--r-- | spec/lib/gitlab/gfm/reference_unfolder_spec.rb | 43 | ||||
-rw-r--r-- | spec/lib/gitlab/reference_extractor_spec.rb | 12 |
8 files changed, 95 insertions, 131 deletions
diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb index a9448af4699..de12ea5c172 100644 --- a/app/services/issues/move_service.rb +++ b/app/services/issues/move_service.rb @@ -83,11 +83,8 @@ module Issues def rewrite_references(noteable) content = noteable_content(noteable).dup - context = { pipeline: :reference_unfold, - project: @project_old, new_project: @project_new } - - new_content = Banzai.render_result(content, context) - new_content[:output].to_s + unfolder = Gitlab::Gfm::ReferenceUnfolder.new(content, @project_old) + unfolder.unfold(@project_new) end def noteable_content(noteable) diff --git a/lib/banzai/filter/reference_unfold_filter.rb b/lib/banzai/filter/reference_unfold_filter.rb deleted file mode 100644 index 70a485ba2ae..00000000000 --- a/lib/banzai/filter/reference_unfold_filter.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'html/pipeline/filter' - -module Banzai - module Filter - ## - # Filter than unfolds local references. - # - # - class ReferenceUnfoldFilter < HTML::Pipeline::Filter - def initialize(*) - super - - unless result[:references].is_a?(Hash) - raise StandardError, 'References not processed!' - end - - @text = context[:text].dup - @new_project = context[:new_project] - @referables = result[:references].values.flatten - end - - def call - @referables.each do |referable| - next unless referable.respond_to?(:to_reference) - - pattern = /#{Regexp.escape(referable.to_reference)}/ - @text.gsub!(pattern, referable.to_reference(@new_project)) - end - - @text - end - - private - - def validate - needs :project - needs :new_project - needs :text - end - end - end -end diff --git a/lib/banzai/pipeline/reference_unfold_pipeline.rb b/lib/banzai/pipeline/reference_unfold_pipeline.rb deleted file mode 100644 index 597bf7befd1..00000000000 --- a/lib/banzai/pipeline/reference_unfold_pipeline.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Banzai - module Pipeline - class ReferenceUnfoldPipeline < BasePipeline - def self.filters - FullPipeline.filters + - [Filter::ReferenceGathererFilter, - Filter::ReferenceUnfoldFilter] - end - - def self.call(text, context = {}) - context = context.merge(text: text) - super - end - - class << self - alias_method :to_document, :call - alias_method :to_html, :call - end - end - end -end diff --git a/lib/gitlab/gfm/reference_unfolder.rb b/lib/gitlab/gfm/reference_unfolder.rb new file mode 100644 index 00000000000..4969e8ebe85 --- /dev/null +++ b/lib/gitlab/gfm/reference_unfolder.rb @@ -0,0 +1,31 @@ +module Gitlab + module Gfm + ## + # Class than unfolds local references in text. + # + # + class ReferenceUnfolder + def initialize(text, project) + @text = text + @project = project + end + + def unfold(from_project) + referables.each_with_object(@text.dup) do |referable, text| + next unless referable.respond_to?(:to_reference) + + pattern = /#{Regexp.escape(referable.to_reference)}/ + text.gsub!(pattern, referable.to_reference(from_project)) + end + end + + private + + def referables + extractor = Gitlab::ReferenceExtractor.new(@project) + extractor.analyze(@text) + extractor.all + end + end + end +end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 4d830aa45e1..8c698d43bef 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,11 @@ module Gitlab end end + def all + REFERABLES.each { |referable| send(referable.to_s.pluralize) } + @references.values.flatten + end + private def reference_context diff --git a/spec/lib/banzai/pipeline/reference_unfold_pipeline_spec.rb b/spec/lib/banzai/pipeline/reference_unfold_pipeline_spec.rb deleted file mode 100644 index c02dc5a2c2c..00000000000 --- a/spec/lib/banzai/pipeline/reference_unfold_pipeline_spec.rb +++ /dev/null @@ -1,62 +0,0 @@ -require 'spec_helper' - -describe Banzai::Pipeline::ReferenceUnfoldPipeline do - let(:text) { 'some text' } - let(:old_project) { create(:project) } - let(:new_project) { create(:project) } - let(:pipeline_context) do - { project: old_project, new_project: new_project } - end - - let(:result) do - described_class.to_document(text, pipeline_context) - end - - context 'invalid initializers' do - subject { -> { result } } - - context 'project context is missing' do - let(:pipeline_context) { { new_project: new_project } } - it { is_expected.to raise_error ArgumentError, /Missing context keys/ } - end - - context 'new project context is missing' do - let(:pipeline_context) { { project: old_project } } - it { is_expected.to raise_error ArgumentError, /Missing context keys/ } - end - end - - context 'multiple issues and merge requests referenced' do - subject { result[:output] } - - let!(:issue_first) { create(:issue, project: old_project) } - let!(:issue_second) { create(:issue, project: old_project) } - let!(:merge_request) { create(:merge_request, source_project: old_project) } - - context 'plain text description' do - let(:text) { 'Description that references #1, #2 and !1' } - - it { is_expected.to include issue_first.to_reference(new_project) } - it { is_expected.to include issue_second.to_reference(new_project) } - it { is_expected.to include merge_request.to_reference(new_project) } - end - - context 'description with ignored elements' do - let(:text) do - "Hi. This references #1, but not `#2`\n" + - '<pre>and not !1</pre>' - end - - it { is_expected.to include issue_first.to_reference(new_project) } - it { is_expected.to_not include issue_second.to_reference(new_project) } - it { is_expected.to_not include merge_request.to_reference(new_project) } - end - - context 'description ambigous elements' do - let(:url) { 'http://gitlab.com/#1' } - let(:text) { "This references #1, but not #{url}" } - - it { is_expected.to include url } - end - end -end diff --git a/spec/lib/gitlab/gfm/reference_unfolder_spec.rb b/spec/lib/gitlab/gfm/reference_unfolder_spec.rb new file mode 100644 index 00000000000..4f8b960350c --- /dev/null +++ b/spec/lib/gitlab/gfm/reference_unfolder_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe Gitlab::Gfm::ReferenceUnfolder do + let(:text) { 'some text' } + let(:old_project) { create(:project) } + let(:new_project) { create(:project) } + + describe '#unfold' do + subject { described_class.new(text, old_project).unfold(new_project) } + + context 'multiple issues and merge requests referenced' do + let!(:issue_first) { create(:issue, project: old_project) } + let!(:issue_second) { create(:issue, project: old_project) } + let!(:merge_request) { create(:merge_request, source_project: old_project) } + + context 'plain text description' do + let(:text) { 'Description that references #1, #2 and !1' } + + it { is_expected.to include issue_first.to_reference(new_project) } + it { is_expected.to include issue_second.to_reference(new_project) } + it { is_expected.to include merge_request.to_reference(new_project) } + end + + context 'description with ignored elements' do + let(:text) do + "Hi. This references #1, but not `#2`\n" + + '<pre>and not !1</pre>' + end + + it { is_expected.to include issue_first.to_reference(new_project) } + it { is_expected.to_not include issue_second.to_reference(new_project) } + it { is_expected.to_not include merge_request.to_reference(new_project) } + end + + context 'description ambigous elements' do + let(:url) { 'http://gitlab.com/#1' } + let(:text) { "This references #1, but not #{url}" } + + it { is_expected.to include url } + end + end + end +end diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 7d963795e17..78ab162e5d6 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -122,4 +122,16 @@ describe Gitlab::ReferenceExtractor, lib: true do expect(extracted).to match_array([issue]) end end + + describe '#all' do + let(:issue) { create(:issue, project: project) } + let(:label) { create(:label, project: project) } + let(:text) { "Ref. #{issue.to_reference} and #{label.to_reference}" } + + before { subject.analyze(text) } + + it 'returns all referables' do + expect(subject.all).to match_array([issue, label]) + end + end end |