gitlab_quality-test_tooling 1.14.1 → 1.15.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: 9d4626e6b818482d139f6256f13044ae3434b93989c377526485aae69f32b9eb
4
- data.tar.gz: 148291a52850f6b6b5612dc0e1c46d2a6af0115d771c3ad3c9d1a0af7dbe2280
3
+ metadata.gz: 8364acd36abab9ce89c0846c346b893ca041a6a740ced7dc5c784da5990ea74c
4
+ data.tar.gz: 9468d8b559aeec587f9c3722e4f6e9d539d790828f9ecc7f815cc39ca22f2657
5
5
  SHA512:
6
- metadata.gz: a2fca44f7bf0ccda3cf905e561b8d52f7462df04c35f54a92d61fed7f4e6121e82bd2d3d60757f46b1c8d2cd30e788ac72aad4fd9d96e5607e50960437c7c58c
7
- data.tar.gz: 29a5e42c5c8f34b76e2aabb6280f0150a4aedf5d34a43bf44aef4be25aacb71d6a5f1bd9942f0593ec90626db3079cc2ad2fd4ee40ef084e9de9bd738cd427d4
6
+ metadata.gz: 4d287ca74d5fe7bc1bd9acd25541eb6f150f717f95f9e8c0bdf7a53ac139f3dab5186565ec74f2f7279e50dd47268d22121eb94ba2e3955cc5f6de33e7a952c0
7
+ data.tar.gz: e2954fea3d65bdce6e72f26a201965f45cc3aab583a34af9835f4d42f71540ad21582f4f8a96a12cd377a949644ab458ea213febfb2e6e90fbdc25c1867ddb72
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (1.14.1)
4
+ gitlab_quality-test_tooling (1.15.0)
5
5
  activesupport (>= 6.1, < 7.1)
6
6
  amatch (~> 0.4.1)
7
7
  gitlab (~> 4.19)
@@ -9,7 +9,7 @@ module GitlabQuality
9
9
  client.create_branch(project, branch_name, ref)
10
10
  end
11
11
 
12
- Runtime::Logger.debug("Created branch #{branch['name']} (#{branch['web_url']})")
12
+ Runtime::Logger.debug("Created branch #{branch['name']} (#{branch['web_url']})") if branch
13
13
  branch
14
14
  end
15
15
  end
@@ -5,11 +5,13 @@ module GitlabQuality
5
5
  module GitlabClient
6
6
  class CommitsClient < GitlabClient
7
7
  def create(branch_name, file_path, new_content, message)
8
- commit = client.create_commit(project, branch_name, message, [
9
- { action: :update, file_path: file_path, content: new_content }
10
- ])
8
+ commit = handle_gitlab_client_exceptions do
9
+ client.create_commit(project, branch_name, message, [
10
+ { action: :update, file_path: file_path, content: new_content }
11
+ ])
12
+ end
11
13
 
12
- Runtime::Logger.debug("Created commit #{commit['id']} (#{commit['web_url']}) on #{branch_name}")
14
+ Runtime::Logger.debug("Created commit #{commit['id']} (#{commit['web_url']}) on #{branch_name}") if commit
13
15
  commit
14
16
  end
15
17
  end
@@ -22,7 +22,7 @@ module GitlabQuality
22
22
  # If so, we want it to terminate at that point
23
23
  raise
24
24
  rescue SystemCallError, OpenSSL::SSL::SSLError, Net::OpenTimeout, Net::ReadTimeout,
25
- Gitlab::Error::InternalServerError, Gitlab::Error::Parsing => e
25
+ Gitlab::Error::InternalServerError, Gitlab::Error::BadRequest, Gitlab::Error::ResponseError, Gitlab::Error::Parsing => e
26
26
  @retry_backoff += RETRY_BACK_OFF_DELAY
27
27
 
28
28
  raise if @retry_backoff > RETRY_BACK_OFF_DELAY * MAX_RETRY_ATTEMPTS
@@ -5,10 +5,12 @@ module GitlabQuality
5
5
  module GitlabClient
6
6
  class MergeRequestsClient < GitlabClient
7
7
  def find_merge_request_changes(merge_request_iid:)
8
- client.merge_request_changes(project, merge_request_iid)
8
+ handle_gitlab_client_exceptions do
9
+ client.merge_request_changes(project, merge_request_iid)
10
+ end
9
11
  end
10
12
 
11
- def create_merge_request(title:, source_branch:, target_branch:, description:, labels:, assignee_id: nil)
13
+ def create_merge_request(title:, source_branch:, target_branch:, description:, labels:, assignee_id: nil, reviewer_ids: [])
12
14
  attrs = {
13
15
  source_branch: source_branch,
14
16
  target_branch: target_branch,
@@ -16,7 +18,8 @@ module GitlabQuality
16
18
  labels: labels,
17
19
  assignee_id: assignee_id,
18
20
  squash: true,
19
- remove_source_branch: true
21
+ remove_source_branch: true,
22
+ reviewer_ids: reviewer_ids
20
23
  }.compact
21
24
 
22
25
  merge_request = handle_gitlab_client_exceptions do
@@ -26,10 +26,11 @@ module GitlabQuality
26
26
  puts "The following note would have been updated id: #{id} with body: #{note} for mr_iid: #{merge_request_iid}"
27
27
  end
28
28
 
29
- def create_merge_request(title:, source_branch:, target_branch:, description:, labels:, assignee_id:)
29
+ def create_merge_request(title:, source_branch:, target_branch:, description:, labels:, assignee_id:, reviewer_ids:)
30
30
  puts "A merge request would be created with title: #{title} " \
31
31
  "source_branch: #{source_branch} target_branch: #{target_branch} " \
32
- "description: #{description} labels: #{labels}, assignee_id: #{assignee_id}"
32
+ "description: #{description} labels: #{labels}, assignee_id: #{assignee_id}" \
33
+ "reviewer_ids: #{reviewer_ids}"
33
34
  end
34
35
  end
35
36
  end
@@ -268,7 +268,7 @@ module GitlabQuality
268
268
  if stacktrace_match
269
269
  stacktrace_match[:stacktrace].gsub(/^\s*#.*$/, '').gsub(/^[[:space:]]+/, '').strip
270
270
  else
271
- puts " => [DEBUG] Stacktrace doesn't match the regex (#{regex}):\n----------------\n#{stacktrace}\n----------------\n"
271
+ puts " => [DEBUG] Stacktrace doesn't match the regex (#{regex})!"
272
272
  end
273
273
  end
274
274
 
@@ -33,6 +33,10 @@ module GitlabQuality
33
33
  env_var_value_if_defined('QA_LOG_LEVEL')&.upcase || 'INFO'
34
34
  end
35
35
 
36
+ def gitlab_bot_username
37
+ env_var_value_if_defined('GITLAB_BOT_USERNAME') || 'gitlab-bot'
38
+ end
39
+
36
40
  def log_path
37
41
  env_var_value_if_defined('QA_LOG_PATH') || host_artifacts_dir
38
42
  end
@@ -14,38 +14,39 @@ module GitlabQuality
14
14
  # @param [TestMetaUpdater] context instance of TestMetaUpdater
15
15
  def execute(spec, context) # rubocop:disable Metrics/AbcSize
16
16
  @context = context
17
-
17
+ @existing_mrs = nil
18
18
  @file_path = spec["file_path"]
19
19
  devops_stage = spec["stage"]
20
20
  product_group = spec["product_group"]
21
21
  @example_name = spec["name"]
22
22
  @mr_title = format("%{prefix} %{example_name}", prefix: '[PROMOTE TO BLOCKING]', example_name: example_name)
23
23
 
24
- return unless proceed_with_merge_request?
25
-
26
24
  @file_contents = context.get_file_contents(file_path)
27
25
 
28
- new_content, changed_line_no = add_blocking_metadata
26
+ new_content, @changed_line_no = add_blocking_metadata
29
27
 
30
- return if changed_line_no.negative?
28
+ return unless proceed_with_merge_request?
31
29
 
32
30
  branch = context.create_branch("blocking-promotion-#{SecureRandom.hex(4)}", example_name, context.ref)
33
31
 
34
32
  context.commit_changes(branch, <<~COMMIT_MESSAGE, file_path, new_content)
35
33
  Promote end-to-end test to blocking
36
34
 
37
- Promote to blocking: #{example_name}
35
+ #{"Promote to blocking: #{example_name}".truncate(72)}
38
36
  COMMIT_MESSAGE
39
37
 
40
- assignee_id, assignee_handle = context.fetch_dri_id(product_group, devops_stage)
38
+ reviewer_id, assignee_handle = context.fetch_dri_id(product_group, devops_stage)
39
+
40
+ gitlab_bot_user_id = context.user_id_for_username(Runtime::Env.gitlab_bot_username)
41
41
 
42
- merge_request = context.create_merge_request(mr_title, branch, assignee_id) do
42
+ merge_request = context.create_merge_request(mr_title, branch, gitlab_bot_user_id, [reviewer_id]) do
43
43
  <<~MARKDOWN
44
44
  ## What does this MR do?
45
45
 
46
46
  Promotes the test [`#{example_name}`](https://gitlab.com/#{context.project}/-/blob/#{context.ref}/#{file_path}#L#{changed_line_no + 1})
47
47
  to the blocking bucket
48
48
 
49
+ This test was identified in the reliable e2e test report: #{context.report_issue}
49
50
 
50
51
  /label ~"Quality" ~"QA" ~"type::maintenance"
51
52
  /label ~"devops::#{devops_stage}"
@@ -62,6 +63,11 @@ module GitlabQuality
62
63
  If you think this MR should not be merged, please close it and add a note of the reason to the blocking report: #{context.report_issue}
63
64
  MARKDOWN
64
65
 
66
+ if merge_request
67
+ context.add_processed_record({ file_path => changed_line_no })
68
+ Runtime::Logger.info(" Created MR for promotion to blocking: #{merge_request.web_url}")
69
+ end
70
+
65
71
  merge_request
66
72
  end
67
73
 
@@ -82,15 +88,20 @@ module GitlabQuality
82
88
 
83
89
  private
84
90
 
85
- attr_reader :context, :file_path, :file_contents, :example_name, :mr_title
91
+ attr_reader :context, :file_path, :file_contents, :example_name, :mr_title, :changed_line_no
86
92
 
87
93
  # Checks if there is already an MR open
88
94
  #
89
95
  # @return [Boolean]
90
- def proceed_with_merge_request?
91
- open_mrs = context.existing_merge_requests(title: mr_title)
92
- if open_mrs.any?
93
- puts " An open MR already exists for '#{example_name}': #{open_mrs.first['web_url']}. Will not proceed with creating MR."
96
+ def proceed_with_merge_request? # rubocop:disable Metrics/AbcSize
97
+ if changed_line_no.negative?
98
+ Runtime::Logger.info(" No lines were changed in #{file_path}. Will not proceed with creating MR.")
99
+ return false
100
+ elsif context.record_processed?(file_path, changed_line_no)
101
+ Runtime::Logger.info(" Record already processed for #{file_path}:#{changed_line_no}. Will not proceed with creating MR.")
102
+ return false
103
+ elsif existing_mrs&.any?
104
+ Runtime::Logger.info(" An open MR already exists for '#{example_name}': #{existing_mrs.first['web_url']}. Will not proceed with creating MR.")
94
105
  return false
95
106
  end
96
107
 
@@ -24,7 +24,7 @@ module GitlabQuality
24
24
  # @param [TestMetaUpdater] context instance of TestMetaUpdater
25
25
  def execute(spec, context) # rubocop:disable Metrics/AbcSize
26
26
  @context = context
27
-
27
+ @existing_mrs = nil
28
28
  @file_path = spec["file_path"]
29
29
  devops_stage = spec["stage"]
30
30
  @failure_issue_url = spec["failure_issue"]
@@ -33,21 +33,23 @@ module GitlabQuality
33
33
  @mr_title = format("%{prefix} %{example_name}", prefix: '[QUARANTINE]', example_name: example_name)
34
34
  @failure_issue = context.fetch_issue(iid: issue_id)
35
35
 
36
- return unless proceed_with_merge_request?
37
-
38
36
  @file_contents = context.get_file_contents(file_path)
39
37
 
40
- new_content, changed_line_no = add_quarantine_metadata
38
+ new_content, @changed_line_no = add_quarantine_metadata
39
+
40
+ return unless proceed_with_merge_request?
41
41
 
42
42
  branch = context.create_branch("#{issue_id}-quarantine-#{SecureRandom.hex(4)}", example_name, context.ref)
43
43
 
44
44
  context.commit_changes(branch, <<~COMMIT_MESSAGE, file_path, new_content)
45
45
  Quarantine end-to-end test
46
46
 
47
- Quarantine #{example_name}
47
+ #{"Quarantine #{example_name}".truncate(72)}
48
48
  COMMIT_MESSAGE
49
49
 
50
- context.create_merge_request(mr_title, branch) do
50
+ gitlab_bot_user_id = context.user_id_for_username(Runtime::Env.gitlab_bot_username)
51
+
52
+ merge_request = context.create_merge_request(mr_title, branch, gitlab_bot_user_id) do
51
53
  <<~MARKDOWN
52
54
  ## What does this MR do?
53
55
 
@@ -85,6 +87,13 @@ module GitlabQuality
85
87
  </div>
86
88
  MARKDOWN
87
89
  end
90
+
91
+ if merge_request
92
+ context.add_processed_record({ file_path => changed_line_no })
93
+ Runtime::Logger.info(" Created MR for quarantine: #{merge_request.web_url}")
94
+ end
95
+
96
+ merge_request
88
97
  end
89
98
 
90
99
  # Performs post processing. Takes a list of MRs and posts them in a note on report_issue and Slack
@@ -114,20 +123,21 @@ module GitlabQuality
114
123
 
115
124
  private
116
125
 
117
- attr_reader :context, :file_path, :file_contents, :failure_issue_url, :example_name, :issue_id, :mr_title, :failure_issue
126
+ attr_reader :context, :file_path, :file_contents, :failure_issue_url, :example_name,
127
+ :issue_id, :mr_title, :failure_issue, :changed_line_no
118
128
 
119
129
  # Checks if the failure issue is closed or if there is already an MR open
120
130
  #
121
131
  # @return [Boolean]
122
- def proceed_with_merge_request?
132
+ def proceed_with_merge_request? # rubocop:disable Metrics/AbcSize
123
133
  if context.issue_is_closed?(failure_issue)
124
- puts " Failure issue '#{failure_issue_url}' is closed. Will not proceed with creating MR."
134
+ Runtime::Logger.info(" Failure issue '#{failure_issue_url}' is closed. Will not proceed with creating MR.")
125
135
  return false
126
- end
127
-
128
- open_mrs = context.existing_merge_requests(title: mr_title)
129
- if open_mrs.any?
130
- puts " An open MR already exists for '#{example_name}': #{open_mrs.first['web_url']}. Will not proceed with creating MR."
136
+ elsif context.record_processed?(file_path, changed_line_no)
137
+ Runtime::Logger.info(" Record already processed for #{file_path}:#{changed_line_no}. Will not proceed with creating MR.")
138
+ return false
139
+ elsif existing_mrs&.any?
140
+ Runtime::Logger.info(" An open MR already exists for '#{example_name}': #{existing_mrs.first['web_url']}. Will not proceed with creating MR.")
131
141
  return false
132
142
  end
133
143
 
@@ -144,7 +154,7 @@ module GitlabQuality
144
154
  indentation = context.indentation(line)
145
155
 
146
156
  if line.include?(',') && line.split.last != 'do'
147
- line[line.index(',')] = format(QUARANTINE_METADATA.rstrip, issue_url: failure_issue_url, indentation: indentation, suffix: ',', quarantine_type: quarantine_type)
157
+ line[line.rindex(',')] = format(QUARANTINE_METADATA.rstrip, issue_url: failure_issue_url, indentation: indentation, suffix: ',', quarantine_type: quarantine_type)
148
158
  else
149
159
  line[line.rindex(' ')] = format(QUARANTINE_METADATA.rstrip, issue_url: failure_issue_url, indentation: indentation, suffix: ' ', quarantine_type: quarantine_type)
150
160
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/core_ext/string/filters'
4
+
3
5
  module GitlabQuality
4
6
  module TestTooling
5
7
  module TestMeta
@@ -15,6 +17,13 @@ module GitlabQuality
15
17
  end
16
18
 
17
19
  private_class_method :new
20
+
21
+ # Fetch existing MRs for given mr title
22
+ #
23
+ # @return [Array<Gitlab::ObjectifiedHash>]
24
+ def existing_mrs
25
+ @existing_mrs ||= context.existing_merge_requests(title: mr_title)
26
+ end
18
27
  end
19
28
  end
20
29
  end
@@ -8,7 +8,7 @@ module GitlabQuality
8
8
  class TestMetaUpdater
9
9
  include TestTooling::Concerns::FindSetDri
10
10
 
11
- attr_reader :project, :ref, :report_issue
11
+ attr_reader :project, :ref, :report_issue, :processed_records
12
12
 
13
13
  TEST_PLATFORM_MAINTAINERS_SLACK_CHANNEL_ID = 'C0437FV9KBN' # test-platform-maintainers
14
14
 
@@ -19,6 +19,7 @@ module GitlabQuality
19
19
  @ref = ref
20
20
  @dry_run = dry_run
21
21
  @processor = processor
22
+ @processed_records = {}
22
23
  end
23
24
 
24
25
  def invoke!
@@ -33,10 +34,20 @@ module GitlabQuality
33
34
  end
34
35
  end
35
36
 
37
+ # Add processed records
38
+ #
39
+ # @param [Hash<String,Integer>] record the processed record
40
+ # @option record [String] :file_path the path to the spec file
41
+ # @option spec [Intenger] :changed_line_no the line number change in file_path
42
+ # @return [Hash<String,Integer>] processed_records
43
+ def add_processed_record(record)
44
+ @processed_records.merge!(record)
45
+ end
46
+
36
47
  # Fetch contents of file from the repository
37
48
  #
38
- # [String] file_path path to the file
39
- # [String] contents of the file
49
+ # @param [String] file_path path to the file
50
+ # @return [String] contents of the file
40
51
  def get_file_contents(file_path)
41
52
  repository_files = GitlabClient::RepositoryFilesClient.new(token: token, project: project, file_path: file_path)
42
53
  repository_files.file_contents
@@ -110,8 +121,10 @@ module GitlabQuality
110
121
  # @param [String] example_name the example
111
122
  # @param [Gitlab::ObjectifiedHash] branch the branch
112
123
  # @param [Integer] assignee_id
124
+ # @param [Array<Integer>] reviewer_ids
125
+ # @param [String] labels comma seperated list of labels
113
126
  # @return [Gitlab::ObjectifiedHash] the created merge request
114
- def create_merge_request(title, branch, assignee_id = nil, labels = '')
127
+ def create_merge_request(title, branch, assignee_id = nil, reviewer_ids = [], labels = '')
115
128
  description = yield
116
129
 
117
130
  merge_request_client.create_merge_request(
@@ -120,7 +133,8 @@ module GitlabQuality
120
133
  target_branch: ref,
121
134
  description: description,
122
135
  labels: labels,
123
- assignee_id: assignee_id)
136
+ assignee_id: assignee_id,
137
+ reviewer_ids: reviewer_ids)
124
138
  end
125
139
 
126
140
  # Check if issue is closed
@@ -179,7 +193,15 @@ module GitlabQuality
179
193
  def fetch_dri_id(product_group, devops_stage)
180
194
  assignee_handle = ENV.fetch('QA_TEST_DRI_HANDLE', nil) || set_dri_via_group(product_group, devops_stage)
181
195
 
182
- [issue_client.find_user_id(username: assignee_handle), assignee_handle]
196
+ [user_id_for_username(assignee_handle), assignee_handle]
197
+ end
198
+
199
+ # Fetch id for the given GitLab username/handle
200
+ #
201
+ # @param [String] username
202
+ # @return [Integer]
203
+ def user_id_for_username(username)
204
+ issue_client.find_user_id(username: username)
183
205
  end
184
206
 
185
207
  # Post a message on Slack
@@ -221,6 +243,15 @@ module GitlabQuality
221
243
  merge_request_client.find(options: { search: title, in: 'title', state: 'opened' })
222
244
  end
223
245
 
246
+ # Checks if changes has already been made to given file and line number
247
+ #
248
+ # @param [String] file_path path to the file
249
+ # @param [Integer] changed_line_no updated line number
250
+ # @return [Boolean]
251
+ def record_processed?(file_path, changed_line_no)
252
+ processed_records[file_path] && processed_records[file_path] == changed_line_no
253
+ end
254
+
224
255
  private
225
256
 
226
257
  attr_reader :token, :specs_file, :dry_run, :processor
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "1.14.1"
5
+ VERSION = "1.15.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab_quality-test_tooling
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.1
4
+ version: 1.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab Quality
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-26 00:00:00.000000000 Z
11
+ date: 2024-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control