Skip to content
Snippets Groups Projects
Commit a894e3d6 authored by Luke Duncalfe's avatar Luke Duncalfe :two:
Browse files

Merge branch '15624-multi-line-blockquotes-break-nested-single-line-blockquotes' into 'master'

[markdown] Multi-line blockquotes break nested single-line blockquotes

See merge request !95967
parents 16ad640a b96c029b
No related branches found
No related tags found
1 merge request!95967[markdown] Multi-line blockquotes break nested single-line blockquotes
Pipeline #629265609 passed with warnings
Pipeline: GitLab

#629270760

    Pipeline: GitLab

    #629267470

      ---
      name: markdown_corrected_blockquote
      introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95967
      rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372089
      milestone: '15.4'
      type: development
      group: group::project management
      default_enabled: false
      ......@@ -611,9 +611,10 @@ Quote break.
      If this section isn't rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/user/markdown.md#multiline-blockquote).
      GitLab Flavored Markdown extends the standard Markdown by also supporting multi-line blockquotes
      fenced by `>>>`:
      fenced by `>>>`, with a blank line before and after the block:
      ```markdown
      >>>
      If you paste a message from somewhere else
      ......@@ -621,6 +622,7 @@ that spans multiple lines,
      you can quote that without having to manually prepend `>` to every line!
      >>>
      ```
      >>>
      ......
      ......@@ -5,6 +5,37 @@ module Filter
      class BlockquoteFenceFilter < HTML::Pipeline::TextFilter
      REGEX = %r{
      #{::Gitlab::Regex.markdown_code_or_html_blocks}
      |
      (?=(?<=^\n|\A)>>>\ *\n.*\n>>>\ *(?=\n$|\z))(?:
      # Blockquote:
      # >>>
      # Anything, including code and HTML blocks
      # >>>
      (?<=^\n|\A)>>>\ *\n
      (?<quote>
      (?:
      # Any character that doesn't introduce a code or HTML block
      (?!
      ^```
      |
      ^<[^>]+?>\ *\n
      )
      .
      |
      # A code block
      \g<code>
      |
      # An HTML block
      \g<html>
      )+?
      )
      \n>>>\ *(?=\n$|\z)
      )
      }mx.freeze
      OLD_REGEX = %r{
      #{::Gitlab::Regex.markdown_code_or_html_blocks}
      |
      (?=^>>>\ *\n.*\n>>>\ *$)(?:
      # Blockquote:
      ......@@ -40,7 +71,7 @@ def initialize(text, context = nil, result = nil)
      end
      def call
      @text.gsub(REGEX) do
      @text.gsub(regex) do
      if $~[:quote]
      # keep the same number of source lines/positions by replacing the
      # fence lines with newlines
      ......@@ -50,6 +81,12 @@ def call
      end
      end
      end
      private
      def regex
      Feature.enabled?(:markdown_corrected_blockquote) ? REGEX : OLD_REGEX
      end
      end
      end
      end
      ......@@ -129,3 +129,27 @@ Double `>>>` inside HTML inside blockquote:
      >
      > Quote
      Requires a leading blank line
      >>>
      Not a quote
      >>>
      Requires a trailing blank line
      >>>
      Not a quote
      >>>
      Lorem
      Triple quoting is not our blockquote
      >>> foo
      >>> bar
      >>>
      > baz
      > boo
      >>> far
      >>>
      >>> faz
      ......@@ -129,3 +129,27 @@ Quote
      Quote
      >>>
      Requires a leading blank line
      >>>
      Not a quote
      >>>
      Requires a trailing blank line
      >>>
      Not a quote
      >>>
      Lorem
      Triple quoting is not our blockquote
      >>> foo
      >>> bar
      >>>
      > baz
      > boo
      >>> far
      >>>
      >>> faz
      ......@@ -14,10 +14,22 @@
      expect(output).to eq(expected)
      end
      it 'does not require newlines at start or end of string' do
      expect(filter(">>>\ntest\n>>>")).to eq("\n> test\n")
      end
      it 'allows trailing whitespace on blockquote fence lines' do
      expect(filter(">>> \ntest\n>>> ")).to eq("\n> test\n")
      end
      context 'when feature flag is turned off' do
      it 'does not require a leading or trailing blank line' do
      stub_feature_flags(markdown_corrected_blockquote: false)
      expect(filter("Foo\n>>>\ntest\n>>>\nBar")).to eq("Foo\n\n> test\n\nBar")
      end
      end
      context 'when incomplete blockquote fences with multiple blocks are present' do
      it 'does not raise timeout error' do
      test_string = ">>>#{"\n```\nfoo\n```" * 20}"
      ......
      ......@@ -32,4 +32,21 @@
      expect(result[:output]).to eq('foo foo f...')
      end
      context 'when multiline blockquote' do
      it 'data-sourcepos references correct line in source markdown' do
      markdown = <<~MD
      >>>
      foo
      >>>
      MD
      pipeline_output = described_class.call(markdown, {})[:output]
      pipeline_output = Banzai::Pipeline::PlainMarkdownPipeline.call(pipeline_output, {})[:output]
      sourcepos = pipeline_output.at('blockquote')['data-sourcepos']
      source_line = sourcepos.split(':').first.to_i
      expect(markdown.lines[source_line - 1]).to eq "foo\n"
      end
      end
      end
      ......@@ -63,11 +63,13 @@ def build_issue(issue_params = {})
      it 'wraps the note in a blockquote' do
      note_text = "This is a string\n"\
      "\n"\
      ">>>\n"\
      "with a blockquote\n"\
      "> That has a quote\n"\
      ">>>\n"
      note_result = " > This is a string\n"\
      " > \n"\
      " > \n"\
      " > > with a blockquote\n"\
      " > > > That has a quote\n"\
      ......
      0% Loading or .
      You are about to add 0 people to the discussion. Proceed with caution.
      Finish editing this message first!
      Please register or to comment