From 1d17049946ba3bd0b0f04e3559cf7f8540a39759 Mon Sep 17 00:00:00 2001 From: David O'Regan <doregan@gitlab.com> Date: Fri, 8 Jul 2022 14:54:02 +0000 Subject: [PATCH] Revert "Merge branch '353926' into 'master'" This reverts merge request !81833 --- app/models/wiki_page.rb | 3 +- .../development/wiki_front_matter.yml | 8 +++ lib/gitlab/wiki_pages/front_matter_parser.rb | 18 +++++- .../wiki_pages/front_matter_parser_spec.rb | 29 +++++++++- spec/models/wiki_page_spec.rb | 57 ++++++++++++++++++- 5 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 config/feature_flags/development/wiki_front_matter.yml diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 647b4e787c6aa5..63c60f5a89ec16 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -316,6 +316,7 @@ def serialize_front_matter(hash) end def update_front_matter(attrs) + return unless Gitlab::WikiPages::FrontMatterParser.enabled?(container) return unless attrs.has_key?(:front_matter) fm_yaml = serialize_front_matter(attrs[:front_matter]) @@ -326,7 +327,7 @@ def update_front_matter(attrs) def parsed_content strong_memoize(:parsed_content) do - Gitlab::WikiPages::FrontMatterParser.new(raw_content).parse + Gitlab::WikiPages::FrontMatterParser.new(raw_content, container).parse end end diff --git a/config/feature_flags/development/wiki_front_matter.yml b/config/feature_flags/development/wiki_front_matter.yml new file mode 100644 index 00000000000000..39196440d176e5 --- /dev/null +++ b/config/feature_flags/development/wiki_front_matter.yml @@ -0,0 +1,8 @@ +--- +name: wiki_front_matter +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27706 +rollout_issue_url: +milestone: '12.10' +type: development +group: group::editor +default_enabled: false diff --git a/lib/gitlab/wiki_pages/front_matter_parser.rb b/lib/gitlab/wiki_pages/front_matter_parser.rb index ee30fa907f4aac..071b0dde61919c 100644 --- a/lib/gitlab/wiki_pages/front_matter_parser.rb +++ b/lib/gitlab/wiki_pages/front_matter_parser.rb @@ -3,6 +3,8 @@ module Gitlab module WikiPages class FrontMatterParser + FEATURE_FLAG = :wiki_front_matter + # We limit the maximum length of text we are prepared to parse as YAML, to # avoid exploitations and attempts to consume memory and CPU. We allow for: # - a title line @@ -28,12 +30,18 @@ def initialize(content:, front_matter: {}, reason: nil, error: nil) end # @param [String] wiki_content - def initialize(wiki_content) + # @param [FeatureGate] feature_gate The scope for feature availability + def initialize(wiki_content, feature_gate) @wiki_content = wiki_content + @feature_gate = feature_gate + end + + def self.enabled?(gate = nil) + Feature.enabled?(FEATURE_FLAG, gate) end def parse - return empty_result unless wiki_content.present? + return empty_result unless enabled? && wiki_content.present? return empty_result(block.error) unless block.valid? Result.new(front_matter: block.data, content: strip_front_matter_block) @@ -86,12 +94,16 @@ def not_mapping? private - attr_reader :wiki_content + attr_reader :wiki_content, :feature_gate def empty_result(reason = nil, error = nil) Result.new(content: wiki_content, reason: reason, error: error) end + def enabled? + self.class.enabled?(feature_gate) + end + def block @block ||= parse_front_matter_block end diff --git a/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb b/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb index c0629c8d795a3a..3152dc2ad2f415 100644 --- a/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb +++ b/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb @@ -3,10 +3,11 @@ require 'spec_helper' RSpec.describe Gitlab::WikiPages::FrontMatterParser do - subject(:parser) { described_class.new(raw_content) } + subject(:parser) { described_class.new(raw_content, gate) } let(:content) { 'This is the content' } let(:end_divider) { '---' } + let(:gate) { stub_feature_flag_gate('Gate') } let(:with_front_matter) do <<~MD @@ -61,6 +62,32 @@ def have_correct_front_matter it { is_expected.to have_attributes(reason: :no_match) } end + context 'the feature flag is disabled' do + let(:raw_content) { with_front_matter } + + before do + stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => false) + end + + it { is_expected.to have_attributes(front_matter: be_empty, content: raw_content) } + end + + context 'the feature flag is enabled for the gated object' do + let(:raw_content) { with_front_matter } + + before do + stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => gate) + end + + it do + is_expected.to have_attributes( + front_matter: have_correct_front_matter, + content: content + "\n", + reason: be_nil + ) + end + end + context 'the end divider is ...' do let(:end_divider) { '...' } let(:raw_content) { with_front_matter } diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 51970064c54453..96c396f085c60f 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -24,6 +24,14 @@ def wiki container.wiki end + def disable_front_matter + stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => false) + end + + def enable_front_matter_for(thing) + stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => thing) + end + # Use for groups of tests that do not modify their `subject`. # # include_context 'subject is persisted page', title: 'my title' @@ -40,6 +48,12 @@ def wiki it { expect(wiki_page).to have_attributes(front_matter: {}, content: content) } end + shared_examples 'a page with front-matter' do + let(:front_matter) { { title: 'Foo', slugs: %w[slug_a slug_b] } } + + it { expect(wiki_page.front_matter).to eq(front_matter) } + end + context 'the wiki page has front matter' do let(:content) do <<~MD @@ -54,13 +68,27 @@ def wiki MD end - it 'has front-matter' do - expect(wiki_page.front_matter).to eq({ title: 'Foo', slugs: %w[slug_a slug_b] }) - end + it_behaves_like 'a page with front-matter' it 'strips the front matter from the content' do expect(wiki_page.content.strip).to eq('My actual content') end + + context 'the feature flag is off' do + before do + disable_front_matter + end + + it_behaves_like 'a page without front-matter' + + context 'but enabled for the container' do + before do + enable_front_matter_for(container) + end + + it_behaves_like 'a page with front-matter' + end + end end context 'the wiki page does not have front matter' do @@ -443,6 +471,29 @@ def wiki end end + context 'the front-matter feature flag is not enabled' do + before do + disable_front_matter + end + + it 'does not update the front-matter' do + content = subject.content + subject.update(front_matter: { slugs: ['x'] }) + + page = wiki.find_page(subject.title) + + expect([subject, page]).to all(have_attributes(front_matter: be_empty, content: content)) + end + + context 'but it is enabled for the container' do + before do + enable_front_matter_for(container) + end + + it_behaves_like 'able to update front-matter' + end + end + it 'updates the wiki-page front-matter and content together' do content = 'totally new content' subject.update(content: content, front_matter: { slugs: ['x'] }) -- GitLab