2021-03-11 19:13:27 +05:30
# frozen_string_literal: true
# rubocop:disable Style/SignalException
2021-04-17 20:07:23 +05:30
SEE_DOC = " See the [feature flag documentation](https://docs.gitlab.com/ee/development/feature_flags # feature-flag-definition-and-validation). "
2021-04-29 21:17:54 +05:30
FEATURE_FLAG_LABEL = " feature flag "
2023-06-20 00:43:36 +05:30
FEATURE_FLAG_EXISTS_LABEL = " #{ FEATURE_FLAG_LABEL } ::exists "
FEATURE_FLAG_SKIPPED_LABEL = " #{ FEATURE_FLAG_LABEL } ::skipped "
DEVOPS_LABELS_REQUIRING_FEATURE_FLAG_REVIEW = [ " devops::verify " ]
2021-03-11 19:13:27 +05:30
SUGGEST_MR_COMMENT = << ~ SUGGEST_COMMENT
` ` ` suggestion
group : " %<group>s "
` ` `
#{SEE_DOC}
SUGGEST_COMMENT
2023-06-20 00:43:36 +05:30
FEATURE_FLAG_ENFORCEMENT_WARNING = << ~ WARNING_MESSAGE
There were no new or modified feature flag YAML files detected in this MR .
If the changes here are already controlled under an existing feature flag , please add
the ~ " #{ FEATURE_FLAG_EXISTS_LABEL } " . Otherwise , if you think the changes here don ' t need
to be under a feature flag , please add the label ~ " #{ FEATURE_FLAG_SKIPPED_LABEL } " , and
add a short comment about why we skipped the feature flag .
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
2021-03-11 19:13:27 +05:30
def check_feature_flag_yaml ( feature_flag )
2021-06-08 01:23:25 +05:30
mr_group_label = helper . group_label
2021-03-11 19:13:27 +05:30
if feature_flag . group . nil?
message_for_feature_flag_missing_group! ( feature_flag : feature_flag , mr_group_label : mr_group_label )
else
message_for_feature_flag_with_group! ( feature_flag : feature_flag , mr_group_label : mr_group_label )
end
rescue Psych :: Exception
# YAML could not be parsed, fail the build.
2022-06-21 17:19:12 +05:30
fail " #{ helper . html_link ( feature_flag . path ) } isn't valid YAML! #{ SEE_DOC } "
2021-03-11 19:13:27 +05:30
rescue StandardError = > e
warn " There was a problem trying to check the Feature Flag file. Exception: #{ e . class . name } - #{ e . message } "
end
def message_for_feature_flag_missing_group! ( feature_flag : , mr_group_label : )
if mr_group_label . nil?
2022-06-21 17:19:12 +05:30
warn " Consider setting `group` in #{ helper . html_link ( feature_flag . path ) } . #{ SEE_DOC } "
2021-03-11 19:13:27 +05:30
else
mr_line = feature_flag . raw . lines . find_index ( " group: \n " )
if mr_line
markdown ( format ( SUGGEST_MR_COMMENT , group : mr_group_label ) , file : feature_flag . path , line : mr_line . succ )
else
2022-06-21 17:19:12 +05:30
warn %( Consider setting `group: " #{ mr_group_label } "` in #{ helper . html_link ( feature_flag . path ) } . #{ SEE_DOC } )
2021-03-11 19:13:27 +05:30
end
end
end
2021-09-30 23:02:18 +05:30
def message_for_global_rollout ( feature_flag )
return unless feature_flag . default_enabled == true
message = << ~ 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 % 20 Flag % 20 Roll % 20 Out . 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 % 20 Flag % 20 Roll % 20 Out . md #global-rollout-on-production).
Please make sure in [ the rollout issue ] ( #{feature_flag.rollout_issue_url}) that the preliminary steps have already been done. Otherwise, changing the YAML definition might not have the desired effect.
SUGGEST_COMMENT
mr_line = feature_flag . raw . lines . find_index { | l | l . include? ( 'default_enabled:' ) }
markdown ( message , file : feature_flag . path , line : mr_line . succ )
end
2021-03-11 19:13:27 +05:30
def message_for_feature_flag_with_group! ( feature_flag : , mr_group_label : )
return if feature_flag . group_match_mr_label? ( mr_group_label )
if mr_group_label . nil?
2022-05-07 20:08:51 +05:30
helper . labels_to_add << feature_flag . group
2021-03-11 19:13:27 +05:30
else
2022-06-21 17:19:12 +05:30
fail %( `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! )
2021-03-11 19:13:27 +05:30
end
end
2023-06-20 00:43:36 +05:30
def added_feature_flag_files
feature_flag . feature_flag_files ( change_type : :added )
end
def modified_feature_flag_files
feature_flag . feature_flag_files ( change_type : :modified )
end
2021-09-04 01:27:46 +05:30
def feature_flag_file_added?
2023-06-20 00:43:36 +05:30
added_feature_flag_files . any?
2021-09-04 01:27:46 +05:30
end
2023-06-20 00:43:36 +05:30
def feature_flag_file_modified?
modified_feature_flag_files . any?
2021-03-11 19:13:27 +05:30
end
2023-06-20 00:43:36 +05:30
def feature_flag_file_added_or_modified?
feature_flag_file_added? || feature_flag_file_modified?
end
def mr_has_backend_or_frontend_changes?
changes = helper . changes_by_category
changes . has_key? ( :backend ) || changes . has_key? ( :frontend )
end
def mr_missing_feature_flag_status_label?
( [ FEATURE_FLAG_EXISTS_LABEL , FEATURE_FLAG_SKIPPED_LABEL ] & helper . mr_labels ) . none?
end
def stage_requires_feature_flag_review?
DEVOPS_LABELS_REQUIRING_FEATURE_FLAG_REVIEW . include? ( feature_flag . stage_label )
end
added_feature_flag_files . each do | feature_flag |
2021-03-11 19:13:27 +05:30
check_feature_flag_yaml ( feature_flag )
end
2023-06-20 00:43:36 +05:30
modified_feature_flag_files . each do | feature_flag |
2021-09-30 23:02:18 +05:30
message_for_global_rollout ( feature_flag )
2021-09-04 01:27:46 +05:30
end
2021-09-30 23:02:18 +05:30
if helper . security_mr? && feature_flag_file_added?
fail " Feature flags are discouraged from security merge requests. Read the [security documentation](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/utilities/feature_flags.md) for details. "
2021-03-11 19:13:27 +05:30
end
2023-06-20 00:43:36 +05:30
if ! helper . security_mr? && mr_has_backend_or_frontend_changes? && stage_requires_feature_flag_review?
if feature_flag_file_added_or_modified? && ! helper . mr_has_labels? ( FEATURE_FLAG_EXISTS_LABEL )
# Feature flag config file touched in this MR, so let's add the label to avoid the warning.
helper . labels_to_add << FEATURE_FLAG_EXISTS_LABEL
end
warn FEATURE_FLAG_ENFORCEMENT_WARNING if mr_missing_feature_flag_status_label?
end