Commit fedecbbe authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'jprovazn-remove-redcarpet' into 'master'

Remove Redcarpet markdown engine

Closes #51374

See merge request gitlab-org/gitlab-ce!24819
parents fb296ab5 b2c70230
...@@ -116,7 +116,6 @@ gem 'html-pipeline', '~> 2.8' ...@@ -116,7 +116,6 @@ gem 'html-pipeline', '~> 2.8'
gem 'deckar01-task_list', '2.2.0' gem 'deckar01-task_list', '2.2.0'
gem 'gitlab-markup', '~> 1.6.5' gem 'gitlab-markup', '~> 1.6.5'
gem 'github-markup', '~> 1.7.0', require: 'github/markup' gem 'github-markup', '~> 1.7.0', require: 'github/markup'
gem 'redcarpet', '~> 3.4'
gem 'commonmarker', '~> 0.17' gem 'commonmarker', '~> 0.17'
gem 'RedCloth', '~> 4.3.2' gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~> 6.0' gem 'rdoc', '~> 6.0'
......
...@@ -682,7 +682,6 @@ GEM ...@@ -682,7 +682,6 @@ GEM
recaptcha (3.0.0) recaptcha (3.0.0)
json json
recursive-open-struct (1.1.0) recursive-open-struct (1.1.0)
redcarpet (3.4.0)
redis (3.3.5) redis (3.3.5)
redis-actionpack (5.0.2) redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6) actionpack (>= 4.0, < 6)
...@@ -1118,7 +1117,6 @@ DEPENDENCIES ...@@ -1118,7 +1117,6 @@ DEPENDENCIES
rdoc (~> 6.0) rdoc (~> 6.0)
re2 (~> 1.1.1) re2 (~> 1.1.1)
recaptcha (~> 3.0) recaptcha (~> 3.0)
redcarpet (~> 3.4)
redis (~> 3.2) redis (~> 3.2)
redis-namespace (~> 1.6.0) redis-namespace (~> 1.6.0)
redis-rails (~> 5.0.2) redis-rails (~> 5.0.2)
......
...@@ -28,16 +28,13 @@ MarkdownPreview.prototype.ajaxCache = {}; ...@@ -28,16 +28,13 @@ 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);
...@@ -67,16 +64,6 @@ MarkdownPreview.prototype.showPreview = function($form) { ...@@ -67,16 +64,6 @@ 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;
......
...@@ -108,11 +108,6 @@ export default { ...@@ -108,11 +108,6 @@ export default {
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,
...@@ -313,7 +308,6 @@ export default { ...@@ -313,7 +308,6 @@ export default {
: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,11 +20,6 @@ export default { ...@@ -20,11 +20,6 @@ export default {
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,
...@@ -48,7 +43,6 @@ export default { ...@@ -48,7 +43,6 @@ 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"
:can-attach-file="canAttachFile" :can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
> >
......
...@@ -39,11 +39,6 @@ export default { ...@@ -39,11 +39,6 @@ export default {
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,
...@@ -101,7 +96,6 @@ export default { ...@@ -101,7 +96,6 @@ export default {
: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"
/> />
......
...@@ -1239,15 +1239,13 @@ export default class Notes { ...@@ -1239,15 +1239,13 @@ 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
......
...@@ -39,11 +39,6 @@ export default { ...@@ -39,11 +39,6 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
}, },
data() { data() {
return { return {
...@@ -342,7 +337,6 @@ Please check your network connection and try again.`; ...@@ -342,7 +337,6 @@ 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
......
...@@ -111,7 +111,6 @@ export default { ...@@ -111,7 +111,6 @@ export default {
:line="line" :line="line"
:note="note" :note="note"
:help-page-path="helpPagePath" :help-page-path="helpPagePath"
:markdown-version="note.cached_markdown_version"
@handleFormUpdate="handleFormUpdate" @handleFormUpdate="handleFormUpdate"
@cancelForm="formCancelHandler" @cancelForm="formCancelHandler"
/> />
......
...@@ -26,11 +26,6 @@ export default { ...@@ -26,11 +26,6 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
saveButtonTitle: { saveButtonTitle: {
type: String, type: String,
required: false, required: false,
...@@ -202,7 +197,6 @@ export default { ...@@ -202,7 +197,6 @@ 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"
:line="line" :line="line"
:note="discussionNote" :note="discussionNote"
......
...@@ -44,11 +44,6 @@ export default { ...@@ -44,11 +44,6 @@ export default {
required: false, required: false,
default: true, default: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
helpPagePath: { helpPagePath: {
type: String, type: String,
required: false, required: false,
...@@ -216,10 +211,6 @@ export default { ...@@ -216,10 +211,6 @@ export default {
</template> </template>
</ul> </ul>
<comment-form <comment-form v-if="!commentsDisabled" :noteable-type="noteableType" />
v-if="!commentsDisabled"
:noteable-type="noteableType"
:markdown-version="markdownVersion"
/>
</div> </div>
</template> </template>
...@@ -18,7 +18,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -18,7 +18,6 @@ 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 = parseInt(notesDataset.markdownVersion, 10);
let currentUserData = {}; let currentUserData = {};
noteableData.noteableType = notesDataset.noteableType; noteableData.noteableType = notesDataset.noteableType;
...@@ -37,7 +36,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -37,7 +36,6 @@ document.addEventListener('DOMContentLoaded', () => {
return { return {
noteableData, noteableData,
currentUserData, currentUserData,
markdownVersion,
notesData: JSON.parse(notesDataset.notesData), notesData: JSON.parse(notesDataset.notesData),
}; };
}, },
...@@ -47,7 +45,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -47,7 +45,6 @@ document.addEventListener('DOMContentLoaded', () => {
noteableData: this.noteableData, noteableData: this.noteableData,
notesData: this.notesData, notesData: this.notesData,
userData: this.currentUserData, userData: this.currentUserData,
markdownVersion: this.markdownVersion,
}, },
}); });
}, },
......
...@@ -27,11 +27,6 @@ export default { ...@@ -27,11 +27,6 @@ export default {
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,
...@@ -158,7 +153,7 @@ export default { ...@@ -158,7 +153,7 @@ export default {
this.markdownPreviewLoading = true; this.markdownPreviewLoading = true;
this.markdownPreview = __('Loading…'); this.markdownPreview = __('Loading…');
this.$http this.$http
.post(this.versionedPreviewPath(), { text }) .post(this.markdownPreviewPath, { text })
.then(resp => resp.json()) .then(resp => resp.json())
.then(data => this.renderMarkdown(data)) .then(data => this.renderMarkdown(data))
.catch(() => new Flash(__('Error loading markdown preview'))); .catch(() => new Flash(__('Error loading markdown preview')));
...@@ -186,13 +181,6 @@ export default { ...@@ -186,13 +181,6 @@ export default {
.then(() => $(this.$refs['markdown-preview']).renderGFM()) .then(() => $(this.$refs['markdown-preview']).renderGFM())
.catch(() => new Flash(__('Error rendering markdown preview'))); .catch(() => new Flash(__('Error rendering markdown preview')));
}, },
versionedPreviewPath() {
const { markdownPreviewPath, markdownVersion } = this;
return `${markdownPreviewPath}${
markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
}markdown_version=${markdownVersion}`;
},
}, },
}; };
</script> </script>
......
...@@ -16,8 +16,6 @@ module PreviewMarkdown ...@@ -16,8 +16,6 @@ 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: {
......
...@@ -268,7 +268,6 @@ module IssuablesHelper ...@@ -268,7 +268,6 @@ 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,
lockVersion: issuable.lock_version, lockVersion: issuable.lock_version,
issuableTemplates: issuable_templates(issuable), issuableTemplates: issuable_templates(issuable),
initialTitleHtml: markdown_field(issuable, :title), initialTitleHtml: markdown_field(issuable, :title),
......
...@@ -116,7 +116,6 @@ module MarkupHelper ...@@ -116,7 +116,6 @@ module MarkupHelper
def markup(file_name, text, context = {}) def markup(file_name, text, context = {})
context[:project] ||= @project context[:project] ||= @project
context[:markdown_engine] ||= :redcarpet unless commonmark_for_repositories_enabled?
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
...@@ -132,7 +131,6 @@ module MarkupHelper ...@@ -132,7 +131,6 @@ module MarkupHelper
page_slug: wiki_page.slug, page_slug: wiki_page.slug,
issuable_state_filter_enabled: true issuable_state_filter_enabled: true
) )
context[:markdown_engine] ||= :redcarpet unless commonmark_for_repositories_enabled?
html = html =
case wiki_page.format case wiki_page.format
...@@ -187,10 +185,6 @@ module MarkupHelper ...@@ -187,10 +185,6 @@ module MarkupHelper
end end
end end
def commonmark_for_repositories_enabled?
Feature.enabled?(:commonmark_for_repositories, default_enabled: true)
end
private private
# Return +text+, truncated to +max_chars+ characters, excluding any HTML # Return +text+, truncated to +max_chars+ characters, excluding any HTML
......
...@@ -171,7 +171,6 @@ module NotesHelper ...@@ -171,7 +171,6 @@ 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),
......
...@@ -265,10 +265,6 @@ module ProjectsHelper ...@@ -265,10 +265,6 @@ module ProjectsHelper
link_to 'BFG', 'https://rtyley.github.io/bfg-repo-cleaner/', target: '_blank', rel: 'noopener noreferrer' link_to 'BFG', 'https://rtyley.github.io/bfg-repo-cleaner/', target: '_blank', rel: 'noopener noreferrer'
end end
def legacy_render_context(params)
params[:legacy_render] ? { markdown_engine: :redcarpet } : {}
end
def explore_projects_tab? def explore_projects_tab?
current_page?(explore_projects_path) || current_page?(explore_projects_path) ||
current_page?(trending_explore_projects_path) || current_page?(trending_explore_projects_path) ||
......
...@@ -13,7 +13,6 @@ module CacheMarkdownField ...@@ -13,7 +13,6 @@ module CacheMarkdownField
extend ActiveSupport::Concern extend ActiveSupport::Concern
# Increment this number every time the renderer changes its output # Increment this number every time the renderer changes its output
CACHE_REDCARPET_VERSION = 3
CACHE_COMMONMARK_VERSION_START = 10 CACHE_COMMONMARK_VERSION_START = 10
CACHE_COMMONMARK_VERSION = 14 CACHE_COMMONMARK_VERSION = 14
...@@ -42,18 +41,6 @@ module CacheMarkdownField ...@@ -42,18 +41,6 @@ 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
...@@ -71,7 +58,7 @@ module CacheMarkdownField ...@@ -71,7 +58,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] = MarkdownEngine.from_version(latest_cached_markdown_version) context[:markdown_engine] = :common_mark
context context
end end
...@@ -128,17 +115,7 @@ module CacheMarkdownField ...@@ -128,17 +115,7 @@ module CacheMarkdownField
end end
def latest_cached_markdown_version def latest_cached_markdown_version
return CacheMarkdownField::CACHE_COMMONMARK_VERSION unless cached_markdown_version CacheMarkdownField::CACHE_COMMONMARK_VERSION
if legacy_markdown?
CacheMarkdownField::CACHE_REDCARPET_VERSION
else
CacheMarkdownField::CACHE_COMMONMARK_VERSION
end
end
def legacy_markdown?
cached_markdown_version && cached_markdown_version.between?(1, CacheMarkdownField::CACHE_COMMONMARK_VERSION_START - 1)
end end
included do included do
......
...@@ -614,7 +614,6 @@ class Repository ...@@ -614,7 +614,6 @@ class Repository
return unless readme return unless readme
context = { project: project } context = { project: project }
context[:markdown_engine] = :redcarpet unless MarkupHelper.commonmark_for_repositories_enabled?
MarkupHelper.markup_unsafe(readme.name, readme.data, context) MarkupHelper.markup_unsafe(readme.name, readme.data, context)
end end
......
...@@ -270,9 +270,7 @@ class IssuableBaseService < BaseService ...@@ -270,9 +270,7 @@ class IssuableBaseService < BaseService
tasklist_toggler = TaskListToggleService.new(issuable.description, issuable.description_html, tasklist_toggler = TaskListToggleService.new(issuable.description, issuable.description_html,
line_source: update_task_params[:line_source], line_source: update_task_params[:line_source],
line_number: update_task_params[:line_number].to_i, line_number: update_task_params[:line_number].to_i,
toggle_as_checked: update_task_params[:checked], toggle_as_checked: update_task_params[:checked])
index: update_task_params[:index].to_i,
sourcepos: !issuable.legacy_markdown?)
unless tasklist_toggler.execute unless tasklist_toggler.execute
# if we make it here, the data is much newer than we thought it was - fail fast # if we make it here, the data is much newer than we thought it was - fail fast
......
...@@ -10,8 +10,7 @@ class PreviewMarkdownService < BaseService ...@@ -10,8 +10,7 @@ class PreviewMarkdownService < BaseService
text: text, text: text,
users: users, users: users,
suggestions: suggestions, suggestions: suggestions,
commands: commands.join(' '), commands: commands.join(' ')
markdown_engine: markdown_engine
) )
end end
...@@ -49,12 +48,4 @@ class PreviewMarkdownService < BaseService ...@@ -49,12 +48,4 @@ 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
if params[:legacy_render]
:redcarpet
else
CacheMarkdownField::MarkdownEngine.from_version(params[:markdown_version].to_i)
end
end
end end
...@@ -5,17 +5,13 @@ ...@@ -5,17 +5,13 @@
# We don't care if the text has changed above or below the specific checkbox, as long # We don't care if the text has changed above or below the specific checkbox, as long
# the checkbox still exists at exactly the same line number and the text is equal. # the checkbox still exists at exactly the same line number and the text is equal.
# If successful, new values are available in `updated_markdown` and `updated_markdown_html` # If successful, new values are available in `updated_markdown` and `updated_markdown_html`
#
# Note: once we've removed RedCarpet support, we can remove the `index` and `sourcepos`
# parameters
class TaskListToggleService class TaskListToggleService
attr_reader :updated_markdown, :updated_markdown_html attr_reader :updated_markdown, :updated_markdown_html
def initialize(markdown, markdown_html, line_source:, line_number:, toggle_as_checked:, index:, sourcepos: true) def initialize(markdown, markdown_html, line_source:, line_number:, toggle_as_checked:)
@markdown, @markdown_html = markdown, markdown_html @markdown, @markdown_html = markdown, markdown_html
@line_source, @line_number = line_source, line_number @line_source, @line_number = line_source, line_number
@toggle_as_checked = toggle_as_checked @toggle_as_checked = toggle_as_checked
@index, @use_sourcepos = index, sourcepos
@updated_markdown, @updated_markdown_html = nil @updated_markdown, @updated_markdown_html = nil
end end
...@@ -28,8 +24,8 @@ class TaskListToggleService ...@@ -28,8 +24,8 @@ class TaskListToggleService
private private
attr_reader :markdown, :markdown_html, :index, :toggle_as_checked attr_reader :markdown, :markdown_html, :toggle_as_checked
attr_reader :line_source, :line_number, :use_sourcepos attr_reader :line_source, :line_number
def toggle_markdown def toggle_markdown
source_lines = markdown.split("\n") source_lines = markdown.split("\n")
...@@ -68,17 +64,8 @@ class TaskListToggleService ...@@ -68,17 +64,8 @@ class TaskListToggleService
end end
# When using CommonMark, we should be able to use the embedded `sourcepos` attribute to # When using CommonMark, we should be able to use the embedded `sourcepos` attribute to
# target the exact line in the DOM. For RedCarpet, we need to use the index of the checkbox # target the exact line in the DOM.
# that was checked and match it with what we think is the same checkbox.
# The reason `sourcepos` is slightly more reliable is the case where a line of text is
# changed from a regular line into a checkbox (or vice versa). Then the checked index
# in the UI will be off from the list of checkboxes we've calculated locally.
# It's a rare circumstance, but since we can account for it, we do.
def get_html_checkbox(html) def get_html_checkbox(html)
if use_sourcepos html.css(".task-list-item[data-sourcepos^='#{line_number}:'] > input.task-list-item-checkbox").first
html.css(".task-list-item[data-sourcepos^='#{line_number}:'] > input.task-list-item-checkbox").first
else
html.css('.task-list-item-checkbox')[index - 1]
end
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
%div{ class: container_class } %div{ class: container_class }
.prepend-top-default.append-bottom-default .prepend-top-default.append-bottom-default
.wiki .wiki
= render_wiki_content(@wiki_home, legacy_render_context(params)) = render_wiki_content(@wiki_home)
- else - else
- can_create_wiki = can?(current_user, :create_wiki, @project) - can_create_wiki = can?(current_user, :create_wiki, @project)
.landing{ class: [('row-content-block row p-0 align-items-center' if can_create_wiki), ('content-block' unless can_create_wiki)] } .landing{ class: [('row-content-block row p-0 align-items-center' if can_create_wiki), ('content-block' unless can_create_wiki)] }
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
Write Write
%li %li
= link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id, legacy_render: params[:legacy_render]) do = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
= editing_preview_title(@blob.name) = editing_preview_title(@blob.name)
= form_tag(project_update_blob_path(@project, @id), method: :put, class: 'js-quick-submit js-requires-input js-edit-blob-form', data: blob_editor_paths(@project)) do = form_tag(project_update_blob_path(@project, @id), method: :put, class: 'js-quick-submit js-requires-input js-edit-blob-form', data: blob_editor_paths(@project)) do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.diff-content .diff-content
- if markup?(@blob.name) - if markup?(@blob.name)
.file-content.wiki.md{ class: ('use-csslab' if Feature.enabled?(:csslab)) } .file-content.wiki.md{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
= markup(@blob.name, @content, legacy_render_context(params)) = markup(@blob.name, @content)
- else - else
.file-content.code.js-syntax-highlight .file-content.code.js-syntax-highlight
- unless @diff_lines.empty? - unless @diff_lines.empty?
......
- blob = viewer.blob - blob = viewer.blob
- context = legacy_render_context(params) - context = blob.respond_to?(:rendered_markup) ? { rendered: blob.rendered_markup } : {}
- unless context[:markdown_engine] == :redcarpet
- context[:rendered] = blob.rendered_markup if blob.respond_to?(:rendered_markup)
.file-content.wiki.md{ class: ('use-csslab' if Feature.enabled?(:csslab)) } .file-content.wiki.md{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
= markup(blob.name, blob.data, context) = markup(blob.name, blob.data, context)
= form_for [@project.namespace.becomes(Namespace), @project, @issue], = form_for [@project.namespace.becomes(Namespace), @project, @issue],
html: { class: 'issue-form common-note-form js-quick-submit js-requires-input' }, html: { class: 'issue-form common-note-form js-quick-submit js-requires-input' } do |f|
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], = form_for [@project.namespace.becomes(Namespace), @project, @merge_request],
html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' }, html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f|
data: { markdown_version: @merge_request.cached_markdown_version } do |f|
= render 'shared/issuable/form', f: f, issuable: @merge_request, presenter: @mr_presenter = render 'shared/issuable/form', f: f, issuable: @merge_request, presenter: @mr_presenter
= form_for [@project.namespace.becomes(Namespace), @project, @milestone], = form_for [@project.namespace.becomes(Namespace), @project, @milestone],
html: { class: 'milestone-form common-note-form js-quick-submit js-requires-input' }, html: { class: 'milestone-form common-note-form js-quick-submit js-requires-input' } do |f|
data: { markdown_version: @milestone.cached_markdown_version } do |f|
= form_errors(@milestone) = form_errors(@milestone)
.row .row
.col-md-6 .col-md-6
......
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
= form_for(@release, method: :put, url: project_tag_release_path(@project, @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' }, html: { class: 'common-note-form release-form js-quick-submit' }) do |f|
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 }
- if params[:legacy_render] || !commonmark_for_repositories_enabled?
- markdown_version = CacheMarkdownField::CACHE_REDCARPET_VERSION
- else
- markdown_version = 0
= form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, = 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' }, html: { class: 'wiki-form common-note-form prepend-top-default js-quick-submit' },
data: { markdown_version: markdown_version, uploads_path: uploads_path } do |f| data: { uploads_path: uploads_path } do |f|
= form_errors(@page) = form_errors(@page)
- if @page.persisted? - if @page.persisted?
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
.blocks-container .blocks-container
.block.block-first .block.block-first
- if @sidebar_page - if @sidebar_page
= render_wiki_content(@sidebar_page, legacy_render_context(params)) = render_wiki_content(@sidebar_page)
- else - else
%ul.wiki-pages %ul.wiki-pages
= render @sidebar_wiki_entries, context: 'sidebar' = render @sidebar_wiki_entries, context: 'sidebar'
......
...@@ -27,6 +27,6 @@ ...@@ -27,6 +27,6 @@
.prepend-top-default.append-bottom-default .prepend-top-default.append-bottom-default
.wiki.md{ class: ('use-csslab' if Feature.enabled?(:csslab)) } .wiki.md{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
= render_wiki_content(@page, legacy_render_context(params)) = render_wiki_content(@page)
= render 'sidebar' = render 'sidebar'
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
.file-content.wiki .file-content.wiki
- snippet_chunks.each do |chunk| - snippet_chunks.each do |chunk|
- unless chunk[:data].empty? - unless chunk[:data].empty?
= markup(snippet.file_name, chunk[:data], legacy_render_context(params)) = markup(snippet.file_name, chunk[:data])
- else - else
.file-content.code .file-content.code
.nothing-here-block= _("Empty file") .nothing-here-block= _("Empty file")
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,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, markdown_version: note.cached_markdown_version } } .original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore } }
#{note.note} #{note.note}
- if note_editable - if note_editable
= render 'shared/notes/edit', note: note = render 'shared/notes/edit', note: note
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
.snippet-form-holder .snippet-form-holder
= form_for @snippet, url: url, = form_for @snippet, url: url,
html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" }, html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" } do |f|
data: { markdown_version: @snippet.cached_markdown_version } do |f|
= form_errors(@snippet) = form_errors(@snippet)
.form-group.row .form-group.row
......
---
title: Removed deprecated Redcarpet markdown engine.
merge_request:
author:
type: removed
...@@ -31,8 +31,10 @@ dependency to do so. Please see the [`github-markup` gem readme](https://github. ...@@ -31,8 +31,10 @@ dependency to do so. Please see the [`github-markup` gem readme](https://github.
> As of 11.1, GitLab uses the [CommonMark Ruby Library][commonmarker] for Markdown > As of 11.1, GitLab uses the [CommonMark Ruby Library][commonmarker] for Markdown
processing of all new issues, merge requests, comments, and other Markdown content processing of all new issues, merge requests, comments, and other Markdown content
in the GitLab system. As of 11.3, wiki pages and Markdown files (`.md`) in the in the GitLab system. As of 11.3, wiki pages and Markdown files (`.md`) in the
repositories are also processed with CommonMark. Older content in issues/comments repositories are also processed with CommonMark. As of 11.8, the [Redcarpet
are still processed using the [Redcarpet Ruby library][redcarpet]. Ruby library][redcarpet] has been removed and all issues/comments, including
those from pre-11.1, are now processed using [CommonMark Ruby
Library][commonmarker].
> >
> The documentation website had its [markdown engine migrated from Redcarpet to Kramdown](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/108) > The documentation website had its [markdown engine migrated from Redcarpet to Kramdown](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/108)
in October 2018. in October 2018.
...@@ -41,11 +43,11 @@ in October 2018. ...@@ -41,11 +43,11 @@ in October 2018.
### Transitioning to CommonMark ### Transitioning to CommonMark
You may have Markdown documents in your repository that were written using some You may have older issues/merge requests or Markdown documents in your
of the nuances of RedCarpet's version of Markdown. Since CommonMark uses a repository that were written using some of the nuances of RedCarpet's version
slightly stricter syntax, these documents may now display a little strangely of Markdown. Since CommonMark uses a slightly stricter syntax, these documents
since we've transitioned to CommonMark. Numbered lists with nested lists in may now display a little strangely since we've transitioned to CommonMark.
particular can be displayed incorrectly. Numbered lists with nested lists in particular can be displayed incorrectly.
It is usually quite easy to fix. In the case of a nested list such as this: It is usually quite easy to fix. In the case of a nested list such as this:
...@@ -65,11 +67,6 @@ simply add a space to each nested item: ...@@ -65,11 +67,6 @@ simply add a space to each nested item:
In the documentation below, we try to highlight some of the differences. In the documentation below, we try to highlight some of the differences.
If you have a need to view a document using RedCarpet, you can add the token
`legacy_render=1` to the end of the url, like this:
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md?legacy_render=1
If you have a large volume of Markdown files, it can be tedious to determine If you have a large volume of Markdown files, it can be tedious to determine
if they will be displayed correctly or not. You can use the if they will be displayed correctly or not. You can use the
[diff_redcarpet_cmark](https://gitlab.com/digitalmoksha/diff_redcarpet_cmark) [diff_redcarpet_cmark](https://gitlab.com/digitalmoksha/diff_redcarpet_cmark)
...@@ -677,7 +674,7 @@ Becomes: ...@@ -677,7 +674,7 @@ Becomes:
+ Or pluses + Or pluses
If a list item contains multiple paragraphs, If a list item contains multiple paragraphs,
each subsequent paragraph should be indented to the same level as the start of the list item text (_Redcarpet: paragraph should be indented with four spaces._) each subsequent paragraph should be indented to the same level as the start of the list item text
Example: Example:
...@@ -841,7 +838,7 @@ These details <em>will</em> remain <strong>hidden</strong> until expanded. ...@@ -841,7 +838,7 @@ These details <em>will</em> remain <strong>hidden</strong> until expanded.
</details> </details>
</p> </p>
**Note:** Markdown inside these tags is supported, as long as you have a blank line after the `</summary>` tag and before the `</details>` tag, as shown in the example. _Redcarpet does not support Markdown inside these tags. You can work around this by using HTML, for example you can use `<pre><code>` tags instead of [code fences](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#code-and-syntax-highlighting)._ **Note:** Markdown inside these tags is supported, as long as you have a blank line after the `</summary>` tag and before the `</details>` tag, as shown in the example.
```html ```html
<details> <details>
......
# frozen_string_literal: true
# `Redcarpet` markdown engine for GitLab's Banzai markdown filter.
# This module is used in Banzai::Filter::MarkdownFilter.
# Used gem is `redcarpet` which is a ruby library for markdown processing.
# Homepage: https://github.com/vmg/redcarpet
module Banzai
module Filter
module MarkdownEngines
class Redcarpet
OPTIONS = {
fenced_code_blocks: true,
footnotes: true,
lax_spacing: true,
no_intra_emphasis: true,
space_after_headers: true,
strikethrough: true,
superscript: true,
tables: true
}.freeze
def initialize(context = nil)
html_renderer = Banzai::Renderer::Redcarpet::HTML.new
@renderer = ::Redcarpet::Markdown.new(html_renderer, OPTIONS)
end
def render(text)
@renderer.render(text)
end
end
end
end
end
...@@ -45,8 +45,6 @@ module Banzai ...@@ -45,8 +45,6 @@ module Banzai
]).freeze ]).freeze
def call def call
return doc if context[:markdown_engine] == :redcarpet
doc.xpath(TEXT_QUERY).each do |node| doc.xpath(TEXT_QUERY).each do |node|
content = node.to_html content = node.to_html
......
# frozen_string_literal: true # frozen_string_literal: true
require 'rouge/plugins/common_mark' require 'rouge/plugins/common_mark'
require 'rouge/plugins/redcarpet'
# Generated HTML is transformed back to GFM by app/assets/javascripts/behaviors/markdown/nodes/code_block.js # Generated HTML is transformed back to GFM by app/assets/javascripts/behaviors/markdown/nodes/code_block.js
module Banzai module Banzai
......
# frozen_string_literal: true
module Banzai
module Renderer
module Redcarpet
class HTML < ::Redcarpet::Render::HTML
def block_code(code, lang)
lang_attr = lang ? %Q{ lang="#{lang}"} : ''
"\n<pre>" \
"<code#{lang_attr}>#{ERB::Util.html_escape(code)}</code>" \
"</pre>"
end
end
end
end
end
...@@ -13,7 +13,7 @@ require 'erb' ...@@ -13,7 +13,7 @@ require 'erb'
# #
# Raw Markdown # Raw Markdown
# -> `markdown` helper # -> `markdown` helper
# -> Redcarpet::Render::GitlabHTML converts Markdown to HTML # -> CommonMark::Render::GitlabHTML converts Markdown to HTML
# -> Post-process HTML # -> Post-process HTML
# -> `gfm` helper # -> `gfm` helper
# -> HTML::Pipeline # -> HTML::Pipeline
...@@ -324,31 +324,6 @@ describe 'GitLab Markdown', :aggregate_failures do ...@@ -324,31 +324,6 @@ describe 'GitLab Markdown', :aggregate_failures do
end end
end end
context 'Redcarpet documents' do
before do
allow_any_instance_of(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet')
@html = markdown(@feat.raw_markdown)
end
it 'processes certain elements differently' do
aggregate_failures 'parses superscript' do
expect(doc).to have_selector('sup', count: 3)
end
aggregate_failures 'permits style attribute in th elements' do
expect(doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center'
expect(doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right'
expect(doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left'
end
aggregate_failures 'permits style attribute in td elements' do
expect(doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center'
expect(doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right'
expect(doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left'
end
end
end
# Fake a `current_user` helper # Fake a `current_user` helper
def current_user def current_user
@feat.user @feat.user
......
...@@ -5,8 +5,8 @@ describe 'File blob', :js do ...@@ -5,8 +5,8 @@ describe 'File blob', :js do
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
def visit_blob(path, anchor: nil, ref: 'master', legacy_render: nil) def visit_blob(path, anchor: nil, ref: 'master')
visit project_blob_path(project, File.join(ref, path), anchor: anchor, legacy_render: legacy_render) visit project_blob_path(project, File.join(ref, path), anchor: anchor)
wait_for_requests wait_for_requests
end end
...@@ -171,21 +171,6 @@ describe 'File blob', :js do ...@@ -171,21 +171,6 @@ describe 'File blob', :js do
end end
end end
end end
context 'when rendering legacy markdown' do
before do
visit_blob('files/commonmark/file.md', legacy_render: 1)
wait_for_requests
end
it 'renders using RedCarpet' do
aggregate_failures do
expect(page).to have_content("sublist")
expect(page).to have_xpath("//ol//li//ul")
end
end
end
end end
context 'Markdown file (stored in LFS)' do context 'Markdown file (stored in LFS)' do
......
...@@ -81,17 +81,6 @@ describe 'Editing file blob', :js do ...@@ -81,17 +81,6 @@ describe 'Editing file blob', :js do
expect(page).to have_content("sublist") expect(page).to have_content("sublist")
expect(page).not_to have_xpath("//ol//li//ul") expect(page).not_to have_xpath("//ol//li//ul")
end end
it 'renders content with RedCarpet when legacy_render is set' do
visit project_edit_blob_path(project, tree_join(branch, readme_file_path), legacy_render: 1)
fill_editor(content: "1. one\\n - sublist\\n")
click_link 'Preview'
wait_for_requests
# the above generates a sublist list in RedCarpet
expect(page).to have_content("sublist")
expect(page).to have_xpath("//ol//li//ul")
end
end end
end end
......
...@@ -175,20 +175,6 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -175,20 +175,6 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page).to have_content("sublist") expect(page).to have_content("sublist")
expect(page).not_to have_xpath("//ol//li//ul") expect(page).not_to have_xpath("//ol//li//ul")
end end
it 'renders content with RedCarpet when legacy_render is set' do
wiki_page = create(:wiki_page,
wiki: project.wiki,
attrs: { title: 'home', content: "Empty content" })
visit(project_wiki_edit_path(project, wiki_page, legacy_render: 1))
fill_in :wiki_content, with: "1. one\n - sublist\n"
click_on "Preview"
# the above generates a sublist list in RedCarpet
expect(page).to have_content("sublist")
expect(page).to have_xpath("//ol//li//ul")
end
end end
end end
......
...@@ -80,19 +80,6 @@ describe 'Snippet', :js do ...@@ -80,19 +80,6 @@ describe 'Snippet', :js do
end end
end end
context 'when rendering legacy markdown' do
before do
visit snippet_path(snippet, legacy_render: 1)
wait_for_requests
end
it 'renders using RedCarpet' do
expect(page).to have_content("sublist")
expect(page).to have_xpath("//ol//li//ul")
end
end
context 'with cached CommonMark html' do 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(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
...@@ -100,14 +87,6 @@ describe 'Snippet', :js do ...@@ -100,14 +87,6 @@ describe 'Snippet', :js do
expect(page).not_to have_xpath("//ol//li//ul") expect(page).not_to have_xpath("//ol//li//ul")
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) }
it 'renders correctly' do
expect(page).to have_xpath("//ol//li//ul")
end
end
end end
context 'switching to the simple viewer' do context 'switching to the simple viewer' do
......
...@@ -36,19 +36,6 @@ describe 'Task Lists' do ...@@ -36,19 +36,6 @@ describe 'Task Lists' do
MARKDOWN MARKDOWN
end end
let(:nested_tasks_markdown_redcarpet) do
<<-EOT.strip_heredoc
- [ ] Task a
- [x] Task a.1
- [ ] Task a.2
- [ ] Task b
1. [ ] Task 1
1. [ ] Task 1.1
1. [x] Task 1.2
EOT
end
let(:nested_tasks_markdown) do let(:nested_tasks_markdown) do
<<-EOT.strip_heredoc <<-EOT.strip_heredoc
- [ ] Task a - [ ] Task a
...@@ -153,61 +140,6 @@ describe 'Task Lists' do ...@@ -153,61 +140,6 @@ describe 'Task Lists' do
expect(page).to have_content("1 of 1 task completed") expect(page).to have_content("1 of 1 task completed")
end end
end end
shared_examples 'shared nested tasks' do
before do
allow(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet')
visit_issue(project, issue)
end
it 'renders' do
expect(page).to have_selector('ul.task-list', count: 2)
expect(page).to have_selector('li.task-list-item', count: 7)
expect(page).to have_selector('ul input[checked]', count: 1)
expect(page).to have_selector('ol input[checked]', count: 1)
end
it 'solves tasks' do
expect(page).to have_content("2 of 7 tasks completed")
page.find('li.task-list-item', text: 'Task b').find('input').click
wait_for_requests
page.find('li.task-list-item ul li.task-list-item', text: 'Task a.2').find('input').click
wait_for_requests
page.find('li.task-list-item ol li.task-list-item', text: 'Task 1.1').find('input').click
wait_for_requests
expect(page).to have_content("5 of 7 tasks completed")
visit_issue(project, issue) # reload to see new system notes
expect(page).to have_content('marked the task Task b as complete')
expect(page).to have_content('marked the task Task a.2 as complete')
expect(page).to have_content('marked the task Task 1.1 as complete')
end
end
describe 'nested tasks', :js do
let(:cache_version) { CacheMarkdownField::CACHE_COMMONMARK_VERSION }
let!(:issue) do
create(:issue, description: nested_tasks_markdown, author: user, project: project,
cached_markdown_version: cache_version)
end
before do
visit_issue(project, issue)
end
context 'with Redcarpet' do
let(:cache_version) { CacheMarkdownField::CACHE_REDCARPET_VERSION }
let(:nested_tasks_markdown) { nested_tasks_markdown_redcarpet }
it_behaves_like 'shared nested tasks'
end
context 'with CommonMark' do
it_behaves_like 'shared nested tasks'
end
end
end end
describe 'for Notes' do describe 'for Notes' do
......
...@@ -6,7 +6,7 @@ started. ...@@ -6,7 +6,7 @@ started.
## Markdown ## Markdown
GitLab uses [Redcarpet](http://git.io/ld_NVQ) to parse all Markdown into GitLab uses [Commonmark](https://git.io/fhDag) to parse all Markdown into
HTML. HTML.
It has some special features. Let's try 'em out! It has some special features. Let's try 'em out!
......
...@@ -188,7 +188,6 @@ describe IssuablesHelper do ...@@ -188,7 +188,6 @@ 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: CacheMarkdownField::CACHE_COMMONMARK_VERSION,
issuableTemplates: [], issuableTemplates: [],
lockVersion: issue.lock_version, lockVersion: issue.lock_version,
projectPath: @project.path, projectPath: @project.path,
......
...@@ -212,17 +212,6 @@ describe MarkupHelper do ...@@ -212,17 +212,6 @@ describe MarkupHelper do
helper.render_wiki_content(@wiki) helper.render_wiki_content(@wiki)
end end
it 'uses Wiki pipeline for markdown files with RedCarpet if feature disabled' do
stub_feature_flags(commonmark_for_repositories: false)
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, markdown_engine: :redcarpet)
helper.render_wiki_content(@wiki)
end
it "uses Asciidoctor for asciidoc files" do it "uses Asciidoctor for asciidoc files" do
allow(@wiki).to receive(:format).and_return(:asciidoc) allow(@wiki).to receive(:format).and_return(:asciidoc)
...@@ -273,16 +262,6 @@ describe MarkupHelper do ...@@ -273,16 +262,6 @@ describe MarkupHelper do
it 'defaults to CommonMark' do it 'defaults to CommonMark' do
expect(helper.markup('foo.md', 'x^2')).to include('x^2') expect(helper.markup('foo.md', 'x^2')).to include('x^2')
end end
it 'honors markdown_engine for RedCarpet' do
expect(helper.markup('foo.md', 'x^2', { markdown_engine: :redcarpet })).to include('x<sup>2</sup>')
end
it 'uses RedCarpet if feature disabled' do
stub_feature_flags(commonmark_for_repositories: false)
expect(helper.markup('foo.md', 'x^2', { markdown_engine: :redcarpet })).to include('x<sup>2</sup>')
end
end end
describe '#first_line_in_markdown' do describe '#first_line_in_markdown' do
......
...@@ -535,18 +535,6 @@ describe ProjectsHelper do ...@@ -535,18 +535,6 @@ describe ProjectsHelper do
end end
end end
describe '#legacy_render_context' do
it 'returns the redcarpet engine' do
params = { legacy_render: '1' }
expect(helper.legacy_render_context(params)).to include(markdown_engine: :redcarpet)
end
it 'returns nothing' do
expect(helper.legacy_render_context({})).to be_empty
end
end
describe '#explore_projects_tab?' do describe '#explore_projects_tab?' do
subject { helper.explore_projects_tab? } subject { helper.explore_projects_tab? }
......
...@@ -10,12 +10,6 @@ describe Banzai::Filter::MarkdownFilter do ...@@ -10,12 +10,6 @@ describe Banzai::Filter::MarkdownFilter do
filter('test') filter('test')
end end
it 'uses Redcarpet' do
expect_any_instance_of(Banzai::Filter::MarkdownEngines::Redcarpet).to receive(:render).and_return('test')
filter('test', { markdown_engine: :redcarpet })
end
it 'uses CommonMark' do it 'uses CommonMark' do
expect_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark).to receive(:render).and_return('test') expect_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark).to receive(:render).and_return('test')
...@@ -47,24 +41,6 @@ describe Banzai::Filter::MarkdownFilter do ...@@ -47,24 +41,6 @@ describe Banzai::Filter::MarkdownFilter do
expect(result).to start_with('<pre><code lang="日">') expect(result).to start_with('<pre><code lang="日">')
end end
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
describe 'source line position' do describe 'source line position' do
...@@ -85,18 +61,6 @@ describe Banzai::Filter::MarkdownFilter do ...@@ -85,18 +61,6 @@ describe Banzai::Filter::MarkdownFilter do
expect(result).to eq '<p>test</p>' expect(result).to eq '<p>test</p>'
end end
end end
context 'using Redcarpet' do
before do
stub_const('Banzai::Filter::MarkdownFilter::DEFAULT_ENGINE', :redcarpet)
end
it 'does not support data-sourcepos' do
result = filter('test')
expect(result).to eq '<p>test</p>'
end
end
end end
describe 'footnotes in tables' do describe 'footnotes in tables' do
......
...@@ -26,11 +26,6 @@ describe Banzai::Filter::SpacedLinkFilter do ...@@ -26,11 +26,6 @@ describe Banzai::Filter::SpacedLinkFilter do
expect(doc.at_css('p')).to be_nil expect(doc.at_css('p')).to be_nil
end end
it 'does nothing when markdown_engine is redcarpet' do
exp = act = link
expect(filter(act, markdown_engine: :redcarpet).to_html).to eq exp
end
it 'does nothing with empty text' do it 'does nothing with empty text' do
link = '[](page slug)' link = '[](page slug)'
doc = filter("See #{link}") doc = filter("See #{link}")
......
...@@ -73,6 +73,7 @@ describe CacheMarkdownField do ...@@ -73,6 +73,7 @@ describe CacheMarkdownField do
let(:updated_html) { '<p dir="auto"><code>Bar</code></p>' } let(:updated_html) { '<p dir="auto"><code>Bar</code></p>' }
let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION) } let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
let(:cache_version) { CacheMarkdownField::CACHE_COMMONMARK_VERSION }
before do before do
stub_commonmark_sourcepos_disabled stub_commonmark_sourcepos_disabled
...@@ -97,20 +98,15 @@ describe CacheMarkdownField do ...@@ -97,20 +98,15 @@ describe CacheMarkdownField do
end end
context 'a changed markdown field' do context 'a changed markdown field' do
shared_examples 'with cache version' do |cache_version| let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
before do before do
thing.foo = updated_markdown thing.foo = updated_markdown
thing.save thing.save
end
it { expect(thing.foo_html).to eq(updated_html) }
it { expect(thing.cached_markdown_version).to eq(cache_version) }
end end
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION it { expect(thing.foo_html).to eq(updated_html) }
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION it { expect(thing.cached_markdown_version).to eq(cache_version) }
end end
context 'when a markdown field is set repeatedly to an empty string' do context 'when a markdown field is set repeatedly to an empty string' do
...@@ -143,22 +139,17 @@ describe CacheMarkdownField do ...@@ -143,22 +139,17 @@ describe CacheMarkdownField do
end end
context 'a non-markdown field changed' do context 'a non-markdown field changed' do
shared_examples 'with cache version' do |cache_version| let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
before do
thing.bar = 'OK'
thing.save
end
it { expect(thing.bar).to eq('OK') } before do
it { expect(thing.foo).to eq(markdown) } thing.bar = 'OK'
it { expect(thing.foo_html).to eq(html) } thing.save
it { expect(thing.cached_markdown_version).to eq(cache_version) }
end end
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION it { expect(thing.bar).to eq('OK') }
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION it { expect(thing.foo).to eq(markdown) }
it { expect(thing.foo_html).to eq(html) }
it { expect(thing.cached_markdown_version).to eq(cache_version) }
end end
context 'version is out of date' do context 'version is out of date' do
...@@ -173,73 +164,63 @@ describe CacheMarkdownField do ...@@ -173,73 +164,63 @@ describe CacheMarkdownField do
end end
describe '#cached_html_up_to_date?' do describe '#cached_html_up_to_date?' do
shared_examples 'with cache version' do |cache_version| let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
subject { thing.cached_html_up_to_date?(:foo) } subject { thing.cached_html_up_to_date?(:foo) }
it 'returns false when the version is absent' do it 'returns false when the version is absent' do
thing.cached_markdown_version = nil thing.cached_markdown_version = nil
is_expected.to be_falsy is_expected.to be_falsy
end end
it 'returns false when the version is too early' do it 'returns false when the version is too early' do
thing.cached_markdown_version -= 1 thing.cached_markdown_version -= 1
is_expected.to be_falsy is_expected.to be_falsy
end end
it 'returns false when the version is too late' do it 'returns false when the version is too late' do
thing.cached_markdown_version += 1 thing.cached_markdown_version += 1
is_expected.to be_falsy is_expected.to be_falsy
end end
it 'returns true when the version is just right' do it 'returns true when the version is just right' do
thing.cached_markdown_version = cache_version thing.cached_markdown_version = cache_version
is_expected.to be_truthy is_expected.to be_truthy
end end
it 'returns false if markdown has been changed but html has not' do it 'returns false if markdown has been changed but html has not' do
thing.foo = updated_html thing.foo = updated_html
is_expected.to be_falsy is_expected.to be_falsy
end end
it 'returns true if markdown has not been changed but html has' do it 'returns true if markdown has not been changed but html has' do
thing.foo_html = updated_html thing.foo_html = updated_html
is_expected.to be_truthy is_expected.to be_truthy
end end
it 'returns true if markdown and html have both been changed' do it 'returns true if markdown and html have both been changed' do
thing.foo = updated_markdown thing.foo = updated_markdown
thing.foo_html = updated_html thing.foo_html = updated_html
is_expected.to be_truthy is_expected.to be_truthy
end end
it 'returns false if the markdown field is set but the html is not' do it 'returns false if the markdown field is set but the html is not' do
thing.foo_html = nil thing.foo_html = nil
is_expected.to be_falsy is_expected.to be_falsy
end
end end
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION
end end
describe '#latest_cached_markdown_version' do describe '#latest_cached_markdown_version' do
subject { thing.latest_cached_markdown_version } subject { thing.latest_cached_markdown_version }
it 'returns redcarpet version' do
thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START - 1
is_expected.to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
end
it 'returns commonmark version' do it 'returns commonmark version' do
thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START + 1 thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START + 1
is_expected.to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION) is_expected.to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
...@@ -251,30 +232,6 @@ describe CacheMarkdownField do ...@@ -251,30 +232,6 @@ describe CacheMarkdownField do
end end
end end
describe '#legacy_markdown?' do
subject { thing.legacy_markdown? }
it 'returns true for redcarpet versions' do
thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START - 1
is_expected.to be_truthy
end
it 'returns false for commonmark versions' do
thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
is_expected.to be_falsey
end
it 'returns false if nil' do
thing.cached_markdown_version = nil
is_expected.to be_falsey
end
it 'returns false if 0' do
thing.cached_markdown_version = 0
is_expected.to be_falsey
end
end
describe '#refresh_markdown_cache' do describe '#refresh_markdown_cache' do
before do before do
thing.foo = updated_markdown thing.foo = updated_markdown
...@@ -303,39 +260,34 @@ describe CacheMarkdownField do ...@@ -303,39 +260,34 @@ describe CacheMarkdownField do
end end
describe '#refresh_markdown_cache!' do describe '#refresh_markdown_cache!' do
shared_examples 'with cache version' do |cache_version| let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
before do before do
thing.foo = updated_markdown thing.foo = updated_markdown
end end
it 'fills all html fields' do it 'fills all html fields' do
thing.refresh_markdown_cache! thing.refresh_markdown_cache!
expect(thing.foo_html).to eq(updated_html) expect(thing.foo_html).to eq(updated_html)
expect(thing.foo_html_changed?).to be_truthy expect(thing.foo_html_changed?).to be_truthy
expect(thing.baz_html_changed?).to be_truthy expect(thing.baz_html_changed?).to be_truthy
end end
it 'skips saving if not persisted' do it 'skips saving if not persisted' do
expect(thing).to receive(:persisted?).and_return(false) expect(thing).to receive(:persisted?).and_return(false)
expect(thing).not_to receive(:update_columns) expect(thing).not_to receive(:update_columns)
thing.refresh_markdown_cache! thing.refresh_markdown_cache!
end end
it 'saves the changes using #update_columns' do it 'saves the changes using #update_columns' do
expect(thing).to receive(:persisted?).and_return(true) expect(thing).to receive(:persisted?).and_return(true)
expect(thing).to receive(:update_columns) expect(thing).to receive(:update_columns)
.with("foo_html" => updated_html, "baz_html" => "", "cached_markdown_version" => cache_version) .with("foo_html" => updated_html, "baz_html" => "", "cached_markdown_version" => cache_version)
thing.refresh_markdown_cache! thing.refresh_markdown_cache!
end
end end
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION
it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION
end end
describe '#banzai_render_context' do describe '#banzai_render_context' do
...@@ -408,20 +360,4 @@ describe CacheMarkdownField do ...@@ -408,20 +360,4 @@ 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
...@@ -114,23 +114,4 @@ describe PreviewMarkdownService do ...@@ -114,23 +114,4 @@ describe PreviewMarkdownService do
expect(result[:commands]).to eq 'Tags this commit to v1.2.3 with "Stable release".' expect(result[:commands]).to eq 'Tags this commit to v1.2.3 with "Stable release".'
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
it 'honors the legacy_render parameter' do
service = described_class.new(project, user, { legacy_render: '1' })
result = service.execute
expect(result[:markdown_engine]).to eq :redcarpet
end
end end
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
require 'spec_helper' require 'spec_helper'
describe TaskListToggleService do describe TaskListToggleService do
let(:sourcepos) { true }
let(:markdown) do let(:markdown) do
<<-EOT.strip_heredoc <<-EOT.strip_heredoc
* [ ] Task 1 * [ ] Task 1
...@@ -40,87 +39,47 @@ describe TaskListToggleService do ...@@ -40,87 +39,47 @@ describe TaskListToggleService do
EOT EOT
end end
shared_examples 'task lists' do it 'checks Task 1' do
it 'checks Task 1' do toggler = described_class.new(markdown, markdown_html,
toggler = described_class.new(markdown, markdown_html, toggle_as_checked: true,
index: 1, toggle_as_checked: true, line_source: '* [ ] Task 1', line_number: 1)
line_source: '* [ ] Task 1', line_number: 1,
sourcepos: sourcepos)
expect(toggler.execute).to be_truthy expect(toggler.execute).to be_truthy
expect(toggler.updated_markdown.lines[0]).to eq "* [x] Task 1\n" expect(toggler.updated_markdown.lines[0]).to eq "* [x] Task 1\n"
expect(toggler.updated_markdown_html).to include('disabled checked> Task 1') expect(toggler.updated_markdown_html).to include('disabled checked> Task 1')
end end
it 'unchecks Item 1' do
toggler = described_class.new(markdown, markdown_html,
index: 3, toggle_as_checked: false,
line_source: '1. [X] Item 1', line_number: 6,
sourcepos: sourcepos)
expect(toggler.execute).to be_truthy
expect(toggler.updated_markdown.lines[5]).to eq "1. [ ] Item 1\n"
expect(toggler.updated_markdown_html).to include('disabled> Item 1')
end
it 'returns false if line_source does not match the text' do
toggler = described_class.new(markdown, markdown_html,
index: 2, toggle_as_checked: false,
line_source: '* [x] Task Added', line_number: 2,
sourcepos: sourcepos)
expect(toggler.execute).to be_falsey
end
it 'returns false if markdown is nil' do it 'unchecks Item 1' do
toggler = described_class.new(nil, markdown_html, toggler = described_class.new(markdown, markdown_html,
index: 2, toggle_as_checked: false, toggle_as_checked: false,
line_source: '* [x] Task Added', line_number: 2, line_source: '1. [X] Item 1', line_number: 6)
sourcepos: sourcepos)
expect(toggler.execute).to be_falsey expect(toggler.execute).to be_truthy
end expect(toggler.updated_markdown.lines[5]).to eq "1. [ ] Item 1\n"
expect(toggler.updated_markdown_html).to include('disabled> Item 1')
end
it 'returns false if markdown_html is nil' do it 'returns false if line_source does not match the text' do
toggler = described_class.new(markdown, nil, toggler = described_class.new(markdown, markdown_html,
index: 2, toggle_as_checked: false, toggle_as_checked: false,
line_source: '* [x] Task Added', line_number: 2, line_source: '* [x] Task Added', line_number: 2)
sourcepos: sourcepos)
expect(toggler.execute).to be_falsey expect(toggler.execute).to be_falsey
end
end end
context 'when using sourcepos' do it 'returns false if markdown is nil' do
it_behaves_like 'task lists' toggler = described_class.new(nil, markdown_html,
toggle_as_checked: false,
line_source: '* [x] Task Added', line_number: 2)
expect(toggler.execute).to be_falsey
end end
context 'when using checkbox indexing' do it 'returns false if markdown_html is nil' do
let(:sourcepos) { false } toggler = described_class.new(markdown, nil,
let(:markdown_html) do toggle_as_checked: false,
<<-EOT.strip_heredoc line_source: '* [x] Task Added', line_number: 2)
<ul class="task-list" dir="auto">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled> Task 1
</li>
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled checked> Task 2
</li>
</ul>
<p dir="auto">A paragraph</p>
<ol class="task-list" dir="auto">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled checked> Item 1
<ul class="task-list">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled> Sub-item 1
</li>
</ul>
</li>
</ol>
EOT
end
it_behaves_like 'task lists' expect(toggler.execute).to be_falsey
end 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