Commit d13c778d authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-07-07

# Conflicts:
#	app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
#	app/assets/stylesheets/framework/mixins.scss
#	app/controllers/projects_controller.rb
#	db/schema.rb
#	spec/lib/gitlab/import_export/all_models.yml

[ci skip]
parents be29c562 06e3ea7a
...@@ -108,6 +108,11 @@ ...@@ -108,6 +108,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: { projectPath: {
type: String, type: String,
required: true, required: true,
...@@ -282,6 +287,7 @@ ...@@ -282,6 +287,7 @@
:issuable-templates="issuableTemplates" :issuable-templates="issuableTemplates"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-version="markdownVersion"
:project-path="projectPath" :project-path="projectPath"
:project-namespace="projectNamespace" :project-namespace="projectNamespace"
:show-delete-button="showDeleteButton" :show-delete-button="showDeleteButton"
......
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
canAttachFile: { canAttachFile: {
type: Boolean, type: Boolean,
required: false, required: false,
...@@ -47,6 +52,7 @@ ...@@ -47,6 +52,7 @@
<markdown-field <markdown-field
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-version="markdownVersion"
:can-attach-file="canAttachFile" :can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
> >
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: { projectPath: {
type: String, type: String,
required: true, required: true,
...@@ -97,6 +102,7 @@ ...@@ -97,6 +102,7 @@
:form-state="formState" :form-state="formState"
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-version="markdownVersion"
:can-attach-file="canAttachFile" :can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
/> />
......
...@@ -1251,13 +1251,15 @@ export default class Notes { ...@@ -1251,13 +1251,15 @@ export default class Notes {
var postUrl = $originalContentEl.data('postUrl'); var postUrl = $originalContentEl.data('postUrl');
var targetId = $originalContentEl.data('targetId'); var targetId = $originalContentEl.data('targetId');
var targetType = $originalContentEl.data('targetType'); var targetType = $originalContentEl.data('targetType');
var markdownVersion = $originalContentEl.data('markdownVersion');
this.glForm = new GLForm($editForm.find('form'), this.enableGFM); this.glForm = new GLForm($editForm.find('form'), this.enableGFM);
$editForm $editForm
.find('form') .find('form')
.attr('action', `${postUrl}?html=true`) .attr('action', `${postUrl}?html=true`)
.attr('data-remote', 'true'); .attr('data-remote', 'true')
.attr('data-markdown-version', markdownVersion);
$editForm.find('.js-form-target-id').val(targetId); $editForm.find('.js-form-target-id').val(targetId);
$editForm.find('.js-form-target-type').val(targetType); $editForm.find('.js-form-target-type').val(targetType);
$editForm $editForm
......
...@@ -38,6 +38,11 @@ export default { ...@@ -38,6 +38,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
}, },
data() { data() {
return { return {
...@@ -350,6 +355,7 @@ Please check your network connection and try again.`; ...@@ -350,6 +355,7 @@ Please check your network connection and try again.`;
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath" :quick-actions-docs-path="quickActionsDocsPath"
:markdown-version="markdownVersion"
:add-spacing-classes="false"> :add-spacing-classes="false">
<textarea <textarea
id="note-body" id="note-body"
......
...@@ -92,6 +92,7 @@ export default { ...@@ -92,6 +92,7 @@ export default {
:is-editing="isEditing" :is-editing="isEditing"
:note-body="noteBody" :note-body="noteBody"
:note-id="note.id" :note-id="note.id"
:markdown-version="note.cached_markdown_version"
@handleFormUpdate="handleFormUpdate" @handleFormUpdate="handleFormUpdate"
@cancelForm="formCancelHandler" @cancelForm="formCancelHandler"
/> />
......
...@@ -24,6 +24,11 @@ export default { ...@@ -24,6 +24,11 @@ export default {
required: false, required: false,
default: 0, default: 0,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
saveButtonTitle: { saveButtonTitle: {
type: String, type: String,
required: false, required: false,
...@@ -156,6 +161,7 @@ export default { ...@@ -156,6 +161,7 @@ export default {
<markdown-field <markdown-field
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-version="markdownVersion"
:quick-actions-docs-path="quickActionsDocsPath" :quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false"> :add-spacing-classes="false">
<textarea <textarea
......
...@@ -43,6 +43,11 @@ export default { ...@@ -43,6 +43,11 @@ export default {
required: false, required: false,
default: true, default: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
}, },
data() { data() {
return { return {
...@@ -192,6 +197,7 @@ export default { ...@@ -192,6 +197,7 @@ export default {
<comment-form <comment-form
:noteable-type="noteableType" :noteable-type="noteableType"
:markdown-version="markdownVersion"
/> />
</div> </div>
</template> </template>
...@@ -15,6 +15,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -15,6 +15,7 @@ document.addEventListener('DOMContentLoaded', () => {
const notesDataset = document.getElementById('js-vue-notes').dataset; const notesDataset = document.getElementById('js-vue-notes').dataset;
const parsedUserData = JSON.parse(notesDataset.currentUserData); const parsedUserData = JSON.parse(notesDataset.currentUserData);
const noteableData = JSON.parse(notesDataset.noteableData); const noteableData = JSON.parse(notesDataset.noteableData);
const { markdownVersion } = notesDataset;
let currentUserData = {}; let currentUserData = {};
noteableData.noteableType = notesDataset.noteableType; noteableData.noteableType = notesDataset.noteableType;
...@@ -33,6 +34,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -33,6 +34,7 @@ document.addEventListener('DOMContentLoaded', () => {
return { return {
noteableData, noteableData,
currentUserData, currentUserData,
markdownVersion,
notesData: JSON.parse(notesDataset.notesData), notesData: JSON.parse(notesDataset.notesData),
}; };
}, },
...@@ -42,6 +44,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -42,6 +44,7 @@ document.addEventListener('DOMContentLoaded', () => {
noteableData: this.noteableData, noteableData: this.noteableData,
notesData: this.notesData, notesData: this.notesData,
userData: this.currentUserData, userData: this.currentUserData,
markdownVersion: this.markdownVersion,
}, },
}); });
}, },
......
...@@ -28,12 +28,16 @@ MarkdownPreview.prototype.ajaxCache = {}; ...@@ -28,12 +28,16 @@ MarkdownPreview.prototype.ajaxCache = {};
MarkdownPreview.prototype.showPreview = function ($form) { MarkdownPreview.prototype.showPreview = function ($form) {
var mdText; var mdText;
var markdownVersion;
var url;
var preview = $form.find('.js-md-preview'); var preview = $form.find('.js-md-preview');
var url = preview.data('url');
if (preview.hasClass('md-preview-loading')) { if (preview.hasClass('md-preview-loading')) {
return; return;
} }
mdText = $form.find('textarea.markdown-area').val(); mdText = $form.find('textarea.markdown-area').val();
markdownVersion = $form.attr('data-markdown-version');
url = this.versionedPreviewPath(preview.data('url'), markdownVersion);
if (mdText.trim().length === 0) { if (mdText.trim().length === 0) {
preview.text(this.emptyMessage); preview.text(this.emptyMessage);
...@@ -59,6 +63,14 @@ MarkdownPreview.prototype.showPreview = function ($form) { ...@@ -59,6 +63,14 @@ MarkdownPreview.prototype.showPreview = function ($form) {
} }
}; };
MarkdownPreview.prototype.versionedPreviewPath = function (markdownPreviewPath, markdownVersion) {
if (typeof markdownVersion === 'undefined') {
return markdownPreviewPath;
}
return `${markdownPreviewPath}${markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'}markdown_version=${markdownVersion}`;
};
MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) { MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) {
if (!url) { if (!url) {
return; return;
......
...@@ -139,6 +139,7 @@ export default { ...@@ -139,6 +139,7 @@ export default {
<div> <div>
<span class="mr-widget-pipeline-graph"> <span class="mr-widget-pipeline-graph">
<span <span
<<<<<<< HEAD
class="stage-cell" class="stage-cell"
> >
<linked-pipelines-mini-list <linked-pipelines-mini-list
...@@ -164,6 +165,19 @@ export default { ...@@ -164,6 +165,19 @@ export default {
v-if="triggered.length" v-if="triggered.length"
:triggered="triggered" :triggered="triggered"
/> />
=======
v-if="hasStages"
class="stage-cell"
>
<div
v-for="(stage, i) in pipeline.details.stages"
:key="i"
class="stage-container dropdown js-mini-pipeline-graph mr-widget-pipeline-stages"
>
<pipeline-stage :stage="stage" />
</div>
</span>
>>>>>>> upstream/master
</span> </span>
</div> </div>
</div> </div>
......
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import { s__ } from '~/locale';
import Flash from '../../../flash'; import Flash from '../../../flash';
import GLForm from '../../../gl_form'; import GLForm from '../../../gl_form';
import markdownHeader from './header.vue'; import markdownHeader from './header.vue';
...@@ -22,6 +23,11 @@ ...@@ -22,6 +23,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
addSpacingClasses: { addSpacingClasses: {
type: Boolean, type: Boolean,
required: false, required: false,
...@@ -92,10 +98,11 @@ ...@@ -92,10 +98,11 @@
if (text) { if (text) {
this.markdownPreviewLoading = true; this.markdownPreviewLoading = true;
this.$http.post(this.markdownPreviewPath, { text }) this.$http
.then(resp => resp.json()) .post(this.versionedPreviewPath(), { text })
.then(data => this.renderMarkdown(data)) .then(resp => resp.json())
.catch(() => new Flash('Error loading markdown preview')); .then(data => this.renderMarkdown(data))
.catch(() => new Flash(s__('Error loading markdown preview')));
} else { } else {
this.renderMarkdown(); this.renderMarkdown();
} }
...@@ -119,6 +126,13 @@ ...@@ -119,6 +126,13 @@
$(this.$refs['markdown-preview']).renderGFM(); $(this.$refs['markdown-preview']).renderGFM();
}); });
}, },
versionedPreviewPath() {
const { markdownPreviewPath, markdownVersion } = this;
return `${markdownPreviewPath}${
markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
}markdown_version=${markdownVersion}`;
},
}, },
}; };
</script> </script>
......
...@@ -233,6 +233,7 @@ ...@@ -233,6 +233,7 @@
max-width: 100%; max-width: 100%;
} }
<<<<<<< HEAD
/* /*
* Mixin that handles the container for the job logs (CI/CD and kubernetes pod logs) * Mixin that handles the container for the job logs (CI/CD and kubernetes pod logs)
*/ */
...@@ -332,6 +333,8 @@ ...@@ -332,6 +333,8 @@
animation: blinking-dots 1s linear infinite; animation: blinking-dots 1s linear infinite;
} }
=======
>>>>>>> upstream/master
@mixin borderless-status-icon($color) { @mixin borderless-status-icon($color) {
svg { svg {
border: 1px solid $color; border: 1px solid $color;
......
...@@ -14,6 +14,8 @@ module PreviewMarkdown ...@@ -14,6 +14,8 @@ module PreviewMarkdown
else {} else {}
end end
markdown_params[:markdown_engine] = result[:markdown_engine]
render json: { render json: {
body: view_context.markdown(result[:text], markdown_params), body: view_context.markdown(result[:text], markdown_params),
references: { references: {
......
...@@ -2,7 +2,10 @@ class ProjectsController < Projects::ApplicationController ...@@ -2,7 +2,10 @@ class ProjectsController < Projects::ApplicationController
include IssuableCollections include IssuableCollections
include ExtractsPath include ExtractsPath
include PreviewMarkdown include PreviewMarkdown
<<<<<<< HEAD
prepend EE::ProjectsController prepend EE::ProjectsController
=======
>>>>>>> upstream/master
include SendFileUpload include SendFileUpload
before_action :whitelist_query_limiting, only: [:create] before_action :whitelist_query_limiting, only: [:create]
......
...@@ -252,6 +252,7 @@ module IssuablesHelper ...@@ -252,6 +252,7 @@ module IssuablesHelper
issuableRef: issuable.to_reference, issuableRef: issuable.to_reference,
markdownPreviewPath: preview_markdown_path(parent), markdownPreviewPath: preview_markdown_path(parent),
markdownDocsPath: help_page_path('user/markdown'), markdownDocsPath: help_page_path('user/markdown'),
markdownVersion: issuable.cached_markdown_version,
issuableTemplates: issuable_templates(issuable), issuableTemplates: issuable_templates(issuable),
initialTitleHtml: markdown_field(issuable, :title), initialTitleHtml: markdown_field(issuable, :title),
initialTitleText: issuable.title, initialTitleText: issuable.title,
......
...@@ -107,6 +107,7 @@ module MarkupHelper ...@@ -107,6 +107,7 @@ module MarkupHelper
def markup(file_name, text, context = {}) def markup(file_name, text, context = {})
context[:project] ||= @project context[:project] ||= @project
context[:markdown_engine] ||= :redcarpet
html = context.delete(:rendered) || markup_unsafe(file_name, text, context) html = context.delete(:rendered) || markup_unsafe(file_name, text, context)
prepare_for_rendering(html, context) prepare_for_rendering(html, context)
end end
...@@ -120,7 +121,8 @@ module MarkupHelper ...@@ -120,7 +121,8 @@ module MarkupHelper
project: @project, project: @project,
project_wiki: @project_wiki, project_wiki: @project_wiki,
page_slug: wiki_page.slug, page_slug: wiki_page.slug,
issuable_state_filter_enabled: true issuable_state_filter_enabled: true,
markdown_engine: :redcarpet
} }
html = html =
......
...@@ -171,6 +171,7 @@ module NotesHelper ...@@ -171,6 +171,7 @@ module NotesHelper
registerPath: new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'), registerPath: new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'),
newSessionPath: new_session_path(:user, redirect_to_referer: 'yes'), newSessionPath: new_session_path(:user, redirect_to_referer: 'yes'),
markdownDocsPath: help_page_path('user/markdown'), markdownDocsPath: help_page_path('user/markdown'),
markdownVersion: issuable.cached_markdown_version,
quickActionsDocsPath: help_page_path('user/project/quick_actions'), quickActionsDocsPath: help_page_path('user/project/quick_actions'),
closePath: close_issuable_path(issuable), closePath: close_issuable_path(issuable),
reopenPath: reopen_issuable_path(issuable), reopenPath: reopen_issuable_path(issuable),
......
...@@ -40,6 +40,18 @@ module CacheMarkdownField ...@@ -40,6 +40,18 @@ module CacheMarkdownField
end end
end end
class MarkdownEngine
def self.from_version(version = nil)
return :common_mark if version.nil? || version == 0
if version < CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
:redcarpet
else
:common_mark
end
end
end
def skip_project_check? def skip_project_check?
false false
end end
...@@ -57,7 +69,7 @@ module CacheMarkdownField ...@@ -57,7 +69,7 @@ module CacheMarkdownField
# Banzai is less strict about authors, so don't always have an author key # Banzai is less strict about authors, so don't always have an author key
context[:author] = self.author if self.respond_to?(:author) context[:author] = self.author if self.respond_to?(:author)
context[:markdown_engine] = markdown_engine context[:markdown_engine] = MarkdownEngine.from_version(latest_cached_markdown_version)
context context
end end
...@@ -123,14 +135,6 @@ module CacheMarkdownField ...@@ -123,14 +135,6 @@ module CacheMarkdownField
end end
end end
def markdown_engine
if latest_cached_markdown_version < CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
:redcarpet
else
:common_mark
end
end
included do included do
cattr_reader :cached_markdown_fields do cattr_reader :cached_markdown_fields do
FieldData.new FieldData.new
......
...@@ -571,7 +571,7 @@ class Repository ...@@ -571,7 +571,7 @@ class Repository
end end
def rendered_readme def rendered_readme
MarkupHelper.markup_unsafe(readme.name, readme.data, project: project) if readme MarkupHelper.markup_unsafe(readme.name, readme.data, project: project, markdown_engine: :redcarpet) if readme
end end
cache_method :rendered_readme cache_method :rendered_readme
......
...@@ -62,6 +62,8 @@ class NoteEntity < API::Entities::Note ...@@ -62,6 +62,8 @@ class NoteEntity < API::Entities::Note
expose :attachment, using: NoteAttachmentEntity, if: -> (note, _) { note.attachment? } expose :attachment, using: NoteAttachmentEntity, if: -> (note, _) { note.attachment? }
expose :cached_markdown_version
private private
def current_user def current_user
......
...@@ -6,7 +6,8 @@ class PreviewMarkdownService < BaseService ...@@ -6,7 +6,8 @@ class PreviewMarkdownService < BaseService
success( success(
text: text, text: text,
users: users, users: users,
commands: commands.join(' ') commands: commands.join(' '),
markdown_engine: markdown_engine
) )
end end
...@@ -42,4 +43,8 @@ class PreviewMarkdownService < BaseService ...@@ -42,4 +43,8 @@ class PreviewMarkdownService < BaseService
def commands_target_id def commands_target_id
params[:quick_actions_target_id] params[:quick_actions_target_id]
end end
def markdown_engine
CacheMarkdownField::MarkdownEngine.from_version(params[:markdown_version].to_i)
end
end end
= form_for [@project.namespace.becomes(Namespace), @project, @issue], html: { class: 'issue-form common-note-form js-quick-submit js-requires-input' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @issue],
html: { class: 'issue-form common-note-form js-quick-submit js-requires-input' },
data: { markdown_version: @issue.cached_markdown_version } do |f|
= render 'shared/issuable/form', f: f, issuable: @issue = render 'shared/issuable/form', f: f, issuable: @issue
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @merge_request],
html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' },
data: { markdown_version: @merge_request.cached_markdown_version } do |f|
= render 'shared/issuable/form', f: f, issuable: @merge_request = render 'shared/issuable/form', f: f, issuable: @merge_request
= form_for [@project.namespace.becomes(Namespace), @project, @milestone], html: {class: 'milestone-form common-note-form js-quick-submit js-requires-input'} do |f| = form_for [@project.namespace.becomes(Namespace), @project, @milestone],
html: {class: 'milestone-form common-note-form js-quick-submit js-requires-input'},
data: { markdown_version: @milestone.cached_markdown_version } do |f|
= form_errors(@milestone) = form_errors(@milestone)
.row .row
.col-md-6 .col-md-6
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
%strong= @tag.name %strong= @tag.name
= form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name), html: { class: 'common-note-form release-form js-quick-submit' }) do |f| = form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name),
html: { class: 'common-note-form release-form js-quick-submit' },
data: { markdown_version: @release.cached_markdown_version }) do |f|
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here…" = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here…"
= render 'shared/notes/hints' = render 'shared/notes/hints'
......
- commit_message = @page.persisted? ? s_("WikiPageEdit|Update %{page_title}") : s_("WikiPageCreate|Create %{page_title}") - commit_message = @page.persisted? ? s_("WikiPageEdit|Update %{page_title}") : s_("WikiPageCreate|Create %{page_title}")
- commit_message = commit_message % { page_title: @page.title } - commit_message = commit_message % { page_title: @page.title }
= form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'wiki-form common-note-form prepend-top-default js-quick-submit' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post,
html: { class: 'wiki-form common-note-form prepend-top-default js-quick-submit' },
data: { markdown_version: CacheMarkdownField::CACHE_REDCARPET_VERSION } do |f|
= form_errors(@page) = form_errors(@page)
- if @page.persisted? - if @page.persisted?
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
.note-text.md .note-text.md
= markdown_field(note, :note) = markdown_field(note, :note)
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago') = edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago')
.original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore } } .original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore, markdown_version: note.cached_markdown_version } }
#{note.note} #{note.note}
- if note_editable - if note_editable
= render 'shared/notes/edit', note: note = render 'shared/notes/edit', note: note
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
= page_specific_javascript_tag('lib/ace.js') = page_specific_javascript_tag('lib/ace.js')
.snippet-form-holder .snippet-form-holder
= form_for @snippet, url: url, html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" } do |f| = form_for @snippet, url: url,
html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" },
data: { markdown_version: @snippet.cached_markdown_version } do |f|
= form_errors(@snippet) = form_errors(@snippet)
.form-group.row .form-group.row
......
...@@ -1322,6 +1322,7 @@ ActiveRecord::Schema.define(version: 20180702181530) do ...@@ -1322,6 +1322,7 @@ ActiveRecord::Schema.define(version: 20180702181530) do
add_index "import_export_uploads", ["project_id"], name: "index_import_export_uploads_on_project_id", using: :btree add_index "import_export_uploads", ["project_id"], name: "index_import_export_uploads_on_project_id", using: :btree
add_index "import_export_uploads", ["updated_at"], name: "index_import_export_uploads_on_updated_at", using: :btree add_index "import_export_uploads", ["updated_at"], name: "index_import_export_uploads_on_updated_at", using: :btree
<<<<<<< HEAD
create_table "index_statuses", force: :cascade do |t| create_table "index_statuses", force: :cascade do |t|
t.integer "project_id", null: false t.integer "project_id", null: false
t.datetime "indexed_at" t.datetime "indexed_at"
...@@ -1333,6 +1334,8 @@ ActiveRecord::Schema.define(version: 20180702181530) do ...@@ -1333,6 +1334,8 @@ ActiveRecord::Schema.define(version: 20180702181530) do
add_index "index_statuses", ["project_id"], name: "index_index_statuses_on_project_id", unique: true, using: :btree add_index "index_statuses", ["project_id"], name: "index_index_statuses_on_project_id", unique: true, using: :btree
=======
>>>>>>> upstream/master
create_table "internal_ids", id: :bigserial, force: :cascade do |t| create_table "internal_ids", id: :bigserial, force: :cascade do |t|
t.integer "project_id" t.integer "project_id"
t.integer "usage", null: false t.integer "usage", null: false
......
...@@ -60,7 +60,7 @@ Libraries with the following licenses are acceptable for use: ...@@ -60,7 +60,7 @@ Libraries with the following licenses are acceptable for use:
## Unacceptable Licenses ## Unacceptable Licenses
Libraries with the following licenses are unacceptable for use: Libraries with the following licenses require legal approval for use:
- [GNU GPL][GPL] (version 1, [version 2][GPLv2], [version 3][GPLv3], or any future versions): GPL-licensed libraries cannot be linked to from non-GPL projects. - [GNU GPL][GPL] (version 1, [version 2][GPLv2], [version 3][GPLv3], or any future versions): GPL-licensed libraries cannot be linked to from non-GPL projects.
- [GNU AGPLv3][AGPLv3]: AGPL-licensed libraries cannot be linked to from non-GPL projects. - [GNU AGPLv3][AGPLv3]: AGPL-licensed libraries cannot be linked to from non-GPL projects.
...@@ -68,6 +68,26 @@ Libraries with the following licenses are unacceptable for use: ...@@ -68,6 +68,26 @@ Libraries with the following licenses are unacceptable for use:
- [Facebook BSD + PATENTS][Facebook]: is a 3-clause BSD license with a patent grant that has been deemed [Category X][x-list] by the Apache foundation. - [Facebook BSD + PATENTS][Facebook]: is a 3-clause BSD license with a patent grant that has been deemed [Category X][x-list] by the Apache foundation.
- [WTFPL][WTFPL]: is a public domain dedication [rejected by the OSI (3.2)][WTFPL-OSI]. Also has a strong language which is not in accordance with our diversity policy. - [WTFPL][WTFPL]: is a public domain dedication [rejected by the OSI (3.2)][WTFPL-OSI]. Also has a strong language which is not in accordance with our diversity policy.
## GPL Cooperation Commitment
Before filing or continuing to prosecute any legal proceeding or claim (other than a Defensive Action) arising from termination of a Covered License, GitLab commits to extend to the person or entity (“you”) accused of violating the Covered License the following provisions regarding cure and reinstatement, taken from GPL version 3. As used here, the term ‘this License’ refers to the specific Covered License being enforced.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
GitLab intends this Commitment to be irrevocable, and binding and enforceable against GitLab and assignees of or successors to GitLab’s copyrights.
GitLab may modify this Commitment by publishing a new edition on this page or a successor location.
Definitions
‘Covered License’ means the GNU General Public License, version 2 (GPLv2), the GNU Lesser General Public License, version 2.1 (LGPLv2.1), or the GNU Library General Public License, version 2 (LGPLv2), all as published by the Free Software Foundation.
‘Defensive Action’ means a legal proceeding or claim that GitLab brings against you in response to a prior proceeding or claim initiated by you or your affiliate.
GitLab means GitLab Inc. and its affiliates and subsidiaries.
## Requesting Approval for Licenses ## Requesting Approval for Licenses
Libraries that are not listed in the [Acceptable Licenses][Acceptable-Licenses] or [Unacceptable Licenses][Unacceptable-Licenses] list can be submitted to the legal team for review. Please email `legal@gitlab.com` with the details. After a decision has been made, the original requestor is responsible for updating this document. Libraries that are not listed in the [Acceptable Licenses][Acceptable-Licenses] or [Unacceptable Licenses][Unacceptable-Licenses] list can be submitted to the legal team for review. Please email `legal@gitlab.com` with the details. After a decision has been made, the original requestor is responsible for updating this document.
......
...@@ -207,7 +207,7 @@ kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalanc ...@@ -207,7 +207,7 @@ kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalanc
> **Note**: Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run: > **Note**: Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run:
> >
> ```bash > ```bash
> kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}"`. > kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}".
> ``` > ```
The output is the external IP address of your cluster. This information can then The output is the external IP address of your cluster. This information can then
......
...@@ -9,6 +9,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -9,6 +9,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
[relative link 1](../relative) [relative link 1](../relative)
[relative link 2](./relative) [relative link 2](./relative)
[relative link 3](./e/f/relative) [relative link 3](./e/f/relative)
[spaced link](title with spaces)
HEREDOC HEREDOC
end end
...@@ -42,6 +43,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -42,6 +43,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -64,6 +66,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -64,6 +66,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -86,6 +89,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -86,6 +89,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
end end
...@@ -119,6 +123,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -119,6 +123,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -136,6 +141,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -136,6 +141,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -153,6 +159,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -153,6 +159,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
end end
......
...@@ -68,6 +68,26 @@ describe 'Snippet', :js do ...@@ -68,6 +68,26 @@ describe 'Snippet', :js do
end end
end end
context 'with cached Redcarpet html' do
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, cached_markdown_version: CacheMarkdownField::CACHE_REDCARPET_VERSION) }
let(:file_name) { 'test.md' }
let(:content) { "1. one\n - sublist\n" }
it 'renders correctly' do
expect(page).to have_xpath("//ol//li//ul")
end
end
context 'with cached CommonMark html' do
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
let(:file_name) { 'test.md' }
let(:content) { "1. one\n - sublist\n" }
it 'renders correctly' do
expect(page).not_to have_xpath("//ol//li//ul")
end
end
context 'switching to the simple viewer' do context 'switching to the simple viewer' do
before do before do
find('.js-blob-viewer-switch-btn[data-viewer=simple]').click find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
......
...@@ -185,6 +185,7 @@ describe IssuablesHelper do ...@@ -185,6 +185,7 @@ describe IssuablesHelper do
issuableRef: "##{issue.iid}", issuableRef: "##{issue.iid}",
markdownPreviewPath: "/#{@project.full_path}/preview_markdown", markdownPreviewPath: "/#{@project.full_path}/preview_markdown",
markdownDocsPath: '/help/user/markdown', markdownDocsPath: '/help/user/markdown',
markdownVersion: 11,
issuableTemplates: [], issuableTemplates: [],
projectPath: @project.path, projectPath: @project.path,
projectNamespace: @project.namespace.path, projectNamespace: @project.namespace.path,
......
...@@ -205,7 +205,9 @@ describe MarkupHelper do ...@@ -205,7 +205,9 @@ describe MarkupHelper do
it "uses Wiki pipeline for markdown files" do it "uses Wiki pipeline for markdown files" do
allow(@wiki).to receive(:format).and_return(:markdown) allow(@wiki).to receive(:format).and_return(:markdown)
expect(helper).to receive(:markdown_unsafe).with('wiki content', pipeline: :wiki, project: project, project_wiki: @wiki, page_slug: "nested/page", issuable_state_filter_enabled: true) expect(helper).to receive(:markdown_unsafe).with('wiki content',
pipeline: :wiki, project: project, project_wiki: @wiki, page_slug: "nested/page",
issuable_state_filter_enabled: true, markdown_engine: :redcarpet)
helper.render_wiki_content(@wiki) helper.render_wiki_content(@wiki)
end end
...@@ -236,19 +238,32 @@ describe MarkupHelper do ...@@ -236,19 +238,32 @@ describe MarkupHelper do
expect(helper.markup('foo.rst', content).encoding.name).to eq('UTF-8') expect(helper.markup('foo.rst', content).encoding.name).to eq('UTF-8')
end end
it "delegates to #markdown_unsafe when file name corresponds to Markdown" do it 'delegates to #markdown_unsafe when file name corresponds to Markdown' do
expect(helper).to receive(:gitlab_markdown?).with('foo.md').and_return(true) expect(helper).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
expect(helper).to receive(:markdown_unsafe).and_return('NOEL') expect(helper).to receive(:markdown_unsafe).and_return('NOEL')
expect(helper.markup('foo.md', content)).to eq('NOEL') expect(helper.markup('foo.md', content)).to eq('NOEL')
end end
it "delegates to #asciidoc_unsafe when file name corresponds to AsciiDoc" do it 'delegates to #asciidoc_unsafe when file name corresponds to AsciiDoc' do
expect(helper).to receive(:asciidoc?).with('foo.adoc').and_return(true) expect(helper).to receive(:asciidoc?).with('foo.adoc').and_return(true)
expect(helper).to receive(:asciidoc_unsafe).and_return('NOEL') expect(helper).to receive(:asciidoc_unsafe).and_return('NOEL')
expect(helper.markup('foo.adoc', content)).to eq('NOEL') expect(helper.markup('foo.adoc', content)).to eq('NOEL')
end end
it 'uses passed in rendered content' do
expect(helper).not_to receive(:gitlab_markdown?)
expect(helper).not_to receive(:markdown_unsafe)
expect(helper.markup('foo.md', content, rendered: '<p>NOEL</p>')).to eq('<p>NOEL</p>')
end
it 'defaults to Redcarpet' do
expect(helper).to receive(:markdown_unsafe).with(content, hash_including(markdown_engine: :redcarpet)).and_return('NOEL')
expect(helper.markup('foo.md', content)).to eq('NOEL')
end
end end
describe '#first_line_in_markdown' do describe '#first_line_in_markdown' do
......
...@@ -165,6 +165,7 @@ export const note = { ...@@ -165,6 +165,7 @@ export const note = {
report_abuse_path: report_abuse_path:
'/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_546&user_id=1', '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_546&user_id=1',
path: '/gitlab-org/gitlab-ce/notes/546', path: '/gitlab-org/gitlab-ce/notes/546',
cached_markdown_version: 11,
}; };
export const discussionMock = { export const discussionMock = {
......
...@@ -3,17 +3,61 @@ require 'spec_helper' ...@@ -3,17 +3,61 @@ require 'spec_helper'
describe Banzai::Filter::MarkdownFilter do describe Banzai::Filter::MarkdownFilter do
include FilterSpecHelper include FilterSpecHelper
context 'code block' do describe 'markdown engine from context' do
it 'adds language to lang attribute when specified' do it 'defaults to CommonMark' do
result = filter("```html\nsome code\n```") expect_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark).to receive(:render).and_return('test')
expect(result).to start_with("<pre><code lang=\"html\">") filter('test')
end end
it 'does not add language to lang attribute when not specified' do it 'uses Redcarpet' do
result = filter("```\nsome code\n```") expect_any_instance_of(Banzai::Filter::MarkdownEngines::Redcarpet).to receive(:render).and_return('test')
expect(result).to start_with("<pre><code>") filter('test', { markdown_engine: :redcarpet })
end
it 'uses CommonMark' do
expect_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark).to receive(:render).and_return('test')
filter('test', { markdown_engine: :common_mark })
end
end
describe 'code block' do
context 'using CommonMark' do
before do
stub_const('Banzai::Filter::MarkdownFilter::DEFAULT_ENGINE', :common_mark)
end
it 'adds language to lang attribute when specified' do
result = filter("```html\nsome code\n```")
expect(result).to start_with("<pre><code lang=\"html\">")
end
it 'does not add language to lang attribute when not specified' do
result = filter("```\nsome code\n```")
expect(result).to start_with("<pre><code>")
end
end
context 'using Redcarpet' do
before do
stub_const('Banzai::Filter::MarkdownFilter::DEFAULT_ENGINE', :redcarpet)
end
it 'adds language to lang attribute when specified' do
result = filter("```html\nsome code\n```")
expect(result).to start_with("\n<pre><code lang=\"html\">")
end
it 'does not add language to lang attribute when not specified' do
result = filter("```\nsome code\n```")
expect(result).to start_with("\n<pre><code>")
end
end end
end end
end end
...@@ -331,7 +331,10 @@ project: ...@@ -331,7 +331,10 @@ project:
- settings - settings
- ci_cd_settings - ci_cd_settings
- import_export_upload - import_export_upload
<<<<<<< HEAD
- vulnerability_feedback - vulnerability_feedback
=======
>>>>>>> upstream/master
award_emoji: award_emoji:
- awardable - awardable
- user - user
......
...@@ -370,4 +370,20 @@ describe CacheMarkdownField do ...@@ -370,4 +370,20 @@ describe CacheMarkdownField do
end end
end end
end end
describe CacheMarkdownField::MarkdownEngine do
subject { lambda { |version| CacheMarkdownField::MarkdownEngine.from_version(version) } }
it 'returns :common_mark as a default' do
expect(subject.call(nil)).to eq :common_mark
end
it 'returns :common_mark' do
expect(subject.call(CacheMarkdownField::CACHE_COMMONMARK_VERSION)).to eq :common_mark
end
it 'returns :redcarpet' do
expect(subject.call(CacheMarkdownField::CACHE_REDCARPET_VERSION)).to eq :redcarpet
end
end
end end
...@@ -64,4 +64,16 @@ describe PreviewMarkdownService do ...@@ -64,4 +64,16 @@ describe PreviewMarkdownService do
expect(result[:commands]).to eq 'Sets time estimate to 2y.' expect(result[:commands]).to eq 'Sets time estimate to 2y.'
end end
end end
it 'sets correct markdown engine' do
service = described_class.new(project, user, { markdown_version: CacheMarkdownField::CACHE_REDCARPET_VERSION })
result = service.execute
expect(result[:markdown_engine]).to eq :redcarpet
service = described_class.new(project, user, { markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION })
result = service.execute
expect(result[:markdown_engine]).to eq :common_mark
end
end end
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