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 { ...@@ -110,12 +110,12 @@ export default {
{{ __('stuck') }} {{ __('stuck') }}
</span> </span>
<span <span
v-if="pipeline.flags.merge_request" v-if="pipeline.flags.detached_merge_request_pipeline"
v-gl-tooltip v-gl-tooltip
:title="__('This pipeline is run in a merge request context')" :title="__('This pipeline is run on the source branch')"
class="js-pipeline-url-mergerequest badge badge-info" class="js-pipeline-url-detached badge badge-info"
> >
{{ __('merge request') }} {{ __('detached') }}
</span> </span>
</div> </div>
</div> </div>
......
...@@ -272,10 +272,11 @@ export default { ...@@ -272,10 +272,11 @@ export default {
:tag="commitTag" :tag="commitTag"
:commit-ref="commitRef" :commit-ref="commitRef"
:commit-url="commitUrl" :commit-url="commitUrl"
:merge-request-ref="pipeline.merge_request"
:short-sha="commitShortSha" :short-sha="commitShortSha"
:title="commitTitle" :title="commitTitle"
:author="commitAuthor" :author="commitAuthor"
:show-branch="!isChildView" :show-ref-info="!isChildView"
/> />
</div> </div>
</div> </div>
......
<script> <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 UserAvatarLink from './user_avatar/user_avatar_link.vue';
import Icon from '../../vue_shared/components/icon.vue'; import Icon from '../../vue_shared/components/icon.vue';
...@@ -10,6 +11,7 @@ export default { ...@@ -10,6 +11,7 @@ export default {
components: { components: {
UserAvatarLink, UserAvatarLink,
Icon, Icon,
GlLink,
}, },
props: { props: {
/** /**
...@@ -33,6 +35,27 @@ export default { ...@@ -33,6 +35,27 @@ export default {
required: false, required: false,
default: () => ({}), 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. * Used to link to the commit sha.
*/ */
...@@ -70,7 +93,11 @@ export default { ...@@ -70,7 +93,11 @@ export default {
required: false, required: false,
default: () => ({}), default: () => ({}),
}, },
showBranch: {
/**
* Indicates whether or not to show the branch/MR ref info
*/
showRefInfo: {
type: Boolean, type: Boolean,
required: false, required: false,
default: true, default: true,
...@@ -78,14 +105,12 @@ export default { ...@@ -78,14 +105,12 @@ export default {
}, },
computed: { computed: {
/** /**
* Used to verify if all the properties needed to render the commit * Determines if we shoud render the ref info section based
* ref section were provided.
*
* @returns {Boolean}
*/ */
hasCommitRef() { shouldShowRefInfo() {
return this.commitRef && this.commitRef.name && this.commitRef.ref_url; return this.showRefInfo && (this.commitRef || this.mergeRequestRef);
}, },
/** /**
* Used to verify if all the properties needed to render the commit * Used to verify if all the properties needed to render the commit
* author section were provided. * author section were provided.
...@@ -109,18 +134,35 @@ export default { ...@@ -109,18 +134,35 @@ export default {
</script> </script>
<template> <template>
<div class="branch-commit"> <div class="branch-commit">
<template v-if="hasCommitRef && showBranch"> <template v-if="shouldShowRefInfo">
<div class="icon-container"> <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> </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 }} {{ commitRef.name }}
</a> </gl-link>
</template> </template>
<icon name="commit" class="commit-icon js-commit-icon" /> <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"> <div class="commit-title flex-truncate-parent">
<span v-if="title" class="flex-truncate-child"> <span v-if="title" class="flex-truncate-child">
...@@ -132,7 +174,7 @@ export default { ...@@ -132,7 +174,7 @@ export default {
:tooltip-text="author.username" :tooltip-text="author.username"
class="avatar-image-container" 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>
<span v-else> Can't find HEAD commit for this branch </span> <span v-else> Can't find HEAD commit for this branch </span>
</div> </div>
......
...@@ -88,7 +88,7 @@ class DiffNote < Note ...@@ -88,7 +88,7 @@ class DiffNote < Note
end end
def banzai_render_context(field) def banzai_render_context(field)
super.merge(suggestions_filter_enabled: supports_suggestion?) super.merge(project: project, suggestions_filter_enabled: supports_suggestion?)
end end
private 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 ...@@ -12,6 +12,7 @@ module Banzai
# :only_path - Generate path-only links. # :only_path - Generate path-only links.
class ReferenceFilter < HTML::Pipeline::Filter class ReferenceFilter < HTML::Pipeline::Filter
include RequestStoreReferenceCache include RequestStoreReferenceCache
include OutputSafety
class << self class << self
attr_accessor :reference_type attr_accessor :reference_type
...@@ -43,10 +44,6 @@ module Banzai ...@@ -43,10 +44,6 @@ module Banzai
end.join(' ') end.join(' ')
end end
def escape_once(html)
html.html_safe? ? html : ERB::Util.html_escape_once(html)
end
def ignore_ancestor_query def ignore_ancestor_query
@ignore_ancestor_query ||= begin @ignore_ancestor_query ||= begin
parents = %w(pre code a style) parents = %w(pre code a style)
......
...@@ -6,11 +6,15 @@ module Banzai ...@@ -6,11 +6,15 @@ module Banzai
class SuggestionFilter < HTML::Pipeline::Filter class SuggestionFilter < HTML::Pipeline::Filter
# Class used for tagging elements that should be rendered # Class used for tagging elements that should be rendered
TAG_CLASS = 'js-render-suggestion'.freeze TAG_CLASS = 'js-render-suggestion'.freeze
SUGGESTION_REGEX = Gitlab::Diff::SuggestionsParser::SUGGESTION_CONTEXT
def call def call
return doc unless suggestions_filter_enabled? return doc unless suggestions_filter_enabled?
doc.search('pre.suggestion > code').each do |node| 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) node.add_class(TAG_CLASS)
end end
...@@ -20,6 +24,20 @@ module Banzai ...@@ -20,6 +24,20 @@ module Banzai
def suggestions_filter_enabled? def suggestions_filter_enabled?
context[:suggestions_filter_enabled] context[:suggestions_filter_enabled]
end 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 end
end end
...@@ -8,6 +8,11 @@ module Banzai ...@@ -8,6 +8,11 @@ module Banzai
# HTML Filter to highlight fenced code blocks # HTML Filter to highlight fenced code blocks
# #
class SyntaxHighlightFilter < HTML::Pipeline::Filter class SyntaxHighlightFilter < HTML::Pipeline::Filter
include OutputSafety
PARAMS_DELIMITER = ':'.freeze
LANG_PARAMS_ATTR = 'data-lang-params'.freeze
def call def call
doc.search('pre > code').each do |node| doc.search('pre > code').each do |node|
highlight_node(node) highlight_node(node)
...@@ -18,7 +23,7 @@ module Banzai ...@@ -18,7 +23,7 @@ module Banzai
def highlight_node(node) def highlight_node(node)
css_classes = +'code highlight js-syntax-highlight' css_classes = +'code highlight js-syntax-highlight'
lang = node.attr('lang') lang, lang_params = parse_lang_params(node.attr('lang'))
retried = false retried = false
if use_rouge?(lang) if use_rouge?(lang)
...@@ -46,7 +51,10 @@ module Banzai ...@@ -46,7 +51,10 @@ module Banzai
retry retry
end 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 # Extracted to a method to measure it
replace_parent_pre_element(node, highlighted) replace_parent_pre_element(node, highlighted)
...@@ -54,6 +62,15 @@ module Banzai ...@@ -54,6 +62,15 @@ module Banzai
private 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. # Separate method so it can be instrumented.
def lex(lexer, code) def lex(lexer, code)
lexer.lex(code) lexer.lex(code)
......
...@@ -71,7 +71,7 @@ module Gitlab ...@@ -71,7 +71,7 @@ module Gitlab
end end
def name def name
attribute_value(:name).first attribute_value(:name)&.first
end end
def uid 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 "" ...@@ -12133,6 +12133,9 @@ msgstr ""
msgid "deploy token" msgid "deploy token"
msgstr "" msgstr ""
msgid "detached"
msgstr ""
msgid "disabled" msgid "disabled"
msgstr "" msgstr ""
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'rails_helper' 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 ProjectForksHelper
include TestReportsHelper include TestReportsHelper
...@@ -47,7 +47,7 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -47,7 +47,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push) .execute(:push)
end end
let!(:merge_request_pipeline) do let!(:detached_merge_request_pipeline) do
Ci::CreatePipelineService.new(project, user, ref: 'feature') Ci::CreatePipelineService.new(project, user, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request) .execute(:merge_request_event, merge_request: merge_request)
end end
...@@ -60,16 +60,16 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -60,16 +60,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
end end
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 page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 2) 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
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 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
end end
...@@ -79,7 +79,7 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -79,7 +79,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push) .execute(:push)
end end
let!(:merge_request_pipeline_2) do let!(:detached_merge_request_pipeline_2) do
Ci::CreatePipelineService.new(project, user, ref: 'feature') Ci::CreatePipelineService.new(project, user, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request) .execute(:merge_request_event, merge_request: merge_request)
end end
...@@ -92,15 +92,15 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -92,15 +92,15 @@ describe 'Merge request > User sees merge request pipelines', :js do
end end
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 page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 4) expect(page).to have_selector('.ci-pending', count: 4)
expect(all('.js-pipeline-url-link')[0]) 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]) 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]) expect(all('.js-pipeline-url-link')[2])
.to have_content("##{push_pipeline_2.id}") .to have_content("##{push_pipeline_2.id}")
...@@ -110,25 +110,25 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -110,25 +110,25 @@ describe 'Merge request > User sees merge request pipelines', :js do
end end
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 page.within('.ci-table') do
expect(all('.pipeline-tags')[0]) expect(all('.pipeline-tags')[0])
.to have_content("merge request") .to have_content("detached")
expect(all('.pipeline-tags')[1]) expect(all('.pipeline-tags')[1])
.to have_content("merge request") .to have_content("detached")
expect(all('.pipeline-tags')[2]) expect(all('.pipeline-tags')[2])
.not_to have_content("merge request") .not_to have_content("detached")
expect(all('.pipeline-tags')[3]) expect(all('.pipeline-tags')[3])
.not_to have_content("merge request") .not_to have_content("detached")
end end
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 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 end
end end
...@@ -140,16 +140,16 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -140,16 +140,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
wait_for_requests wait_for_requests
end end
context 'when merge request pipeline is pending' do context 'when detached merge request pipeline is pending' do
it 'waits the head pipeline' do it 'waits the head pipeline' do
expect(page).to have_content('to be merged automatically when the pipeline succeeds') expect(page).to have_content('to be merged automatically when the pipeline succeeds')
expect(page).to have_link('Cancel automatic merge') expect(page).to have_link('Cancel automatic merge')
end end
end end
context 'when merge request pipeline succeeds' do context 'when detached merge request pipeline succeeds' do
before do before do
merge_request_pipeline.succeed! detached_merge_request_pipeline.succeed!
wait_for_requests wait_for_requests
end end
...@@ -218,7 +218,7 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -218,7 +218,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push) .execute(:push)
end end
let!(:merge_request_pipeline) do let!(:detached_merge_request_pipeline) do
Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature') Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request) .execute(:merge_request_event, merge_request: merge_request)
end end
...@@ -236,16 +236,16 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -236,16 +236,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
end end
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 page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 2) 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
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 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
end end
...@@ -261,7 +261,7 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -261,7 +261,7 @@ describe 'Merge request > User sees merge request pipelines', :js do
.execute(:push) .execute(:push)
end end
let!(:merge_request_pipeline_2) do let!(:detached_merge_request_pipeline_2) do
Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature') Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request) .execute(:merge_request_event, merge_request: merge_request)
end end
...@@ -274,15 +274,15 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -274,15 +274,15 @@ describe 'Merge request > User sees merge request pipelines', :js do
end end
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 page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 4) expect(page).to have_selector('.ci-pending', count: 4)
expect(all('.js-pipeline-url-link')[0]) 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]) 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]) expect(all('.js-pipeline-url-link')[2])
.to have_content("##{push_pipeline_2.id}") .to have_content("##{push_pipeline_2.id}")
...@@ -292,25 +292,25 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -292,25 +292,25 @@ describe 'Merge request > User sees merge request pipelines', :js do
end end
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 page.within('.ci-table') do
expect(all('.pipeline-tags')[0]) expect(all('.pipeline-tags')[0])
.to have_content("merge request") .to have_content("detached")
expect(all('.pipeline-tags')[1]) expect(all('.pipeline-tags')[1])
.to have_content("merge request") .to have_content("detached")
expect(all('.pipeline-tags')[2]) expect(all('.pipeline-tags')[2])
.not_to have_content("merge request") .not_to have_content("detached")
expect(all('.pipeline-tags')[3]) expect(all('.pipeline-tags')[3])
.not_to have_content("merge request") .not_to have_content("detached")
end end
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 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 end
...@@ -328,16 +328,16 @@ describe 'Merge request > User sees merge request pipelines', :js do ...@@ -328,16 +328,16 @@ describe 'Merge request > User sees merge request pipelines', :js do
wait_for_requests wait_for_requests
end end
context 'when merge request pipeline is pending' do context 'when detached merge request pipeline is pending' do
it 'waits the head pipeline' do it 'waits the head pipeline' do
expect(page).to have_content('to be merged automatically when the pipeline succeeds') expect(page).to have_content('to be merged automatically when the pipeline succeeds')
expect(page).to have_link('Cancel automatic merge') expect(page).to have_link('Cancel automatic merge')
end end
end end
context 'when merge request pipeline succeeds' do context 'when detached merge request pipeline succeeds' do
before do before do
merge_request_pipeline.succeed! detached_merge_request_pipeline.succeed!
wait_for_requests wait_for_requests
end end
......
require 'spec_helper' require 'spec_helper'
describe 'Pipelines', :js do describe 'Pipelines', :js do
include ProjectForksHelper
let(:project) { create(:project) } let(:project) { create(:project) }
context 'when user is logged in' do context 'when user is logged in' do
...@@ -165,6 +167,99 @@ describe 'Pipelines', :js do ...@@ -165,6 +167,99 @@ describe 'Pipelines', :js do
end end
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 context 'when pipeline has configuration errors' do
let(:pipeline) do let(:pipeline) do
create(:ci_pipeline, :invalid, project: project) create(:ci_pipeline, :invalid, project: project)
......
...@@ -60,7 +60,7 @@ describe('Environment item', () => { ...@@ -60,7 +60,7 @@ describe('Environment item', () => {
sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
ref: { ref: {
name: 'master', name: 'master',
ref_path: 'root/ci-folders/tree/master', ref_url: 'root/ci-folders/tree/master',
}, },
tag: true, tag: true,
'last?': true, 'last?': true,
......
...@@ -100,7 +100,8 @@ describe('Pipeline Url Component', () => { ...@@ -100,7 +100,8 @@ describe('Pipeline Url Component', () => {
latest: true, latest: true,
yaml_errors: true, yaml_errors: true,
stuck: true, stuck: true,
merge_request: true, merge_request_pipeline: true,
detached_merge_request_pipeline: true,
}, },
}, },
autoDevopsHelpPath: 'foo', autoDevopsHelpPath: 'foo',
...@@ -108,15 +109,16 @@ describe('Pipeline Url Component', () => { ...@@ -108,15 +109,16 @@ describe('Pipeline Url Component', () => {
}).$mount(); }).$mount();
expect(component.$el.querySelector('.js-pipeline-url-latest').textContent).toContain('latest'); expect(component.$el.querySelector('.js-pipeline-url-latest').textContent).toContain('latest');
expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain( expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain(
'yaml invalid', '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-stuck').textContent).toContain('stuck');
expect(component.$el.querySelector('.js-pipeline-url-detached').textContent).toContain(
'detached',
);
}); });
it('should render a badge for autodevops', () => { it('should render a badge for autodevops', () => {
......
...@@ -61,7 +61,7 @@ describe('Commit component', () => { ...@@ -61,7 +61,7 @@ describe('Commit component', () => {
}); });
it('should render a tag icon if it represents a tag', () => { 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', () => { it('should render a link to the ref url', () => {
...@@ -143,4 +143,92 @@ describe('Commit component', () => { ...@@ -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' ...@@ -5,7 +5,7 @@ require 'spec_helper'
describe Banzai::Filter::SuggestionFilter do describe Banzai::Filter::SuggestionFilter do
include FilterSpecHelper 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 let(:default_context) do
{ suggestions_filter_enabled: true } { suggestions_filter_enabled: true }
end end
...@@ -23,4 +23,35 @@ describe Banzai::Filter::SuggestionFilter do ...@@ -23,4 +23,35 @@ describe Banzai::Filter::SuggestionFilter do
expect(result[:class]).to be_nil expect(result[:class]).to be_nil
end 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 end
...@@ -45,7 +45,10 @@ describe Banzai::Filter::SyntaxHighlightFilter do ...@@ -45,7 +45,10 @@ describe Banzai::Filter::SyntaxHighlightFilter do
end end
context "languages that should be passed through" do 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 context "when #{lang} is specified" do
it "highlights as plaintext but with the correct language attribute and class" 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>}) result = filter(%{<pre><code lang="#{lang}">This is a test</code></pre>})
...@@ -55,6 +58,33 @@ describe Banzai::Filter::SyntaxHighlightFilter do ...@@ -55,6 +58,33 @@ describe Banzai::Filter::SyntaxHighlightFilter do
include_examples "XSS prevention", lang include_examples "XSS prevention", lang
end 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
end end
......
...@@ -336,6 +336,16 @@ describe DiffNote do ...@@ -336,6 +336,16 @@ describe DiffNote do
end end
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 describe "image diff notes" do
subject { build(:image_diff_note_on_merge_request, project: project, noteable: merge_request) } 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