Skip to content
代码片段 群组 项目
未验证 提交 17772f74 编辑于 作者: Rémy Coutable's avatar Rémy Coutable
浏览文件

Improve architecture of danger/feature_flag/


Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
上级 02b8f86b
No related branches found
No related tags found
无相关合并请求
...@@ -27,32 +27,23 @@ module Tooling ...@@ -27,32 +27,23 @@ module Tooling
For guidance on when to use a feature flag, please see the [documentation](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/#when-to-use-feature-flags). For guidance on when to use a feature flag, please see the [documentation](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/#when-to-use-feature-flags).
WARNING_MESSAGE WARNING_MESSAGE
def initialize(context:, feature_flag_helper:, helper:) def initialize(context:, added_files:, modified_files:, helper:)
@context = context @context = context
@feature_flag_helper = feature_flag_helper @added_files = added_files
@modified_files = modified_files
@helper = helper @helper = helper
end end
def check_feature_flag_yaml(feature_flag)
unless feature_flag.valid?
context.failure("#{helper.html_link(feature_flag.path)} isn't valid YAML! #{SEE_DOC}")
return
end
check_group(feature_flag)
check_feature_issue_url(feature_flag)
# Note: we don't check introduced_by_url as it's already done by danger/config_files/Dangerfile
check_rollout_issue_url(feature_flag)
check_milestone(feature_flag)
check_default_enabled(feature_flag)
end
def check_touched_feature_flag_files def check_touched_feature_flag_files
touched_feature_flag_files.each do |feature_flag| touched_feature_flag_files.each do |feature_flag|
check_feature_flag_yaml(feature_flag) check_feature_flag_yaml(feature_flag)
end end
end end
def feature_flag_file_touched?
touched_feature_flag_files.any?
end
def mr_has_backend_or_frontend_changes? def mr_has_backend_or_frontend_changes?
changes = helper.changes_by_category changes = helper.changes_by_category
changes.has_key?(:backend) || changes.has_key?(:frontend) changes.has_key?(:backend) || changes.has_key?(:frontend)
...@@ -68,22 +59,24 @@ module Tooling ...@@ -68,22 +59,24 @@ module Tooling
private private
attr_reader :context, :feature_flag_helper, :helper attr_reader :context, :added_files, :modified_files, :helper
def touched_feature_flag_files def check_feature_flag_yaml(feature_flag)
added_feature_flag_files + modified_feature_flag_files unless feature_flag.valid?
end context.failure("#{helper.html_link(feature_flag.path)} isn't valid YAML! #{SEE_DOC}")
return
def added_feature_flag_files end
feature_flag_helper.feature_flag_files(change_type: :added)
end
def modified_feature_flag_files check_group(feature_flag)
feature_flag_helper.feature_flag_files(change_type: :modified) check_feature_issue_url(feature_flag)
# Note: we don't check introduced_by_url as it's already done by danger/config_files/Dangerfile
check_rollout_issue_url(feature_flag)
check_milestone(feature_flag)
check_default_enabled(feature_flag)
end end
def feature_flag_file_touched? def touched_feature_flag_files
added_feature_flag_files.any? || modified_feature_flag_files.any? added_files + modified_files
end end
def check_group(feature_flag) def check_group(feature_flag)
...@@ -102,13 +95,13 @@ module Tooling ...@@ -102,13 +95,13 @@ module Tooling
return return
end end
mr_line = feature_flag.find_line_index("group:") add_message_on_line(
feature_flag: feature_flag,
if mr_line needle: "group:",
context.failure(format(SUGGEST_MR_COMMENT, group: mr_group_label), file: feature_flag.path, line: mr_line.succ) note: format(SUGGEST_MR_COMMENT, group: mr_group_label),
else fallback_note: %(Please add `group: "#{mr_group_label}"` in #{helper.html_link(feature_flag.path)}. #{SEE_DOC}),
context.failure(%(Please add `group: "#{mr_group_label}"` in #{helper.html_link(feature_flag.path)}. #{SEE_DOC})) message_method: :failure
end )
end end
def message_for_feature_flag_with_group!(feature_flag:, mr_group_label:) def message_for_feature_flag_with_group!(feature_flag:, mr_group_label:)
...@@ -121,27 +114,36 @@ module Tooling ...@@ -121,27 +114,36 @@ module Tooling
`group` is set to ~"#{feature_flag.group}" in #{helper.html_link(feature_flag.path)}, `group` is set to ~"#{feature_flag.group}" in #{helper.html_link(feature_flag.path)},
which does not match ~"#{mr_group_label}" set on the MR! which does not match ~"#{mr_group_label}" set on the MR!
FAILURE_MESSAGE FAILURE_MESSAGE
mr_line = feature_flag.find_line_index("group:")
if mr_line add_message_on_line(
context.failure(note, file: feature_flag.path, line: mr_line.succ) feature_flag: feature_flag,
else needle: "group:",
context.failure(note) note: note,
end message_method: :failure
)
end end
end end
def check_feature_issue_url(feature_flag) def check_feature_issue_url(feature_flag)
return unless feature_flag.missing_feature_issue_url? return unless feature_flag.missing_feature_issue_url?
note = "Consider filling `feature_issue_url:`" add_message_on_line(
mr_line = feature_flag.find_line_index("feature_issue_url:") feature_flag: feature_flag,
needle: "feature_issue_url:",
note: "Consider filling `feature_issue_url:`"
)
end
def add_message_on_line(feature_flag:, needle:, note:, fallback_note: note, message_method: :message)
mr_line = feature_flag.find_line_index(needle)
# rubocop:disable GitlabSecurity/PublicSend -- we allow calling context.message, context.warning & context.failure
if mr_line if mr_line
context.message(note, file: feature_flag.path, line: mr_line.succ) context.public_send(message_method, note, file: feature_flag.path, line: mr_line.succ)
else else
context.message(note) context.public_send(message_method, fallback_note)
end end
# rubocop:enable GitlabSecurity/PublicSend
end end
def check_rollout_issue_url(feature_flag) def check_rollout_issue_url(feature_flag)
...@@ -160,7 +162,7 @@ module Tooling ...@@ -160,7 +162,7 @@ module Tooling
def check_default_enabled(feature_flag) def check_default_enabled(feature_flag)
return unless feature_flag.default_enabled? return unless feature_flag.default_enabled?
if ::Feature::Shared::TYPES.dig(feature_flag.type.to_sym, :can_be_default_enabled) if ::Feature::Shared.can_be_default_enabled?(feature_flag.type)
note = <<~SUGGEST_COMMENT note = <<~SUGGEST_COMMENT
You're about to [release the feature with the feature flag](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Feature%20Flag%20Roll%20Out.md#optional-release-the-feature-with-the-feature-flag). You're about to [release the feature with the feature flag](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Feature%20Flag%20Roll%20Out.md#optional-release-the-feature-with-the-feature-flag).
This process can only be done **after** the [global rollout on production](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Feature%20Flag%20Roll%20Out.md#global-rollout-on-production). This process can only be done **after** the [global rollout on production](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Feature%20Flag%20Roll%20Out.md#global-rollout-on-production).
...@@ -192,7 +194,12 @@ module Tooling ...@@ -192,7 +194,12 @@ module Tooling
end end
end end
feature_flag_dangerfile = Tooling::FeatureFlagDangerfile.new(context: self, feature_flag_helper: feature_flag, helper: helper) feature_flag_dangerfile = Tooling::FeatureFlagDangerfile.new(
context: self,
added_files: feature_flag.feature_flag_files(danger_helper: helper, change_type: :added),
modified_files: feature_flag.feature_flag_files(danger_helper: helper, change_type: :modified),
helper: helper
)
feature_flag_dangerfile.check_touched_feature_flag_files feature_flag_dangerfile.check_touched_feature_flag_files
......
...@@ -99,5 +99,9 @@ module Shared ...@@ -99,5 +99,9 @@ module Shared
group group
default_enabled default_enabled
].freeze ].freeze
def self.can_be_default_enabled?(feature_flag_type)
TYPES.dig(feature_flag_type.to_sym, :can_be_default_enabled)
end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Feature::Shared, feature_category: :tooling do
describe '.can_be_default_enabled?' do
subject { described_class.can_be_default_enabled?(type) }
described_class::TYPES.each do |type, data|
context "when type is #{type}" do
let(:type) { type }
it { is_expected.to eq(data[:can_be_default_enabled]) }
end
end
end
end
...@@ -33,14 +33,14 @@ ...@@ -33,14 +33,14 @@
shared_examples 'an array of Found objects' do |change_type| shared_examples 'an array of Found objects' do |change_type|
it 'returns an array of Found objects' do it 'returns an array of Found objects' do
expect(feature_flag.feature_flag_files(change_type: change_type)).to contain_exactly(an_instance_of(described_class::Found), an_instance_of(described_class::Found)) expect(feature_flag.feature_flag_files(danger_helper: fake_helper, change_type: change_type)).to contain_exactly(an_instance_of(described_class::Found), an_instance_of(described_class::Found))
expect(feature_flag.feature_flag_files(change_type: change_type).map(&:path)).to eq(feature_flag_files) expect(feature_flag.feature_flag_files(danger_helper: fake_helper, change_type: change_type).map(&:path)).to eq(feature_flag_files)
end end
end end
shared_examples 'an empty array' do |change_type| shared_examples 'an empty array' do |change_type|
it 'returns an array of Found objects' do it 'returns an array of Found objects' do
expect(feature_flag.feature_flag_files(change_type: change_type)).to be_empty expect(feature_flag.feature_flag_files(danger_helper: fake_helper, change_type: change_type)).to be_empty
end end
end end
......
...@@ -10,8 +10,8 @@ module FeatureFlag ...@@ -10,8 +10,8 @@ module FeatureFlag
# - :added # - :added
# - :modified # - :modified
# - :deleted # - :deleted
def feature_flag_files(change_type:) def feature_flag_files(danger_helper:, change_type:)
files = helper.public_send("#{change_type}_files") # rubocop:disable GitlabSecurity/PublicSend files = danger_helper.public_send("#{change_type}_files") # rubocop:disable GitlabSecurity/PublicSend -- we allow calling danger_helper.added_files & danger_helper.modified_files
files.select { |path| path =~ %r{\A(ee/)?config/feature_flags/} }.map { |path| Found.build(path) } files.select { |path| path =~ %r{\A(ee/)?config/feature_flags/} }.map { |path| Found.build(path) }
end end
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册