gitlab-dangerfiles 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6298bb4b8fed9c66cd1bc9b811e9ddb93d6e8474dd8797da837780ec5bcbe1a8
4
- data.tar.gz: 2be36370906090104ebba958d4910d5f105cf3b8d0619849c78dbb5b625dcd9a
3
+ metadata.gz: 679d12adff8fd532552d644bba3f1ae62395077310ffcc7aa62181b477f5453d
4
+ data.tar.gz: f6460b3c349cf27d1a65246f41744cae15c95c0c949811aa1b972abe654b3e90
5
5
  SHA512:
6
- metadata.gz: 9c09bdec93ab9d0b1a73565e62a46e400204907f758cb924c0d27d27eda7aae0871e45a02d7ac1f6846d2aa0f6a8c41d341f57147d5e04d94ac4351a2b6b64d1
7
- data.tar.gz: 67710acb881d9f5229944ccb3dc40bb7d9c4ae0d66743190cfb3fac7e560f22f3ca8a7ca7b7b60119e6f595b4a4e00d3235df0728a79370d60723985cb4d0b93
6
+ metadata.gz: 8ebcb0cd08d49021346a0b74adb50b5ff10a8fe64227e86f960a72e6cc88260f0249927088bae3e949ddbf9a295c65d2d4c005d8d4b0ee157a907f700b72ce46
7
+ data.tar.gz: e747d6b68ca54ee597e008332a5bfc7d4fa01a437e44af42fc68d5ab28aaf674b2e76995ab792559016fa381c0cd1e08b58071bb5c3d4b66f37e8c7891bbaa77
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "net/http"
4
4
  require "json"
5
+ require "danger"
5
6
  require_relative "../gitlab/dangerfiles/teammate"
6
7
 
7
8
  module Danger
@@ -15,77 +16,6 @@ module Danger
15
16
  test: "~test ~Quality for `spec/features/*`",
16
17
  engineering_productivity: '~"Engineering Productivity" for CI, Danger',
17
18
  }.freeze
18
- # First-match win, so be sure to put more specific regex at the top...
19
- CATEGORIES = {
20
- %r{\Adoc/} => :docs,
21
- %r{\A(CONTRIBUTING|LICENSE|MAINTENANCE|PHILOSOPHY|PROCESS|README)(\.md)?\z} => :docs,
22
-
23
- %r{\A(ee/)?app/(assets|views)/} => :frontend,
24
- %r{\A(ee/)?public/} => :frontend,
25
- %r{\A(ee/)?spec/(javascripts|frontend)/} => :frontend,
26
- %r{\A(ee/)?vendor/assets/} => :frontend,
27
- %r{\A(ee/)?scripts/frontend/} => :frontend,
28
- %r{(\A|/)(
29
- \.babelrc |
30
- \.eslintignore |
31
- \.eslintrc(\.yml)? |
32
- \.nvmrc |
33
- \.prettierignore |
34
- \.prettierrc |
35
- \.scss-lint.yml |
36
- \.stylelintrc |
37
- \.haml-lint.yml |
38
- \.haml-lint_todo.yml |
39
- babel\.config\.js |
40
- jest\.config\.js |
41
- package\.json |
42
- yarn\.lock |
43
- config/.+\.js
44
- )\z}x => :frontend,
45
-
46
- %r{(\A|/)(
47
- \.gitlab/ci/frontend\.gitlab-ci\.yml
48
- )\z}x => %i[frontend engineering_productivity],
49
-
50
- %r{\A(ee/)?db/(?!fixtures)[^/]+} => :database,
51
- %r{\A(ee/)?lib/gitlab/(database|background_migration|sql|github_import)(/|\.rb)} => :database,
52
- %r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => :database,
53
- %r{\A(ee/)?app/finders/} => :database,
54
- %r{\Arubocop/cop/migration(/|\.rb)} => :database,
55
-
56
- %r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :engineering_productivity,
57
- %r{\A\.codeclimate\.yml\z} => :engineering_productivity,
58
- %r{\A\.overcommit\.yml\.example\z} => :engineering_productivity,
59
- %r{\A\.editorconfig\z} => :engineering_productivity,
60
- %r{Dangerfile\z} => :engineering_productivity,
61
- %r{\A(ee/)?(danger/|lib/gitlab/danger/)} => :engineering_productivity,
62
- %r{\A(ee/)?scripts/} => :engineering_productivity,
63
- %r{\Atooling/} => :engineering_productivity,
64
-
65
- %r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend,
66
- %r{\A(ee/)?(bin|config|generator_templates|lib|rubocop)/} => :backend,
67
- %r{\A(ee/)?spec/features/} => :test,
68
- %r{\A(ee/)?spec/} => :backend,
69
- %r{\A(ee/)?vendor/} => :backend,
70
- %r{\A(Gemfile|Gemfile.lock|Rakefile)\z} => :backend,
71
- %r{\A[A-Z_]+_VERSION\z} => :backend,
72
- %r{\A\.rubocop(_todo)?\.yml\z} => :backend,
73
- %r{\Afile_hooks/} => :backend,
74
-
75
- %r{\A(ee/)?qa/} => :qa,
76
-
77
- # Files that don't fit into any category are marked with :none
78
- %r{\A(ee/)?changelogs/} => :none,
79
- %r{\Alocale/gitlab\.pot\z} => :none,
80
-
81
- # Fallbacks in case the above patterns miss anything
82
- %r{\.rb\z} => :backend,
83
- %r{(
84
- \.(md|txt)\z |
85
- \.markdownlint\.json
86
- )}x => :none, # To reinstate roulette for documentation, set to `:docs`.
87
- %r{\.js\z} => :frontend,
88
- }.freeze
89
19
 
90
20
  HTTPError = Class.new(StandardError)
91
21
 
@@ -98,10 +28,6 @@ module Danger
98
28
  nil
99
29
  end
100
30
 
101
- def rule_names
102
- ci? ? Gitlab::Dangerfiles::LOCAL_RULES | Gitlab::Dangerfiles::CI_ONLY_RULES : Gitlab::Dangerfiles::LOCAL_RULES
103
- end
104
-
105
31
  def html_link(str)
106
32
  ci? ? gitlab_helper.html_link(str) : str
107
33
  end
@@ -148,23 +74,25 @@ module Danger
148
74
  .sort
149
75
  end
150
76
 
151
- def all_ee_changes
152
- all_changed_files.grep(%r{\Aee/})
153
- end
77
+ # Returns a string containing changed lines as git diff
78
+ #
79
+ # Considering changing a line in lib/gitlab/usage_data.rb it will return:
80
+ #
81
+ # [ "--- a/lib/gitlab/usage_data.rb",
82
+ # "+++ b/lib/gitlab/usage_data.rb",
83
+ # "+ # Test change",
84
+ # "- # Old change" ]
85
+ def changed_lines(changed_file)
86
+ diff = git.diff_for_file(changed_file)
87
+ return [] unless diff
154
88
 
155
- def ee?
156
- # Support former project name for `dev` and support local Danger run
157
- %w[gitlab gitlab-ee].include?(ENV["CI_PROJECT_NAME"]) || Dir.exist?("../../ee")
89
+ diff.patch.split("\n").select { |line| %r{^[+-]}.match?(line) }
158
90
  end
159
91
 
160
92
  def release_automation?
161
93
  gitlab_helper&.mr_author == RELEASE_TOOLS_BOT
162
94
  end
163
95
 
164
- def project_name
165
- ee? ? "gitlab" : "gitlab-foss"
166
- end
167
-
168
96
  def markdown_list(items)
169
97
  list = items.map { |item| "* `#{item}`" }.join("\n")
170
98
 
@@ -176,16 +104,23 @@ module Danger
176
104
  end
177
105
 
178
106
  # @return [Hash<String,Array<String>>]
179
- def changes_by_category
107
+ def changes_by_category(categories)
180
108
  all_changed_files.each_with_object(Hash.new { |h, k| h[k] = [] }) do |file, hash|
181
- categories_for_file(file).each { |category| hash[category] << file }
109
+ categories_for_file(file, categories).each { |category| hash[category] << file }
182
110
  end
183
111
  end
184
112
 
185
113
  # Determines the categories a file is in, e.g., `[:frontend]`, `[:backend]`, or `%i[frontend engineering_productivity]`.
186
114
  # @return Array<Symbol>
187
- def categories_for_file(file)
188
- _, categories = CATEGORIES.find { |regexp, _| regexp.match?(file) }
115
+ def categories_for_file(file, categories)
116
+ _, categories = categories.find do |key, _|
117
+ filename_regex, changes_regex = Array(key)
118
+
119
+ found = filename_regex.match?(file)
120
+ found &&= changed_lines(file).any? { |changed_line| changes_regex.match?(changed_line) } if changes_regex
121
+
122
+ found
123
+ end
189
124
 
190
125
  Array(categories || :unknown)
191
126
  end
@@ -251,6 +186,10 @@ module Danger
251
186
  "/label #{labels_list(labels, sep: " ")}"
252
187
  end
253
188
 
189
+ def changed_files(regex)
190
+ all_changed_files.grep(regex)
191
+ end
192
+
254
193
  private
255
194
 
256
195
  def has_database_scoped_labels?(current_mr_labels)
@@ -9,42 +9,53 @@ module Danger
9
9
  ROULETTE_DATA_URL = "https://gitlab-org.gitlab.io/gitlab-roulette/roulette.json"
10
10
  HOURS_WHEN_PERSON_CAN_BE_PICKED = (6..14).freeze
11
11
 
12
- Spin = Struct.new(:category, :reviewer, :maintainer, :optional_role)
12
+ INCLUDE_TIMEZONE_FOR_CATEGORY = {
13
+ database: false,
14
+ }.freeze
15
+
16
+ Spin = Struct.new(:category, :reviewer, :maintainer, :optional_role, :timezone_experiment)
17
+
18
+ def team_mr_author
19
+ team.find { |person| person.username == mr_author_username }
20
+ end
13
21
 
14
22
  # Assigns GitLab team members to be reviewer and maintainer
15
23
  # for each change category that a Merge Request contains.
16
24
  #
17
25
  # @return [Array<Spin>]
18
- def spin(project, categories, branch_name, timezone_experiment: false)
19
- team = begin
20
- project_team(project)
21
- rescue => err
22
- warn("Reviewer roulette failed to load team data: #{err.message}")
23
- []
24
- end
26
+ def spin(project, categories, timezone_experiment: false)
27
+ spins = categories.map do |category|
28
+ including_timezone = INCLUDE_TIMEZONE_FOR_CATEGORY.fetch(category, timezone_experiment)
25
29
 
26
- canonical_branch_name = canonical_branch_name(branch_name)
27
-
28
- spin_per_category = categories.each_with_object({}) do |category, memo|
29
- memo[category] = spin_for_category(team, project, category, canonical_branch_name, timezone_experiment: timezone_experiment)
30
+ spin_for_category(project, category, timezone_experiment: including_timezone)
30
31
  end
31
32
 
32
- spin_per_category.map do |category, spin|
33
- case category
33
+ backend_spin = spins.find { |spin| spin.category == :backend }
34
+
35
+ spins.each do |spin|
36
+ including_timezone = INCLUDE_TIMEZONE_FOR_CATEGORY.fetch(spin.category, timezone_experiment)
37
+ case spin.category
38
+ when :qa
39
+ # MR includes QA changes, but also other changes, and author isn't an SET
40
+ if categories.size > 1 && !team_mr_author&.reviewer?(project, spin.category, [])
41
+ spin.optional_role = :maintainer
42
+ end
34
43
  when :test
44
+ spin.optional_role = :maintainer
45
+
35
46
  if spin.reviewer.nil?
36
47
  # Fetch an already picked backend reviewer, or pick one otherwise
37
- spin.reviewer = spin_per_category[:backend]&.reviewer || spin_for_category(team, project, :backend, canonical_branch_name).reviewer
48
+ spin.reviewer = backend_spin&.reviewer || spin_for_category(project, :backend, timezone_experiment: including_timezone).reviewer
38
49
  end
39
50
  when :engineering_productivity
40
51
  if spin.maintainer.nil?
41
52
  # Fetch an already picked backend maintainer, or pick one otherwise
42
- spin.maintainer = spin_per_category[:backend]&.maintainer || spin_for_category(team, project, :backend, canonical_branch_name).maintainer
53
+ spin.maintainer = backend_spin&.maintainer || spin_for_category(project, :backend, timezone_experiment: including_timezone).maintainer
43
54
  end
44
55
  end
45
-
46
- spin
47
56
  end
57
+
58
+ spins
48
59
  end
49
60
 
50
61
  # Looks up the current list of GitLab team members and parses it into a
@@ -66,14 +77,9 @@ module Danger
66
77
  # @return [Array<Teammate>]
67
78
  def project_team(project_name)
68
79
  team.select { |member| member.in_project?(project_name) }
69
- end
70
-
71
- def canonical_branch_name(branch_name)
72
- branch_name.gsub(/^[ce]e-|-[ce]e$/, "")
73
- end
74
-
75
- def new_random(seed)
76
- Random.new(Digest::MD5.hexdigest(seed).to_i(16))
80
+ rescue => err
81
+ warn("Reviewer roulette failed to load team data: #{err.message}")
82
+ []
77
83
  end
78
84
 
79
85
  # Known issue: If someone is rejected due to OOO, and then becomes not OOO, the
@@ -106,16 +112,35 @@ module Danger
106
112
  # @param [Teammate] person
107
113
  # @return [Boolean]
108
114
  def mr_author?(person)
109
- person.username == gitlab.mr_author
115
+ person.username == mr_author_username
116
+ end
117
+
118
+ def mr_author_username
119
+ helper.gitlab_helper&.mr_author || `whoami`
120
+ end
121
+
122
+ def mr_source_branch
123
+ return `git rev-parse --abbrev-ref HEAD` unless helper.gitlab_helper&.mr_json
124
+
125
+ helper.gitlab_helper.mr_json["source_branch"]
126
+ end
127
+
128
+ def mr_labels
129
+ helper.gitlab_helper&.mr_labels || []
130
+ end
131
+
132
+ def new_random(seed)
133
+ Random.new(Digest::MD5.hexdigest(seed).to_i(16))
110
134
  end
111
135
 
112
136
  def spin_role_for_category(team, role, project, category)
113
137
  team.select do |member|
114
- member.public_send("#{role}?", project, category, gitlab.mr_labels) # rubocop:disable GitlabSecurity/PublicSend
138
+ member.public_send("#{role}?", project, category, mr_labels) # rubocop:disable GitlabSecurity/PublicSend
115
139
  end
116
140
  end
117
141
 
118
- def spin_for_category(team, project, category, branch_name, timezone_experiment: false)
142
+ def spin_for_category(project, category, timezone_experiment: false)
143
+ team = project_team(project)
119
144
  reviewers, traintainers, maintainers =
120
145
  %i[reviewer traintainer maintainer].map do |role|
121
146
  spin_role_for_category(team, role, project, category)
@@ -125,11 +150,11 @@ module Danger
125
150
  # https://gitlab.com/gitlab-org/gitlab/issues/26723
126
151
 
127
152
  # Make traintainers have triple the chance to be picked as a reviewer
128
- random = new_random(branch_name)
153
+ random = new_random(mr_source_branch)
129
154
  reviewer = spin_for_person(reviewers + traintainers + traintainers, random: random, timezone_experiment: timezone_experiment)
130
155
  maintainer = spin_for_person(maintainers, random: random, timezone_experiment: timezone_experiment)
131
156
 
132
- Spin.new(category, reviewer, maintainer)
157
+ Spin.new(category, reviewer, maintainer, false, timezone_experiment)
133
158
  end
134
159
  end
135
160
  end
@@ -2,39 +2,5 @@ require "gitlab/dangerfiles/version"
2
2
 
3
3
  module Gitlab
4
4
  module Dangerfiles
5
- LOCAL_RULES ||= %w[
6
- changes_size
7
- commit_messages
8
- database
9
- documentation
10
- duplicate_yarn_dependencies
11
- eslint
12
- frozen_string
13
- karma
14
- prettier
15
- telemetry
16
- utility_css
17
- ].freeze
18
- CI_ONLY_RULES ||= %w[
19
- ce_ee_vue_templates
20
- changelog
21
- metadata
22
- roulette
23
- sidekiq_queues
24
- specs
25
- ].freeze
26
- MESSAGE_PREFIX = "==>".freeze
27
-
28
- def self.load_tasks
29
- require "gitlab/dangerfiles/tasks"
30
- end
31
-
32
- def self.local_warning_message
33
- "#{MESSAGE_PREFIX} Only the following Danger rules can be run locally: #{LOCAL_RULES.join(", ")}"
34
- end
35
-
36
- def self.success_message
37
- "#{MESSAGE_PREFIX} No Danger rule violations!"
38
- end
39
5
  end
40
6
  end
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  module Dangerfiles
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-dangerfiles
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rémy Coutable
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-27 00:00:00.000000000 Z
11
+ date: 2020-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: danger
@@ -130,36 +130,14 @@ files:
130
130
  - fixtures/emojis/aliases.json
131
131
  - fixtures/emojis/digests.json
132
132
  - gitlab-dangerfiles.gemspec
133
- - lib/danger/changelog.rb
134
133
  - lib/danger/helper.rb
135
134
  - lib/danger/roulette.rb
136
- - lib/danger/sidekiq_queues.rb
137
135
  - lib/gitlab-dangerfiles.rb
138
136
  - lib/gitlab/Dangerfile
139
137
  - lib/gitlab/dangerfiles.rb
140
- - lib/gitlab/dangerfiles/bundle_size/Dangerfile
141
- - lib/gitlab/dangerfiles/ce_ee_vue_templates/Dangerfile
142
- - lib/gitlab/dangerfiles/changelog/Dangerfile
143
- - lib/gitlab/dangerfiles/changes_size/Dangerfile
144
138
  - lib/gitlab/dangerfiles/commit_linter.rb
145
- - lib/gitlab/dangerfiles/commit_messages/Dangerfile
146
- - lib/gitlab/dangerfiles/database/Dangerfile
147
- - lib/gitlab/dangerfiles/documentation/Dangerfile
148
- - lib/gitlab/dangerfiles/duplicate_yarn_dependencies/Dangerfile
149
139
  - lib/gitlab/dangerfiles/emoji_checker.rb
150
- - lib/gitlab/dangerfiles/eslint/Dangerfile
151
- - lib/gitlab/dangerfiles/frozen_string/Dangerfile
152
- - lib/gitlab/dangerfiles/karma/Dangerfile
153
- - lib/gitlab/dangerfiles/metadata/Dangerfile
154
- - lib/gitlab/dangerfiles/popen.rb
155
- - lib/gitlab/dangerfiles/prettier/Dangerfile
156
- - lib/gitlab/dangerfiles/roulette/Dangerfile
157
- - lib/gitlab/dangerfiles/sidekiq_queues/Dangerfile
158
- - lib/gitlab/dangerfiles/specs/Dangerfile
159
- - lib/gitlab/dangerfiles/tasks.rb
160
140
  - lib/gitlab/dangerfiles/teammate.rb
161
- - lib/gitlab/dangerfiles/telemetry/Dangerfile
162
- - lib/gitlab/dangerfiles/utility_css/Dangerfile
163
141
  - lib/gitlab/dangerfiles/version.rb
164
142
  homepage: https://gitlab.com/gitlab-org/gitlab-dangerfiles
165
143
  licenses:
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Danger
4
- # Common helper functions for our danger scripts. See Danger::Helper
5
- # for more details
6
- class Changelog < Danger::Plugin
7
- NO_CHANGELOG_LABELS = [
8
- "backstage", # To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/222360.
9
- "tooling",
10
- "tooling::pipelines",
11
- "tooling::workflow",
12
- "ci-build",
13
- "meta",
14
- ].freeze
15
- NO_CHANGELOG_CATEGORIES = %i[docs none].freeze
16
-
17
- def needed?
18
- categories_need_changelog? && (gitlab.mr_labels & NO_CHANGELOG_LABELS).empty?
19
- end
20
-
21
- def found
22
- @found ||= git.added_files.find { |path| path =~ %r{\A(ee/)?(changelogs/unreleased)(-ee)?/} }
23
- end
24
-
25
- def sanitized_mr_title
26
- gitlab.mr_json["title"].gsub(/^WIP: */, "").gsub(/`/, '\\\`')
27
- end
28
-
29
- def ee_changelog?
30
- found.start_with?("ee/")
31
- end
32
-
33
- private
34
-
35
- def categories_need_changelog?
36
- (helper.changes_by_category.keys - NO_CHANGELOG_CATEGORIES).any?
37
- end
38
- end
39
- end