Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Dangerfile « feature_flag « danger - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 602ff1128f2df378e3630fb80472d9c42cc09736 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# frozen_string_literal: true
# rubocop:disable Style/SignalException

SEE_DOC = "See the [feature flag documentation](https://docs.gitlab.com/ee/development/feature_flags#feature-flag-definition-and-validation)."
FEATURE_FLAG_LABEL = "feature flag"
FEATURE_FLAG_EXISTS_LABEL = "#{FEATURE_FLAG_LABEL}::exists"
FEATURE_FLAG_SKIPPED_LABEL = "#{FEATURE_FLAG_LABEL}::skipped"
DEVOPS_LABELS_REQUIRING_FEATURE_FLAG_REVIEW = ["devops::verify"]

SUGGEST_MR_COMMENT = <<~SUGGEST_COMMENT
```suggestion
group: "%<group>s"
```

#{SEE_DOC}
SUGGEST_COMMENT

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

def check_feature_flag_yaml(feature_flag)
  mr_group_label = helper.group_label

  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.
  fail "#{helper.html_link(feature_flag.path)} isn't valid YAML! #{SEE_DOC}"
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?
    warn "Consider setting `group` in #{helper.html_link(feature_flag.path)}. #{SEE_DOC}"
  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
      warn %(Consider setting `group: "#{mr_group_label}"` in #{helper.html_link(feature_flag.path)}. #{SEE_DOC})
    end
  end
end

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%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).
  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

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?
    helper.labels_to_add << feature_flag.group
  else
    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!)
  end
end

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

def feature_flag_file_added?
  added_feature_flag_files.any?
end

def feature_flag_file_modified?
  modified_feature_flag_files.any?
end

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|
  check_feature_flag_yaml(feature_flag)
end

modified_feature_flag_files.each do |feature_flag|
  message_for_global_rollout(feature_flag)
end

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."
end

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