diff --git a/app/models/group.rb b/app/models/group.rb index d38971c83f34c731c6fa5fe05bffa9c1db665b91..5cc5e0ab6be6db7f7405ca3629febde5c89699fa 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -502,12 +502,6 @@ def human_name full_name end - def to_human_reference(from = nil) - return unless cross_namespace_reference?(from) - - human_name - end - def visibility_level_allowed_by_parent?(level = self.visibility_level) return true unless parent_id && parent_id.nonzero? diff --git a/ee/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/ee/spec/lib/gitlab/gfm/reference_rewriter_spec.rb deleted file mode 100644 index aeea856a4b5456311dc5689d3f90cc18c6a3e1d4..0000000000000000000000000000000000000000 --- a/ee/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ /dev/null @@ -1,236 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::Gfm::ReferenceRewriter, feature_category: :team_planning do - describe '#rewrite with table syntax' do - using RSpec::Parameterized::TableSyntax - - let_it_be(:parent_group1) { create(:group, path: "parent-group-one") } - let_it_be(:parent_group2) { create(:group, path: "parent-group-two") } - let_it_be(:user) { create(:user) } - - let_it_be(:source_project) { create(:project, path: 'old-project', group: parent_group1) } - let_it_be(:target_project1) { create(:project, path: 'new-project', group: parent_group1) } - let_it_be(:target_project2) { create(:project, path: 'new-project', group: parent_group2) } - let_it_be(:source_group) { create(:group, path: 'old-group', parent: parent_group1) } - let_it_be(:target_group1) { create(:group, path: 'new-group', parent: parent_group1) } - let_it_be(:target_group2) { create(:group, path: 'new-group', parent: parent_group2) } - - let_it_be(:work_item_project_first) { create(:issue, project: source_project) } - let_it_be(:work_item_group_first) { create(:issue, :group_level, namespace: source_group) } - - let_it_be(:merge_request) { create(:merge_request, source_project: source_project) } - - let_it_be(:project_label) { create(:label, id: 123, name: 'pr label1', project: source_project) } - let_it_be(:parent_group_label) { create(:group_label, id: 321, name: 'gr label1', group: parent_group1) } - - let_it_be(:project_milestone) { create(:milestone, title: 'project milestone', project: source_project) } - let_it_be(:parent_group_milestone) { create(:milestone, title: 'group milestone', group: parent_group1) } - - before_all do - parent_group1.add_reporter(user) - parent_group2.add_reporter(user) - end - - context 'with source as Project and target as Project within same parent group' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_project1 } # 'parent-group-one/new-project' - - where(:source_text, :destination_text) do - # group level work item reference - 'ref parent-group-one/old-group#1' | 'ref parent-group-one/old-group#1' - 'ref parent-group-one/old-group#1+' | 'ref parent-group-one/old-group#1+' - 'ref parent-group-one/old-group#1+s' | 'ref parent-group-one/old-group#1+s' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Project and target as Project within different parent groups' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_project2 } # 'parent-group-two/new-project' - - where(:source_text, :destination_text) do - # group level work item reference - 'ref parent-group-one/old-group#1' | 'ref parent-group-one/old-group#1' - 'ref parent-group-one/old-group#1+' | 'ref parent-group-one/old-group#1+' - 'ref parent-group-one/old-group#1+s' | 'ref parent-group-one/old-group#1+s' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Project and target as Group within same parent group' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_group1 } # 'parent-group-one/new-group' - - where(:source_text, :destination_text) do - # group level work item reference - 'ref parent-group-one/old-group#1' | 'ref parent-group-one/old-group#1' - 'ref parent-group-one/old-group#1+' | 'ref parent-group-one/old-group#1+' - 'ref parent-group-one/old-group#1+s' | 'ref parent-group-one/old-group#1+s' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Project and target as Group within different parent groups' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_group2 } # 'parent-group-two/new-group' - - where(:source_text, :destination_text) do - # group level work item reference - 'ref parent-group-one/old-group#1' | 'ref parent-group-one/old-group#1' - 'ref parent-group-one/old-group#1+' | 'ref parent-group-one/old-group#1+' - 'ref parent-group-one/old-group#1+s' | 'ref parent-group-one/old-group#1+s' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Group and target as Project within same parent groups' do - let_it_be(:source_parent) { source_group } # 'parent-group-one/old-group' - let_it_be(:target_parent) { target_project1 } # 'parent-group-one/new-project' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref parent-group-one/old-project#1' | 'ref parent-group-one/old-project#1' - 'ref parent-group-one/old-project#1+' | 'ref parent-group-one/old-project#1+' - 'ref parent-group-one/old-project#1+s' | 'ref parent-group-one/old-project#1+s' - # group level work item reference - 'ref #1' | 'ref parent-group-one/old-group#1' - 'ref #1+' | 'ref parent-group-one/old-group#1+' - 'ref #1+s' | 'ref parent-group-one/old-group#1+s' - # merge request reference - 'ref parent-group-one/old-project!1' | 'ref parent-group-one/old-project!1' - 'ref parent-group-one/old-project!1+' | 'ref parent-group-one/old-project!1+' - 'ref parent-group-one/old-project!1+s' | 'ref parent-group-one/old-project!1+s' - # project label reference - 'ref parent-group-one/old-project~123' | 'ref parent-group-one/old-project~123' - 'ref parent-group-one/old-project~"pr label1"' | 'ref parent-group-one/old-project~123' - # group level label reference - 'ref ~321' | 'ref parent-group-one/old-group~321' - 'ref ~"gr label1"' | 'ref parent-group-one/old-group~321' - # project level milestone reference - 'ref parent-group-one/old-project%"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Group and target as Project within different parent groups' do - let_it_be(:source_parent) { source_group } # 'parent-group-one/old-group' - let_it_be(:target_parent) { target_project2 } # 'parent-group-two/new-project' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref parent-group-one/old-project#1' | 'ref parent-group-one/old-project#1' - 'ref parent-group-one/old-project#1+' | 'ref parent-group-one/old-project#1+' - 'ref parent-group-one/old-project#1+s' | 'ref parent-group-one/old-project#1+s' - # group level work item reference - 'ref #1' | 'ref parent-group-one/old-group#1' - 'ref #1+' | 'ref parent-group-one/old-group#1+' - 'ref #1+s' | 'ref parent-group-one/old-group#1+s' - # merge request reference - 'ref parent-group-one/old-project!1' | 'ref parent-group-one/old-project!1' - 'ref parent-group-one/old-project!1+' | 'ref parent-group-one/old-project!1+' - 'ref parent-group-one/old-project!1+s' | 'ref parent-group-one/old-project!1+s' - # project label reference - 'ref parent-group-one/old-project~123' | 'ref parent-group-one/old-project~123' - 'ref parent-group-one/old-project~"pr label1"' | 'ref parent-group-one/old-project~123' - # group level label reference - 'ref ~321' | 'ref parent-group-one/old-group~321' - 'ref ~"gr label1"' | 'ref parent-group-one/old-group~321' - # project level milestone reference - 'ref parent-group-one/old-project%"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Group and target as Group within same parent groups' do - let_it_be(:source_parent) { source_group } # 'parent-group-one/old-group' - let_it_be(:target_parent) { target_group1 } # 'parent-group-one/new-group' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref parent-group-one/old-project#1' | 'ref parent-group-one/old-project#1' - 'ref parent-group-one/old-project#1+' | 'ref parent-group-one/old-project#1+' - 'ref parent-group-one/old-project#1+s' | 'ref parent-group-one/old-project#1+s' - # group level work item reference - 'ref #1' | 'ref parent-group-one/old-group#1' - 'ref #1+' | 'ref parent-group-one/old-group#1+' - 'ref #1+s' | 'ref parent-group-one/old-group#1+s' - # merge request reference - 'ref parent-group-one/old-project!1' | 'ref parent-group-one/old-project!1' - 'ref parent-group-one/old-project!1+' | 'ref parent-group-one/old-project!1+' - 'ref parent-group-one/old-project!1+s' | 'ref parent-group-one/old-project!1+s' - # project label reference - 'ref parent-group-one/old-project~123' | 'ref parent-group-one/old-project~123' - 'ref parent-group-one/old-project~"pr label1"' | 'ref parent-group-one/old-project~123' - # group level label reference - 'ref ~321' | 'ref parent-group-one/old-group~321' - 'ref ~"gr label1"' | 'ref parent-group-one/old-group~321' - # project level milestone reference - 'ref parent-group-one/old-project%"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Group and target as Group within different parent groups' do - let_it_be(:source_parent) { source_group } # 'parent-group-one/old-group' - let_it_be(:target_parent) { target_group2 } # 'parent-group-two/new-group' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref parent-group-one/old-project#1' | 'ref parent-group-one/old-project#1' - 'ref parent-group-one/old-project#1+' | 'ref parent-group-one/old-project#1+' - 'ref parent-group-one/old-project#1+s' | 'ref parent-group-one/old-project#1+s' - # group level work item reference - 'ref #1' | 'ref parent-group-one/old-group#1' - 'ref #1+' | 'ref parent-group-one/old-group#1+' - 'ref #1+s' | 'ref parent-group-one/old-group#1+s' - # merge request reference - 'ref parent-group-one/old-project!1' | 'ref parent-group-one/old-project!1' - 'ref parent-group-one/old-project!1+' | 'ref parent-group-one/old-project!1+' - 'ref parent-group-one/old-project!1+s' | 'ref parent-group-one/old-project!1+s' - # project label reference - 'ref parent-group-one/old-project~123' | 'ref parent-group-one/old-project~123' - 'ref parent-group-one/old-project~"pr label1"' | 'ref parent-group-one/old-project~123' - # group level label reference - 'ref ~321' | 'ref parent-group-one/old-group~321' - 'ref ~"gr label1"' | 'ref parent-group-one/old-group~321' - # project level milestone reference - 'ref parent-group-one/old-project%"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - end -end diff --git a/lib/banzai/filter/references/abstract_reference_filter.rb b/lib/banzai/filter/references/abstract_reference_filter.rb index 06ce1cb07ef4daa6a1b9b71c8adb8ae3a2134193..812475b944ca20abee06df6a2b31c6db0fe3541e 100644 --- a/lib/banzai/filter/references/abstract_reference_filter.rb +++ b/lib/banzai/filter/references/abstract_reference_filter.rb @@ -228,7 +228,7 @@ def object_link_filter(text, pattern, link_content: nil, link_reference: false) url.chomp!(matches[:format]) if matches.names.include?("format") - content = context[:link_text] || link_content || object_link_text(object, matches) + content = link_content || object_link_text(object, matches) link = %(<a href="#{url}" #{data} title="#{escape_once(title)}" diff --git a/lib/banzai/filter/references/issue_reference_filter.rb b/lib/banzai/filter/references/issue_reference_filter.rb index 8b3cca320e4ffe084493f211bdbaf48a5f7844bd..9a6dd834e84132a28406ffcafeec9aaffd472fd5 100644 --- a/lib/banzai/filter/references/issue_reference_filter.rb +++ b/lib/banzai/filter/references/issue_reference_filter.rb @@ -22,10 +22,6 @@ def url_for_object(issue, _parent) end def parent_records(parent, ids) - # we are treating all group level issues as work items so those would be handled - # by the WorkItemReferenceFilter - return Issue.none if parent.is_a?(Group) - parent.issues.where(iid: ids.to_a) .includes(:project, :namespace, ::Gitlab::Issues::TypeAssociationGetter.call) end diff --git a/lib/banzai/filter/references/milestone_reference_filter.rb b/lib/banzai/filter/references/milestone_reference_filter.rb index 566552f77697913af0c2cfd99488bbb6878cc625..af8050cf8d001cffc2c62ec64786855d12d62f05 100644 --- a/lib/banzai/filter/references/milestone_reference_filter.rb +++ b/lib/banzai/filter/references/milestone_reference_filter.rb @@ -158,15 +158,6 @@ def parent def requires_unescaping? true end - - def data_attributes_for(text, parent, object, link_content: false, link_reference: false) - object_parent = object.resource_parent - - return super unless object_parent.is_a?(Group) - return super if object_parent.id == parent.id - - super.merge({ group: object_parent.id, namespace: object_parent.id, project: nil }) - end end end end diff --git a/lib/banzai/filter/references/reference_cache.rb b/lib/banzai/filter/references/reference_cache.rb index 2d4760ee3306c51c7f97b59e1f144eea5667d8d5..03af5062cb6881875894c949aadab5fd7b35ea77 100644 --- a/lib/banzai/filter/references/reference_cache.rb +++ b/lib/banzai/filter/references/reference_cache.rb @@ -195,7 +195,29 @@ def cached_objects_for_paths(paths, absolute_path) def objects_for_paths(paths, absolute_path) search_paths = absolute_path ? paths.pluck(1..-1) : paths - Route.by_paths(search_paths).preload(source: [:route, { namespace: :route }]).map(&:source) + klass = parent_type.to_s.camelize.constantize + result = if parent_type == :namespace + klass.id_in(Route.by_paths(search_paths).select(:namespace_id)) + else + klass.where_full_path_in(search_paths) + end + + return result if parent_type == :group || parent_type == :namespace + return unless parent_type == :project + + projects = result.includes(namespace: :route) + .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046") + + return projects unless absolute_path + + # If we make it to here, then we're handling absolute path(s). + # Which means we need to also search groups as well as projects. + # Possible future optimization might be to use Route along the lines of: + # Routable.where_full_path_in(paths).includes(:source) + # See `routable.rb` + groups = Group.where_full_path_in(search_paths) + + projects.to_a + groups.to_a end def refs_cache diff --git a/lib/gitlab/gfm/reference_rewriter.rb b/lib/gitlab/gfm/reference_rewriter.rb index eb4c6f1709670ebfed7ef57376c2326e80921ff9..de598879e206779c362d2091e94a6b284eaeb91e 100644 --- a/lib/gitlab/gfm/reference_rewriter.rb +++ b/lib/gitlab/gfm/reference_rewriter.rb @@ -72,7 +72,6 @@ def original_html end def unfold_reference(reference, match, target_parent) - format = match[:format].to_s before = @text[0...match.begin(0)] after = @text[match.end(0)..] @@ -86,26 +85,22 @@ def unfold_reference(reference, match, target_parent) raise RewriteError, "Unspecified reference detected for #{referable.class.name}" end - cross_reference += format new_text = before + cross_reference + after substitution_valid?(new_text) ? cross_reference : reference end def find_referable(reference) - extractor = Gitlab::ReferenceExtractor.new(source_parent_param[:project], @current_user) - extractor.analyze(reference, **source_parent_param) + extractor = Gitlab::ReferenceExtractor.new(@source_parent, @current_user) + extractor.analyze(reference) extractor.all.first end def build_cross_reference(referable, target_parent) - class_name = referable.class.base_class.name - - return referable.to_reference(target_parent) unless %w[Label Milestone].include?(class_name) - return referable.to_reference(@source_parent, target_container: target_parent) if referable.is_a?(GroupLabel) - return referable.to_reference(target_parent, full: true, absolute_path: true) if referable.is_a?(Milestone) - - full = @source_parent.is_a?(Group) ? true : false - referable.to_reference(target_parent, full: full) + if referable.respond_to?(:project) + referable.to_reference(target_parent) + else + referable.to_reference(@source_parent, target_container: target_parent) + end end def substitution_valid?(substituted) @@ -113,20 +108,8 @@ def substitution_valid?(substituted) end def markdown(text) - Banzai.render(text, **source_parent_param, no_original_data: true, no_sourcepos: true, link_text: 'placeholder') - end - - def source_parent_param - case @source_parent - when Project - { project: @source_parent } - when Group - { group: @source_parent, project: nil } - when Namespaces::ProjectNamespace - { project: @source_parent.project } - end + Banzai.render(text, project: @source_parent, no_original_data: true, no_sourcepos: true) end - strong_memoize_attr :source_parent_param end end end diff --git a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb index ad07c361bf69ca4635cb2e3db58e15d02e0de346..d54c11f0b54fe2705f26b3a9ce786cb0cafb074f 100644 --- a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb @@ -793,34 +793,14 @@ let_it_be(:context) { { project: nil, group: another_group } } it 'can not find the label' do - reference = "#{another_group.full_path}~#{group_label.name}" + reference = "#{group.full_path}~#{group_label.name}" result = reference_filter("See #{reference}", context) expect(result.to_html).to include "See #{reference}" end - it 'finds the label with relative reference' do - label_name = group_label.name - reference = "#{group.full_path}~#{label_name}" - result = reference_filter("See #{reference}", context) - - if context[:label_url_method] == :group_url - expect(result.css('a').first.attr('href')).to eq(urls.group_url(group, label_name: label_name)) - else - expect(result.css('a').first.attr('href')).to eq(urls.issues_group_url(group, label_name: label_name)) - end - end - - it 'finds label in ancestors' do - label_name = parent_group_label.name - reference = "#{group.full_path}~#{label_name}" - result = reference_filter("See #{reference}", context) - - if context[:label_url_method] == :group_url - expect(result.css('a').first.attr('href')).to eq(urls.group_url(group, label_name: label_name)) - else - expect(result.css('a').first.attr('href')).to eq(urls.issues_group_url(group, label_name: label_name)) - end + it_behaves_like 'absolute group reference' do + let_it_be(:reference) { "#{group.full_path}~#{group_label.name}" } end it 'does not find label in ancestors' do @@ -829,10 +809,6 @@ expect(result.to_html).to include "See #{reference}" end - - it_behaves_like 'absolute group reference' do - let_it_be(:reference) { "#{group.full_path}~#{group_label.name}" } - end end end diff --git a/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb index 8eaf629c24c651229fd7bed12ca27b6a16a59337..05dba4f774154a194552d34530355ee51fa34034 100644 --- a/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb @@ -33,13 +33,8 @@ doc = reference_filter("Milestone #{reference}") link = doc.css('a').first - if milestone.project.present? - expect(link).to have_attribute('data-project') - expect(link.attr('data-project')).to eq project.id.to_s - elsif milestone.group.present? - expect(link).to have_attribute('data-group') - expect(link.attr('data-group')).to eq milestone.group.id.to_s - end + expect(link).to have_attribute('data-project') + expect(link.attr('data-project')).to eq project.id.to_s end it 'includes a data-milestone attribute' do @@ -158,13 +153,8 @@ doc = reference_filter("Milestone #{link_reference}") link = doc.css('a').first - if milestone.project.present? - expect(link).to have_attribute('data-project') - expect(link.attr('data-project')).to eq project.id.to_s - elsif milestone.group.present? - expect(link).to have_attribute('data-group') - expect(link.attr('data-group')).to eq milestone.group.id.to_s - end + expect(link).to have_attribute('data-project') + expect(link.attr('data-project')).to eq project.id.to_s end it 'includes a data-milestone attribute' do diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index 8b754c515b8a051dd090f43d173b64b2f148eb17..75427ac0402ee54f1bef2db139fd60aa4390e9e2 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Gfm::ReferenceRewriter, feature_category: :team_planning do +RSpec.describe Gitlab::Gfm::ReferenceRewriter do let_it_be(:group) { create(:group) } let_it_be(:user) { create(:user) } @@ -26,6 +26,14 @@ 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" \ @@ -63,9 +71,60 @@ it { is_expected.to eq "#{ref}, `#1`, #{ref}, `#1`" } end + + context 'description with project labels' do + let!(:label) { create(:label, id: 123, name: 'test', project: old_project) } + + context 'label referenced by id' do + let(:text) { '#1 and ~123' } + + it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~123) } + end + + context 'label referenced by text' do + let(:text) { '#1 and ~"test"' } + + it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~123) } + end + end + + context 'description with group labels' do + let(:old_group) { create(:group) } + let!(:group_label) { create(:group_label, id: 321, name: 'group label', group: old_group) } + + before do + old_project.update!(namespace: old_group) + end + + context 'label referenced by id' do + let(:text) { '#1 and ~321' } + + it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~321) } + end + + context 'label referenced by text' do + let(:text) { '#1 and ~"group label"' } + + it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~321) } + end + end end end + context 'when description contains a local reference' do + let(:local_issue) { create(:issue, project: old_project) } + let(:text) { "See ##{local_issue.iid}" } + + it { is_expected.to eq("See #{old_project.path}##{local_issue.iid}") } + end + + context 'when description contains a cross reference' do + let(:merge_request) { create(:merge_request) } + let(:text) { "See #{merge_request.project.full_path}!#{merge_request.iid}" } + + it { is_expected.to eq(text) } + end + context 'with a commit' do let(:old_project) { create(:project, :repository, name: 'old-project', group: group) } let(:commit) { old_project.commit } @@ -83,6 +142,26 @@ end end + context 'reference contains project milestone' do + let!(:milestone) do + create(:milestone, title: '9.0', project: old_project) + end + + let(:text) { 'milestone: %"9.0"' } + + it { is_expected.to eq %(milestone: #{old_project_ref}%"9.0") } + end + + context 'when referring to group milestone' do + let!(:milestone) do + create(:milestone, title: '10.0', group: group) + end + + let(:text) { 'milestone %"10.0"' } + + it { is_expected.to eq text } + end + context 'when referring to a group' do let(:text) { "group @#{group.full_path}" } @@ -99,7 +178,9 @@ before do create(:milestone, title: '9.0', project: old_project) - allow_any_instance_of(Milestone).to receive(:to_reference).and_return(nil) + allow_any_instance_of(Milestone) + .to receive(:to_reference) + .and_return(nil) end let(:text) { 'milestone: %"9.0"' } @@ -112,153 +193,4 @@ end end end - - describe '#rewrite with table syntax' do - using RSpec::Parameterized::TableSyntax - - let_it_be(:parent_group1) { create(:group, path: "parent-group-one") } - let_it_be(:parent_group2) { create(:group, path: "parent-group-two") } - let_it_be(:user) { create(:user) } - - let_it_be(:source_project) { create(:project, path: 'old-project', group: parent_group1) } - let_it_be(:target_project1) { create(:project, path: 'new-project', group: parent_group1) } - let_it_be(:target_project2) { create(:project, path: 'new-project', group: parent_group2) } - let_it_be(:target_group1) { create(:group, path: 'new-group', parent: parent_group1) } - let_it_be(:target_group2) { create(:group, path: 'new-group', parent: parent_group2) } - - let_it_be(:work_item_project_first) { create(:issue, project: source_project) } - - let_it_be(:merge_request) { create(:merge_request, source_project: source_project) } - - let_it_be(:project_label) { create(:label, id: 123, name: 'pr label1', project: source_project) } - let_it_be(:parent_group_label) { create(:group_label, id: 321, name: 'gr label1', group: parent_group1) } - - let_it_be(:project_milestone) { create(:milestone, title: 'project milestone', project: source_project) } - let_it_be(:parent_group_milestone) { create(:milestone, title: 'group milestone', group: parent_group1) } - - before_all do - parent_group1.add_reporter(user) - parent_group2.add_reporter(user) - end - - context 'with source as Project and target as Project within same parent group' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_project1 } # 'parent-group-one/new-project' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref #1' | 'ref old-project#1' - 'ref #1+' | 'ref old-project#1+' - 'ref #1+s' | 'ref old-project#1+s' - # merge request reference - 'ref !1' | 'ref old-project!1' - 'ref !1+' | 'ref old-project!1+' - 'ref !1+s' | 'ref old-project!1+s' - # project label reference - 'ref ~123' | 'ref old-project~123' - 'ref ~"pr label1"' | 'ref old-project~123' - # group level label reference - 'ref ~321' | 'ref old-project~321' - 'ref ~"gr label1"' | 'ref old-project~321' - # project level milestone reference - 'ref %"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Project and target as Project within different parent groups' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_project2 } # 'parent-group-two/new-project' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref #1' | 'ref parent-group-one/old-project#1' - 'ref #1+' | 'ref parent-group-one/old-project#1+' - 'ref #1+s' | 'ref parent-group-one/old-project#1+s' - # merge request reference - 'ref !1' | 'ref parent-group-one/old-project!1' - 'ref !1+' | 'ref parent-group-one/old-project!1+' - 'ref !1+s' | 'ref parent-group-one/old-project!1+s' - # project label reference - 'ref ~123' | 'ref parent-group-one/old-project~123' - 'ref ~"pr label1"' | 'ref parent-group-one/old-project~123' - # group level label reference - 'ref ~321' | 'ref parent-group-one/old-project~321' - 'ref ~"gr label1"' | 'ref parent-group-one/old-project~321' - # project level milestone reference - 'ref %"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Project and target as Group within same parent group' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_group1 } # 'parent-group-one/new-group' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref #1' | 'ref parent-group-one/old-project#1' - 'ref #1+' | 'ref parent-group-one/old-project#1+' - 'ref #1+s' | 'ref parent-group-one/old-project#1+s' - # merge request reference - 'ref !1' | 'ref parent-group-one/old-project!1' - 'ref !1+' | 'ref parent-group-one/old-project!1+' - 'ref !1+s' | 'ref parent-group-one/old-project!1+s' - # project label reference - 'ref ~123' | 'ref parent-group-one/old-project~123' - 'ref ~"pr label1"' | 'ref parent-group-one/old-project~123' - # group level label reference - 'ref ~321' | 'ref parent-group-one/old-project~321' - 'ref ~"gr label1"' | 'ref parent-group-one/old-project~321' - # project level milestone reference - 'ref %"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - - context 'with source as Project and target as Group within different parent groups' do - let_it_be(:source_parent) { source_project } # 'parent-group-one/old-project' - let_it_be(:target_parent) { target_group2 } # 'parent-group-two/new-group' - - where(:source_text, :destination_text) do - # project level work item reference - 'ref #1' | 'ref parent-group-one/old-project#1' - 'ref #1+' | 'ref parent-group-one/old-project#1+' - 'ref #1+s' | 'ref parent-group-one/old-project#1+s' - # merge request reference - 'ref !1' | 'ref parent-group-one/old-project!1' - 'ref !1+' | 'ref parent-group-one/old-project!1+' - 'ref !1+s' | 'ref parent-group-one/old-project!1+s' - # project label reference - 'ref ~123' | 'ref parent-group-one/old-project~123' - 'ref ~"pr label1"' | 'ref parent-group-one/old-project~123' - # group level label reference - 'ref ~321' | 'ref parent-group-one/old-project~321' - 'ref ~"gr label1"' | 'ref parent-group-one/old-project~321' - # project level milestone reference - 'ref %"project milestone"' | 'ref /parent-group-one/old-project%"project milestone"' - # group level milestone reference - 'ref %"group milestone"' | 'ref /parent-group-one%"group milestone"' - end - - with_them do - it_behaves_like 'rewrites references correctly' - end - end - end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index cb74824eb1cff59d97a1ab0b075ff5690df4bc93..e63b07b2f0808e95dce8494323465c6744fbd64d 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -1554,13 +1554,6 @@ it { expect(group.human_name).to eq(group.name) } end - describe '#to_human_reference' do - let_it_be(:new_group) { create(:group) } - - it { expect(group.to_human_reference).to be_nil } - it { expect(group.to_human_reference(new_group)).to eq(group.full_name) } - end - describe '#add_user' do let(:user) { create(:user) } diff --git a/spec/models/label_note_spec.rb b/spec/models/label_note_spec.rb index e859d8a057f029abcc69f0c60b689a311bb3ed3f..a521c0051aac54ac907e5ced3557358e2891422f 100644 --- a/spec/models/label_note_spec.rb +++ b/spec/models/label_note_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe LabelNote, feature_category: :team_planning do +RSpec.describe LabelNote do include Gitlab::Routing.url_helpers let_it_be(:project) { create(:project, :repository) } diff --git a/spec/support/shared_examples/lib/gitlab/gfm/reference_rewriter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/gfm/reference_rewriter_shared_examples.rb deleted file mode 100644 index 16a276ac9c06695d7124c13bf6d33c66fbccedc0..0000000000000000000000000000000000000000 --- a/spec/support/shared_examples/lib/gitlab/gfm/reference_rewriter_shared_examples.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples 'rewrites references correctly' do - let(:noteable) { source_parent.work_items.first } - - let(:note_params) do - case source_parent - when ::Group - { namespace: source_parent, project: nil } - when ::Project - { project: source_parent } - when ::Namespaces::ProjectNamespace - { project: source_parent.project } - end - end - - let(:note) { create(:note, note: source_text, noteable: noteable, **note_params) } - - it 'checks source and target markdown text', :aggregate_failures do - new_text = described_class.new(note.note, note.note_html, source_parent, user).rewrite(target_parent) - source_text_html = generate_html_from_markdown(source_text, source_parent) - target_text_html = generate_html_from_markdown(destination_text, target_parent) - source_referable = find_referable(source_text, source_parent, user) - target_referable = find_referable(new_text, source_parent, user) - - expect(new_text).to eq(destination_text) - - # this checks that the rendered html actually did render, in contrary the result html would look smth like: - # <p dir="auto">ref #1</p> without an actual link to the referenced object - expect(source_text_html).to include("href=") - expect(target_text_html).to include("href=") - expect(referable_href(source_text_html)).to eq(referable_href(target_text_html)) - - # validate that expected referable can be extracted from source and destination texts - expect(source_referable.id).to eq(target_referable.id) - - # test rewriter with target as project namespace - if target_parent.is_a?(Project) - project_namespace = target_parent.project_namespace - new_text = described_class.new(note.note, note.note_html, source_parent, user).rewrite(project_namespace) - - expect(new_text).to eq(destination_text) - end - - # test rewriter with source as project namespace - if source_parent.is_a?(Project) - project_namespace = source_parent.project_namespace - new_text = described_class.new(note.note, note.note_html, project_namespace, user).rewrite(target_parent) - - expect(new_text).to eq(destination_text) - end - - # test rewriter with source and target as project namespace - if target_parent.is_a?(Project) && source_parent.is_a?(Project) - target_namespace = target_parent.project_namespace - source_namespace = source_parent.project_namespace - new_text = described_class.new(note.note, note.note_html, source_namespace, user).rewrite(target_namespace) - - expect(new_text).to eq(destination_text) - end - end -end - -def generate_html_from_markdown(text, parent) - Banzai.render(text, **parent_argument(parent), no_original_data: true, no_sourcepos: true) -end - -def parent_argument(parent) - case parent - when Project - { project: parent } - when Group - { group: parent, project: nil } - when Namespaces::ProjectNamespace - { project: parent.project } - end -end - -def find_referable(reference, parent, user) - extractor = Gitlab::ReferenceExtractor.new(parent_argument(parent)[:project], user) - extractor.analyze(reference, **parent_argument(parent)) - extractor.all.first -end - -def referable_href(text_html) - css = 'a' - xpath = Gitlab::Utils::Nokogiri.css_to_xpath(css) - Nokogiri::HTML::DocumentFragment.parse(text_html).xpath(xpath).first.attribute('href').value -end