Commit 51aa7637 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents 46aa2b02 a8bb2c12
......@@ -110,12 +110,12 @@ export default {
{{ __('stuck') }}
</span>
<span
v-if="pipeline.flags.merge_request"
v-if="pipeline.flags.detached_merge_request_pipeline"
v-gl-tooltip
:title="__('This pipeline is run in a merge request context')"
class="js-pipeline-url-mergerequest badge badge-info"
:title="__('This pipeline is run on the source branch')"
class="js-pipeline-url-detached badge badge-info"
>
{{ __('merge request') }}
{{ __('detached') }}
</span>
</div>
</div>
......
......@@ -272,10 +272,11 @@ export default {
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:merge-request-ref="pipeline.merge_request"
:short-sha="commitShortSha"
:title="commitTitle"
:author="commitAuthor"
:show-branch="!isChildView"
:show-ref-info="!isChildView"
/>
</div>
</div>
......
<script>
import { GlTooltipDirective } from '@gitlab/ui';
import _ from 'underscore';
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import UserAvatarLink from './user_avatar/user_avatar_link.vue';
import Icon from '../../vue_shared/components/icon.vue';
......@@ -10,6 +11,7 @@ export default {
components: {
UserAvatarLink,
Icon,
GlLink,
},
props: {
/**
......@@ -33,6 +35,27 @@ export default {
required: false,
default: () => ({}),
},
/**
* If provided, is used the render the MR IID and link
* in place of the branch name. Must contains the
* following properties:
* - iid (number)
* - path (non-empty string)
*
* May optionally contain the following properties:
* - title (string): used in a tooltip if provided
*
* Any additional properties are ignored.
*/
mergeRequestRef: {
type: Object,
required: false,
default: undefined,
validator: ref =>
_.isUndefined(ref) || (_.isFinite(ref.iid) && _.isString(ref.path) && !_.isEmpty(ref.path)),
},
/**
* Used to link to the commit sha.
*/
......@@ -70,7 +93,11 @@ export default {
required: false,
default: () => ({}),
},
showBranch: {
/**
* Indicates whether or not to show the branch/MR ref info
*/
showRefInfo: {
type: Boolean,
required: false,
default: true,
......@@ -78,14 +105,12 @@ export default {
},
computed: {
/**
* Used to verify if all the properties needed to render the commit
* ref section were provided.
*
* @returns {Boolean}
* Determines if we shoud render the ref info section based
*/
hasCommitRef() {
return this.commitRef && this.commitRef.name && this.commitRef.ref_url;
shouldShowRefInfo() {
return this.showRefInfo && (this.commitRef || this.mergeRequestRef);
},
/**
* Used to verify if all the properties needed to render the commit
* author section were provided.
......@@ -109,18 +134,35 @@ export default {
</script>
<template>
<div class="branch-commit">
<template v-if="hasCommitRef && showBranch">
<template v-if="shouldShowRefInfo">
<div class="icon-container">
<i v-if="tag" class="fa fa-tag" aria-hidden="true"> </i> <icon v-if="!tag" name="fork" />
<icon v-if="tag" name="tag" />
<icon v-else-if="mergeRequestRef" name="git-merge" />
<icon v-else name="branch" />
</div>
<a v-gl-tooltip :href="commitRef.ref_url" :title="commitRef.name" class="ref-name">
<gl-link
v-if="mergeRequestRef"
v-gl-tooltip
:href="mergeRequestRef.path"
:title="mergeRequestRef.title"
class="ref-name"
>
{{ mergeRequestRef.iid }}
</gl-link>
<gl-link
v-else
v-gl-tooltip
:href="commitRef.ref_url"
:title="commitRef.name"
class="ref-name"
>
{{ commitRef.name }}
</a>
</gl-link>
</template>
<icon name="commit" class="commit-icon js-commit-icon" />
<a :href="commitUrl" class="commit-sha"> {{ shortSha }} </a>
<gl-link :href="commitUrl" class="commit-sha"> {{ shortSha }} </gl-link>
<div class="commit-title flex-truncate-parent">
<span v-if="title" class="flex-truncate-child">
......@@ -132,7 +174,7 @@ export default {
:tooltip-text="author.username"
class="avatar-image-container"
/>
<a :href="commitUrl" class="commit-row-message"> {{ title }} </a>
<gl-link :href="commitUrl" class="commit-row-message"> {{ title }} </gl-link>
</span>
<span v-else> Can't find HEAD commit for this branch </span>
</div>
......
......@@ -88,7 +88,7 @@ class DiffNote < Note
end
def banzai_render_context(field)
super.merge(suggestions_filter_enabled: supports_suggestion?)
super.merge(project: project, suggestions_filter_enabled: supports_suggestion?)
end
private
......
---
title: Upgrade to Gitaly v1.29.0
merge_request: 26406
author:
type: changed
---
title: Update pipeline list view to accommodate post-merge pipeline information
merge_request: 25690
author:
type: added
---
title: Prepare multi-line suggestions for rendering in Markdown
merge_request: 26107
author:
type: other
# frozen_string_literal: true
module Banzai
module Filter
module OutputSafety
def escape_once(html)
html.html_safe? ? html : ERB::Util.html_escape_once(html)
end
end
end
end
......@@ -12,6 +12,7 @@ module Banzai
# :only_path - Generate path-only links.
class ReferenceFilter < HTML::Pipeline::Filter
include RequestStoreReferenceCache
include OutputSafety
class << self
attr_accessor :reference_type
......@@ -43,10 +44,6 @@ module Banzai
end.join(' ')
end
def escape_once(html)
html.html_safe? ? html : ERB::Util.html_escape_once(html)
end
def ignore_ancestor_query
@ignore_ancestor_query ||= begin
parents = %w(pre code a style)
......
......@@ -6,11 +6,15 @@ module Banzai
class SuggestionFilter < HTML::Pipeline::Filter
# Class used for tagging elements that should be rendered
TAG_CLASS = 'js-render-suggestion'.freeze
SUGGESTION_REGEX = Gitlab::Diff::SuggestionsParser::SUGGESTION_CONTEXT
def call
return doc unless suggestions_filter_enabled?
doc.search('pre.suggestion > code').each do |node|
# TODO: Remove once multi-line suggestions FF get removed (#59178).
remove_multi_line_params(node.parent)
node.add_class(TAG_CLASS)
end
......@@ -20,6 +24,20 @@ module Banzai
def suggestions_filter_enabled?
context[:suggestions_filter_enabled]
end
private
def project
context[:project]
end
def remove_multi_line_params(node)
return if Feature.enabled?(:multi_line_suggestions, project)
if node[SyntaxHighlightFilter::LANG_PARAMS_ATTR]&.match?(SUGGESTION_REGEX)
node.remove_attribute(SyntaxHighlightFilter::LANG_PARAMS_ATTR)
end
end
end
end
end
......@@ -8,6 +8,11 @@ module Banzai
# HTML Filter to highlight fenced code blocks
#
class SyntaxHighlightFilter < HTML::Pipeline::Filter
include OutputSafety
PARAMS_DELIMITER = ':'.freeze
LANG_PARAMS_ATTR = 'data-lang-params'.freeze
def call
doc.search('pre > code').each do |node|
highlight_node(node)
......@@ -18,7 +23,7 @@ module Banzai
def highlight_node(node)
css_classes = +'code highlight js-syntax-highlight'
lang = node.attr('lang')
lang, lang_params = parse_lang_params(node.attr('lang'))
retried = false
if use_rouge?(lang)
......@@ -46,7 +51,10 @@ module Banzai
retry
end
highlighted = %(<pre class="#{css_classes}" lang="#{language}" v-pre="true"><code>#{code}</code></pre>)
highlighted = %(<pre class="#{css_classes}"
lang="#{language}"
#{lang_params}
v-pre="true"><code>#{code}</code></pre>)
# Extracted to a method to measure it
replace_parent_pre_element(node, highlighted)
......@@ -54,6 +62,15 @@ module Banzai
private
def parse_lang_params(language)
return unless language
lang, params = language.split(PARAMS_DELIMITER, 2)
formatted_params = %(#{LANG_PARAMS_ATTR}="#{escape_once(params)}") if params
[lang, formatted_params]
end
# Separate method so it can be instrumented.
def lex(lexer, code)
lexer.lex(code)
......
......@@ -71,7 +71,7 @@ module Gitlab
end
def name
attribute_value(:name).first
attribute_value(:name)&.first
end
def uid
......
# frozen_string_literal: true
module Gitlab
module Diff
class SuggestionsParser
# Matches for instance "-1", "+1" or "-1+2".
SUGGESTION_CONTEXT = /^(\-(?<above>\d+))?(\+(?<below>\d+))?$/.freeze
end
end
end
......@@ -12133,6 +12133,9 @@ msgstr ""
msgid "deploy token"
msgstr ""
msgid "detached"
msgstr ""
msgid "disabled"
msgstr ""
......
......@@ -2,7 +2,7 @@
require 'rails_helper'
describe 'Merge request > User sees merge request pipelines', :js do
describe 'Merge request > User sees pipelines triggered by merge request', :js do
include ProjectForksHelper
include TestReportsHelper
......@@ -47,7 +47,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push)
end
let!(:merge_request_pipeline) do
let!(:detached_merge_request_pipeline) do
Ci::CreatePipelineService.new(project, user, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request)
end
......@@ -60,16 +60,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
end
end
it 'sees branch pipelines and merge request pipelines in correct order' do
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 2)
expect(first('.js-pipeline-url-link')).to have_content("##{merge_request_pipeline.id}")
expect(first('.js-pipeline-url-link')).to have_content("##{detached_merge_request_pipeline.id}")
end
end
it 'sees the latest merge request pipeline as the head pipeline' do
it 'sees the latest detached merge request pipeline as the head pipeline' do
page.within('.ci-widget-content') do
expect(page).to have_content("##{merge_request_pipeline.id}")
expect(page).to have_content("##{detached_merge_request_pipeline.id}")
end
end
......@@ -79,7 +79,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push)
end
let!(:merge_request_pipeline_2) do
let!(:detached_merge_request_pipeline_2) do
Ci::CreatePipelineService.new(project, user, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request)
end
......@@ -92,15 +92,15 @@ describe 'Merge request > User sees merge request pipelines', :js do
end
end
it 'sees branch pipelines and merge request pipelines in correct order' do
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 4)
expect(all('.js-pipeline-url-link')[0])
.to have_content("##{merge_request_pipeline_2.id}")
.to have_content("##{detached_merge_request_pipeline_2.id}")
expect(all('.js-pipeline-url-link')[1])
.to have_content("##{merge_request_pipeline.id}")
.to have_content("##{detached_merge_request_pipeline.id}")
expect(all('.js-pipeline-url-link')[2])
.to have_content("##{push_pipeline_2.id}")
......@@ -110,25 +110,25 @@ describe 'Merge request > User sees merge request pipelines', :js do
end
end
it 'sees merge request tag for merge request pipelines' do
it 'sees detached tag for detached merge request pipelines' do
page.within('.ci-table') do
expect(all('.pipeline-tags')[0])
.to have_content("merge request")
.to have_content("detached")
expect(all('.pipeline-tags')[1])
.to have_content("merge request")
.to have_content("detached")
expect(all('.pipeline-tags')[2])
.not_to have_content("merge request")
.not_to have_content("detached")
expect(all('.pipeline-tags')[3])
.not_to have_content("merge request")
.not_to have_content("detached")
end
end
it 'sees the latest merge request pipeline as the head pipeline' do
it 'sees the latest detached merge request pipeline as the head pipeline' do
page.within('.ci-widget-content') do
expect(page).to have_content("##{merge_request_pipeline_2.id}")
expect(page).to have_content("##{detached_merge_request_pipeline_2.id}")
end
end
end
......@@ -140,16 +140,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
wait_for_requests
end
context 'when merge request pipeline is pending' do
context 'when detached merge request pipeline is pending' do
it 'waits the head pipeline' do
expect(page).to have_content('to be merged automatically when the pipeline succeeds')
expect(page).to have_link('Cancel automatic merge')
end
end
context 'when merge request pipeline succeeds' do
context 'when detached merge request pipeline succeeds' do
before do
merge_request_pipeline.succeed!
detached_merge_request_pipeline.succeed!
wait_for_requests
end
......@@ -218,7 +218,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push)
end
let!(:merge_request_pipeline) do
let!(:detached_merge_request_pipeline) do
Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request)
end
......@@ -236,16 +236,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
end
end
it 'sees branch pipelines and merge request pipelines in correct order' do
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 2)
expect(first('.js-pipeline-url-link')).to have_content("##{merge_request_pipeline.id}")
expect(first('.js-pipeline-url-link')).to have_content("##{detached_merge_request_pipeline.id}")
end
end
it 'sees the latest merge request pipeline as the head pipeline' do
it 'sees the latest detached merge request pipeline as the head pipeline' do
page.within('.ci-widget-content') do
expect(page).to have_content("##{merge_request_pipeline.id}")
expect(page).to have_content("##{detached_merge_request_pipeline.id}")
end
end
......@@ -261,7 +261,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push)
end
let!(:merge_request_pipeline_2) do
let!(:detached_merge_request_pipeline_2) do
Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request)
end
......@@ -274,15 +274,15 @@ describe 'Merge request > User sees merge request pipelines', :js do
end
end
it 'sees branch pipelines and merge request pipelines in correct order' do
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 4)
expect(all('.js-pipeline-url-link')[0])
.to have_content("##{merge_request_pipeline_2.id}")
.to have_content("##{detached_merge_request_pipeline_2.id}")
expect(all('.js-pipeline-url-link')[1])
.to have_content("##{merge_request_pipeline.id}")
.to have_content("##{detached_merge_request_pipeline.id}")
expect(all('.js-pipeline-url-link')[2])
.to have_content("##{push_pipeline_2.id}")
......@@ -292,25 +292,25 @@ describe 'Merge request > User sees merge request pipelines', :js do
end
end
it 'sees merge request tag for merge request pipelines' do
it 'sees detached tag for detached merge request pipelines' do
page.within('.ci-table') do
expect(all('.pipeline-tags')[0])
.to have_content("merge request")
.to have_content("detached")
expect(all('.pipeline-tags')[1])
.to have_content("merge request")
.to have_content("detached")
expect(all('.pipeline-tags')[2])
.not_to have_content("merge request")
.not_to have_content("detached")
expect(all('.pipeline-tags')[3])
.not_to have_content("merge request")
.not_to have_content("detached")
end
end
it 'sees the latest merge request pipeline as the head pipeline' do
it 'sees the latest detached merge request pipeline as the head pipeline' do
page.within('.ci-widget-content') do
expect(page).to have_content("##{merge_request_pipeline_2.id}")
expect(page).to have_content("##{detached_merge_request_pipeline_2.id}")
end
end
......@@ -328,16 +328,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
wait_for_requests
end
context 'when merge request pipeline is pending' do
context 'when detached merge request pipeline is pending' do
it 'waits the head pipeline' do
expect(page).to have_content('to be merged automatically when the pipeline succeeds')
expect(page).to have_link('Cancel automatic merge')
end
end
context 'when merge request pipeline succeeds' do
context 'when detached merge request pipeline succeeds' do
before do
merge_request_pipeline.succeed!
detached_merge_request_pipeline.succeed!
wait_for_requests
end
......
require 'spec_helper'
describe 'Pipelines', :js do
include ProjectForksHelper
let(:project) { create(:project) }
context 'when user is logged in' do
......@@ -165,6 +167,99 @@ describe 'Pipelines', :js do
end
end
context 'when pipeline is detached merge request pipeline' do
let(:merge_request) do
create(:merge_request,
:with_detached_merge_request_pipeline,
source_project: source_project,
target_project: target_project)
end
let!(:pipeline) { merge_request.all_pipelines.first }
let(:source_project) { project }
let(:target_project) { project }
before do
visit project_pipelines_path(source_project)
end
shared_examples_for 'showing detached merge request pipeline information' do
it 'shows detached tag for the pipeline' do
within '.pipeline-tags' do
expect(page).to have_content('detached')
end
end
it 'shows the link of the merge request' do
within '.branch-commit' do
expect(page).to have_link(merge_request.iid,
href: project_merge_request_path(project, merge_request))
end
end
it 'does not show the ref of the pipeline' do
within '.branch-commit' do
expect(page).not_to have_link(pipeline.ref)
end
end
end
it_behaves_like 'showing detached merge request pipeline information'
context 'when source project is a forked project' do
let(:source_project) { fork_project(project, user, repository: true) }
it_behaves_like 'showing detached merge request pipeline information'
end
end
context 'when pipeline is merge request pipeline' do
let(:merge_request) do
create(:merge_request,
:with_merge_request_pipeline,
source_project: source_project,
target_project: target_project,
merge_sha: target_project.commit.sha)
end
let!(:pipeline) { merge_request.all_pipelines.first }
let(:source_project) { project }
let(:target_project) { project }
before do
visit project_pipelines_path(source_project)
end
shared_examples_for 'Correct merge request pipeline information' do
it 'does not show detached tag for the pipeline' do
within '.pipeline-tags' do
expect(page).not_to have_content('detached')
end
end
it 'shows the link of the merge request' do
within '.branch-commit' do
expect(page).to have_link(merge_request.iid,
href: project_merge_request_path(project, merge_request))
end
end
it 'does not show the ref of the pipeline' do
within '.branch-commit' do
expect(page).not_to have_link(pipeline.ref)
end
end
end
it_behaves_like 'Correct merge request pipeline information'
context 'when source project is a forked project' do
let(:source_project) { fork_project(project, user, repository: true) }
it_behaves_like 'Correct merge request pipeline information'
end
end
context 'when pipeline has configuration errors' do
let(:pipeline) do
create(:ci_pipeline, :invalid, project: project)
......
......@@ -60,7 +60,7 @@ describe('Environment item', () => {
sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
ref: {
name: 'master',
ref_path: 'root/ci-folders/tree/master',
ref_url: 'root/ci-folders/tree/master',
},
tag: true,
'last?': true,
......
......@@ -100,7 +100,8 @@ describe('Pipeline Url Component', () => {
latest: true,
yaml_errors: true,
stuck: true,
merge_request: true,
merge_request_pipeline: true,
detached_merge_request_pipeline: true,
},
},
autoDevopsHelpPath: 'foo',
......@@ -108,15 +109,16 @@ describe('Pipeline Url Component', () => {
}).$mount();
expect(component.$el.querySelector('.js-pipeline-url-latest').textContent).toContain('latest');
expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain(
'yaml invalid',
);
expect(component.$el.querySelector('.js-pipeline-url-mergerequest').textContent).toContain(
'merge request',
);
expect(component.$el.querySelector('.js-pipeline-url-stuck').textContent).toContain('stuck');
expect(component.$el.querySelector('.js-pipeline-url-detached').textContent).toContain(
'detached',
);
});
it('should render a badge for autodevops', () => {
......
......@@ -61,7 +61,7 @@ describe('Commit component', () => {
});
it('should render a tag icon if it represents a tag', () => {
expect(component.$el.querySelector('.icon-container i').classList).toContain('fa-tag');
expect(component.$el.querySelector('.icon-container svg.ic-tag')).not.toBeNull();
});
it('should render a link to the ref url', () => {
......@@ -143,4 +143,92 @@ describe('Commit component', () => {
);
});
});
describe('When commit ref is provided, but merge ref is not', () => {
it('should render the commit ref', () => {
props = {
tag: false,
commitRef: {
name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
},
commitUrl:
'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067',
shortSha: 'b7836edd',
title: null,
author: {},
};
component = mountComponent(CommitComponent, props);
const refEl = component.$el.querySelector('.ref-name');
expect(refEl.textContent).toContain('master');
expect(refEl.href).toBe(props.commitRef.ref_url);
expect(refEl.getAttribute('data-original-title')).toBe(props.commitRef.name);
expect(component.$el.querySelector('.icon-container .ic-branch')).not.toBeNull();
});
});
describe('When both commit and merge ref are provided', () => {
it('should render the merge ref', () => {
props = {
tag: false,
commitRef: {
name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
},
commitUrl:
'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067',
mergeRequestRef: {
iid: 1234,
path: 'https://example.com/path/to/mr',
title: 'Test MR',
},
shortSha: 'b7836edd',
title: null,
author: {},
};
component = mountComponent(CommitComponent, props);
const refEl = component.$el.querySelector('.ref-name');
expect(refEl.textContent).toContain('1234');
expect(refEl.href).toBe(props.mergeRequestRef.path);
expect(refEl.getAttribute('data-original-title')).toBe(props.mergeRequestRef.title);
expect(component.$el.querySelector('.icon-container .ic-git-merge')).not.toBeNull();
});
});
describe('When showRefInfo === false', () => {
it('should not render any ref info', () => {
props = {
tag: false,
commitRef: {
name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
},
commitUrl:
'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067',
mergeRequestRef: {
iid: 1234,
path: '/path/to/mr',
title: 'Test MR',
},
shortSha: 'b7836edd',
title: null,
author: {},
showRefInfo: false,
};
component = mountComponent(CommitComponent, props);
expect(component.$el.querySelector('.ref-name')).toBeNull();
});
});
});
# frozen_string_literal: true
require 'spec_helper'
describe Banzai::Filter::OutputSafety do
subject do
Class.new do
include Banzai::Filter::OutputSafety
end.new
end
let(:content) { '<pre><code>foo</code></pre>' }
context 'when given HTML is safe' do
let(:html) { content.html_safe }
it 'returns safe HTML' do
expect(subject.escape_once(html)).to eq(html)
end
end
context 'when given HTML is not safe' do
let(:html) { content }
it 'returns escaped HTML' do
expect(subject.escape_once(html)).to eq(ERB::Util.html_escape_once(html))
end
end
end
......@@ -5,7 +5,7 @@ require 'spec_helper'
describe Banzai::Filter::SuggestionFilter do
include FilterSpecHelper
let(:input) { "<pre class='code highlight js-syntax-highlight suggestion'><code>foo\n</code></pre>" }
let(:input) { %(<pre class="code highlight js-syntax-highlight suggestion"><code>foo\n</code></pre>) }
let(:default_context) do
{ suggestions_filter_enabled: true }
end
......@@ -23,4 +23,35 @@ describe Banzai::Filter::SuggestionFilter do
expect(result[:class]).to be_nil
end
context 'multi-line suggestions' do
let(:data_attr) { Banzai::Filter::SyntaxHighlightFilter::LANG_PARAMS_ATTR }
let(:input) { %(<pre class="code highlight js-syntax-highlight suggestion" #{data_attr}="-3+2"><code>foo\n</code></pre>) }
context 'feature disabled' do
before do
stub_feature_flags(multi_line_suggestions: false)
end
it 'removes data-lang-params if it matches a multi-line suggestion param' do
doc = filter(input, default_context)
pre = doc.css('pre').first
expect(pre[data_attr]).to be_nil
end
end
context 'feature enabled' do
before do
stub_feature_flags(multi_line_suggestions: true)
end
it 'keeps data-lang-params' do
doc = filter(input, default_context)
pre = doc.css('pre').first
expect(pre[data_attr]).to eq('-3+2')
end
end
end
end
......@@ -45,7 +45,10 @@ describe Banzai::Filter::SyntaxHighlightFilter do
end
context "languages that should be passed through" do
%w(math mermaid plantuml).each do |lang|
let(:delimiter) { described_class::PARAMS_DELIMITER }
let(:data_attr) { described_class::LANG_PARAMS_ATTR }
%w(math mermaid plantuml suggestion).each do |lang|
context "when #{lang} is specified" do
it "highlights as plaintext but with the correct language attribute and class" do
result = filter(%{<pre><code lang="#{lang}">This is a test</code></pre>})
......@@ -55,6 +58,33 @@ describe Banzai::Filter::SyntaxHighlightFilter do
include_examples "XSS prevention", lang
end
context "when #{lang} has extra params" do
let(:lang_params) { 'foo-bar-kux' }
it "includes data-lang-params tag with extra information" do
result = filter(%{<pre><code lang="#{lang}#{delimiter}#{lang_params}">This is a test</code></pre>})
expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight #{lang}" lang="#{lang}" #{data_attr}="#{lang_params}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
end
include_examples "XSS prevention", lang
include_examples "XSS prevention",
"#{lang}#{described_class::PARAMS_DELIMITER}&lt;script&gt;alert(1)&lt;/script&gt;"
include_examples "XSS prevention",
"#{lang}#{described_class::PARAMS_DELIMITER}<script>alert(1)</script>"
end
end
context 'when multiple param delimiters are used' do
let(:lang) { 'suggestion' }
let(:lang_params) { '-1+10' }
it "delimits on the first appearence" do
result = filter(%{<pre><code lang="#{lang}#{delimiter}#{lang_params}#{delimiter}more-things">This is a test</code></pre>})
expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight #{lang}" lang="#{lang}" #{data_attr}="#{lang_params}#{delimiter}more-things" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
end
end
end
......
......@@ -336,6 +336,16 @@ describe DiffNote do
end
end
describe '#banzai_render_context' do
let(:note) { create(:diff_note_on_merge_request) }
it 'includes expected context' do
context = note.banzai_render_context(:note)
expect(context).to include(suggestions_filter_enabled: true, noteable: note.noteable, project: note.project)
end
end
describe "image diff notes" do
subject { build(:image_diff_note_on_merge_request, project: project, noteable: merge_request) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment