Skip to content
Snippets Groups Projects
Commit fd8394fa authored by Grzegorz Bizon's avatar Grzegorz Bizon
Browse files

Move reference unfolder for GFM to separate class

parent cd0f1945
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -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)
Loading
Loading
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
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
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
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)
Loading
Loading
@@ -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
Loading
Loading
@@ -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
Loading
Loading
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
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
Loading
Loading
@@ -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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment