gitlab_quality-test_tooling 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 279a7eab459c664263a3506753c09d78111784af48af599cab26ed8928f54e2a
4
- data.tar.gz: '06388341bfbb2c868ae25569af2597666f64cdb7e980465078a78778081ca107'
3
+ metadata.gz: 8547ed9407707737f7d776f263543f3681e19706d7705591968f2e0ec348ed88
4
+ data.tar.gz: 84f1fb8007ce5c5dd96a1782cfa7b75207d456df2b9c163ddde5900f3efe6ad2
5
5
  SHA512:
6
- metadata.gz: cd37eca775b6899df0e476d11499ee491a8ea4278d88bf8f9584feb3cb8d1245da3319aa534ed4743c06ca1bd7da7a4eefcf619aa26688eb895bf3168d58eb9d
7
- data.tar.gz: 58f7c549202b39a20d6d5b5fc117e9017a044ee2e6bff63f07b82dda9650ed819f43407f20a5363d638b986fb8860d69c2452ea68bdf7fe5b7e33e70abb281b4
6
+ metadata.gz: 43e26da079892ae22a44025b4c96a076b65499e1ab1a5574da130132e9c70358ed12ae9ba123bb645b757b8e177bb59c11fd036f5e8d9d14e22620c5c0616958
7
+ data.tar.gz: f236ba27bc98161951cc4d98e4ff22321eeee476b6e305c0b67e2d58b09f6329a0361c9d834c20ff3efa86b41f5763733eb278c755fffa1e5fa49d25c556c1a9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (2.6.0)
4
+ gitlab_quality-test_tooling (2.8.0)
5
5
  activesupport (>= 7.0, < 7.2)
6
6
  amatch (~> 0.4.1)
7
7
  fog-google (~> 1.24, >= 1.24.1)
@@ -9,10 +9,11 @@ module GitlabQuality
9
9
  RETRY_BACK_OFF_DELAY = 60
10
10
  MAX_RETRY_ATTEMPTS = 3
11
11
 
12
- def initialize(token:, project:, **_kwargs)
12
+ def initialize(token:, project:, endpoint: nil, **_kwargs)
13
13
  @token = token
14
14
  @project = project
15
15
  @retry_backoff = 0
16
+ @endpoint = endpoint
16
17
  end
17
18
 
18
19
  def handle_gitlab_client_exceptions
@@ -76,11 +77,11 @@ module GitlabQuality
76
77
 
77
78
  private
78
79
 
79
- attr_reader :project, :token
80
+ attr_reader :project, :token, :endpoint
80
81
 
81
82
  def client
82
83
  @client ||= Gitlab.client(
83
- endpoint: Runtime::Env.gitlab_api_base,
84
+ endpoint: endpoint || Runtime::Env.gitlab_api_base,
84
85
  private_token: token
85
86
  )
86
87
  end
@@ -128,6 +128,12 @@ module GitlabQuality
128
128
  end
129
129
  end
130
130
 
131
+ def find_commit(project, sha)
132
+ handle_gitlab_client_exceptions do
133
+ client.commit(project, sha)
134
+ end
135
+ end
136
+
131
137
  def find_commit_parent(project, sha)
132
138
  handle_gitlab_client_exceptions do
133
139
  # In a merged results commit, the first parent is the one from
@@ -137,6 +143,24 @@ module GitlabQuality
137
143
  end
138
144
  end
139
145
 
146
+ def find_commit_diff(project, sha)
147
+ handle_gitlab_client_exceptions do
148
+ client.commit_diff(project, sha)
149
+ end
150
+ end
151
+
152
+ def find_deployments(project, environment:, status:, order_by: 'id', sort: 'desc')
153
+ handle_gitlab_client_exceptions do
154
+ client.deployments(
155
+ project,
156
+ environment: environment,
157
+ status: status,
158
+ order_by: order_by,
159
+ sort: sort
160
+ )
161
+ end
162
+ end
163
+
140
164
  private
141
165
 
142
166
  attr_reader :token, :project
@@ -5,20 +5,14 @@ module GitlabQuality
5
5
  module Report
6
6
  module Concerns
7
7
  module GroupAndCategoryLabels
8
- def labels_inference
9
- @labels_inference ||= GitlabQuality::TestTooling::LabelsInference.new
10
- end
11
-
12
- def new_issue_labels(test)
13
- debug_line = ' => [DEBUG] '
14
- debug_line += "product_group: #{test&.product_group}; " if test.respond_to?(:product_group)
15
- debug_line += "feature_category: #{test&.feature_category}" if test.respond_to?(:feature_category)
16
- puts debug_line
8
+ def group_and_category_labels_for_test(test)
9
+ labels_inference = GitlabQuality::TestTooling::LabelsInference.new
10
+ new_labels = Set.new
17
11
 
18
- new_labels = self.class::NEW_ISSUE_LABELS
19
12
  new_labels += labels_inference.infer_labels_from_product_group(test.product_group) if test.respond_to?(:product_group)
20
13
  new_labels += labels_inference.infer_labels_from_feature_category(test.feature_category) if test.respond_to?(:feature_category)
21
- up_to_date_labels(test: test, new_labels: new_labels)
14
+
15
+ new_labels
22
16
  end
23
17
  end
24
18
  end
@@ -15,6 +15,10 @@ module GitlabQuality
15
15
  "#{title[...MAX_TITLE_LENGTH - 3]}..."
16
16
  end
17
17
 
18
+ def label_names_to_label_quick_action(label_names)
19
+ %(/label #{label_names.map { |label| %(~"#{label}") }.join(' ')})
20
+ end
21
+
18
22
  def new_issue_title(test)
19
23
  "[Test] #{partial_file_path(test.file)} | #{search_safe(test.name)}".strip
20
24
  end
@@ -57,7 +57,7 @@ module GitlabQuality
57
57
  current_reports_note = find_failure_discussion_note(issue: issue, test: test, reports_discussion: reports_discussion)
58
58
 
59
59
  new_reports_list = new_reports_list(current_reports_note: current_reports_note, test: test)
60
- note_body = new_note_body(
60
+ note_body = append_quick_actions_to_note(
61
61
  new_reports_list: new_reports_list,
62
62
  related_issues: related_issues,
63
63
  options: {
@@ -105,6 +105,14 @@ module GitlabQuality
105
105
  IDENTITY_LABELS
106
106
  end
107
107
 
108
+ def new_issue_labels(test)
109
+ up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS + group_and_category_labels_for_test(test))
110
+ end
111
+
112
+ def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
113
+ (base_issue_labels + super).to_a
114
+ end
115
+
108
116
  def report_section_header
109
117
  REPORT_SECTION_HEADER
110
118
  end
@@ -139,10 +147,6 @@ module GitlabQuality
139
147
  quick_actions.join("\n")
140
148
  end
141
149
 
142
- def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
143
- (base_issue_labels + super).to_a
144
- end
145
-
146
150
  def find_failure_discussion_note(issue:, test:, reports_discussion:)
147
151
  return unless reports_discussion
148
152
 
@@ -44,6 +44,14 @@ module GitlabQuality
44
44
  IDENTITY_LABELS
45
45
  end
46
46
 
47
+ def new_issue_labels(test)
48
+ up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS)
49
+ end
50
+
51
+ def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
52
+ (base_issue_labels + super).to_a
53
+ end
54
+
47
55
  def report_section_header
48
56
  REPORT_SECTION_HEADER
49
57
  end
@@ -52,22 +60,22 @@ module GitlabQuality
52
60
  REPORTS_DOCUMENTATION
53
61
  end
54
62
 
55
- def health_problem_status_label_quick_action(reports_list, **)
63
+ def health_problem_status_label_quick_action(reports_list, options: {})
56
64
  case reports_list.reports_count
57
65
  when 399..Float::INFINITY
58
- '/label ~"flakiness::1"'
66
+ label_names = Set.new(['flakiness::1'])
67
+ label_names += group_and_category_labels_for_test(options[:test]) if options.key?(:test)
68
+ label_names_to_label_quick_action(label_names)
59
69
  when 37..398
60
- '/label ~"flakiness::2"'
70
+ label_names = Set.new(['flakiness::2'])
71
+ label_names += group_and_category_labels_for_test(options[:test]) if options.key?(:test)
72
+ label_names_to_label_quick_action(label_names)
61
73
  when 13..36
62
74
  '/label ~"flakiness::3"'
63
75
  else
64
76
  '/label ~"flakiness::4"'
65
77
  end
66
78
  end
67
-
68
- def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
69
- (base_issue_labels + super).to_a
70
- end
71
79
  end
72
80
  end
73
81
  end
@@ -45,6 +45,10 @@ module GitlabQuality
45
45
  []
46
46
  end
47
47
 
48
+ def new_issue_labels(_test)
49
+ []
50
+ end
51
+
48
52
  def search_labels
49
53
  BASE_SEARCH_LABELS
50
54
  end
@@ -57,10 +61,6 @@ module GitlabQuality
57
61
  ''
58
62
  end
59
63
 
60
- def health_problem_status_label_quick_action(*)
61
- ''
62
- end
63
-
64
64
  def item_extra_content(_test)
65
65
  found_label
66
66
  end
@@ -115,7 +115,13 @@ module GitlabQuality
115
115
  current_reports_note = existing_reports_note(issue_iid: issue.iid)
116
116
 
117
117
  new_reports_list = new_reports_list(current_reports_note: current_reports_note, test: test)
118
- note_body = new_note_body(new_reports_list: new_reports_list, related_issues: related_issues)
118
+ note_body = append_quick_actions_to_note(
119
+ new_reports_list: new_reports_list,
120
+ related_issues: related_issues,
121
+ options: {
122
+ test: test
123
+ }
124
+ )
119
125
 
120
126
  if current_reports_note
121
127
  gitlab.edit_issue_note(
@@ -138,7 +144,7 @@ module GitlabQuality
138
144
  )
139
145
  end
140
146
 
141
- def new_note_body(new_reports_list:, related_issues:, options: {})
147
+ def append_quick_actions_to_note(new_reports_list:, related_issues:, options: {})
142
148
  report = new_reports_list
143
149
 
144
150
  quick_actions = [
@@ -164,10 +170,15 @@ module GitlabQuality
164
170
  end
165
171
  end
166
172
 
173
+ # Defined in subclasses
174
+ def health_problem_status_label_quick_action(*)
175
+ ''
176
+ end
177
+
167
178
  def identity_labels_quick_action
168
179
  return if identity_labels.empty?
169
180
 
170
- %(/label #{identity_labels.map { |label| %(~"#{label}") }.join(' ')})
181
+ label_names_to_label_quick_action(identity_labels)
171
182
  end
172
183
 
173
184
  def relate_issues_quick_actions(issues)
@@ -39,6 +39,10 @@ module GitlabQuality
39
39
  search_and_create_issue
40
40
  end
41
41
 
42
+ def new_issue_labels(test)
43
+ up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS + group_and_category_labels_for_test(test))
44
+ end
45
+
42
46
  def search_and_create_issue
43
47
  filtered_report = KnapsackReports::SpecRunTimeReport.new(
44
48
  token: token,
@@ -33,6 +33,21 @@ module GitlabQuality
33
33
  'gitlab-org/customers-gitlab-com' => 'gitlab-org/customers-gitlab-com'
34
34
  }.freeze
35
35
 
36
+ # The project contains record of the deployments we use to determine the commit diff
37
+ OPS_RELEASES_METADATA_PROJECT = 'gitlab-org/release/metadata'
38
+
39
+ # Naming of the environments are different between `gitlab-org/release/metadata` and `gitlab-org/quality`
40
+ # This maps the gitlab-org/quality environment names to the equivalent in `gitlab-org/release/metadata`
41
+ ENVIRONMENT_MAPPING = {
42
+ 'production' => 'gprd',
43
+ 'canary' => 'gprd-cny',
44
+ 'staging' => 'gstg',
45
+ 'staging-canary' => 'gstg-cny',
46
+ 'staging-ref' => 'gstg-ref',
47
+ 'preprod' => 'pre',
48
+ 'release' => 'release'
49
+ }.freeze
50
+
36
51
  MultipleIssuesFound = Class.new(StandardError)
37
52
 
38
53
  def initialize(
@@ -54,7 +69,7 @@ module GitlabQuality
54
69
 
55
70
  private
56
71
 
57
- attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search, :metrics_files
72
+ attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search, :metrics_files, :ops_gitlab_client
58
73
 
59
74
  def run!
60
75
  puts "Reporting test failures in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
@@ -65,6 +80,14 @@ module GitlabQuality
65
80
  end
66
81
  end
67
82
 
83
+ def new_issue_labels(test)
84
+ up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS + group_and_category_labels_for_test(test))
85
+ end
86
+
87
+ def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
88
+ (Set.new(base_issue_labels) + (super << pipeline_name_label)).to_a
89
+ end
90
+
68
91
  def test_metric_collections
69
92
  @test_metric_collections ||= Dir.glob(metrics_files).map do |path|
70
93
  TestMetrics::JsonTestMetricCollection.new(path)
@@ -278,7 +301,7 @@ module GitlabQuality
278
301
 
279
302
  def new_issue_description(test)
280
303
  super + [
281
- "\n#{compare_against_previous_commit}",
304
+ "\n#{commit_diff_section}",
282
305
  "### Stack trace",
283
306
  "```\n#{test.full_stacktrace}\n```",
284
307
  screenshot_section(test),
@@ -287,8 +310,123 @@ module GitlabQuality
287
310
  ].compact.join("\n\n")
288
311
  end
289
312
 
290
- def compare_against_previous_commit
291
- pipeline_sha = gitlab.find_pipeline(project, Runtime::Env.ci_pipeline_id.to_i).sha
313
+ def commit_diff_section
314
+ "### Commit diff\n#{generate_diff_link}"
315
+ end
316
+
317
+ def generate_diff_link
318
+ initialize_gitlab_ops_client
319
+
320
+ if Runtime::Env.ci_pipeline_url.include?('ops.gitlab.net')
321
+ pipeline = ops_gitlab_client.find_pipeline(project, Runtime::Env.ci_pipeline_id.to_i)
322
+ generate_ops_gitlab_diff(pipeline)
323
+ else
324
+ pipeline = gitlab.find_pipeline(project, Runtime::Env.ci_pipeline_id.to_i)
325
+ generate_gitlab_diff(pipeline)
326
+ end
327
+ end
328
+
329
+ def generate_ops_gitlab_diff(pipeline)
330
+ deployment_info = fetch_deployment_info(pipeline)
331
+
332
+ return deployment_info if deployment_info.is_a?(String)
333
+
334
+ source_gitlab_ee_sha = fetch_deployment_gitlab_ee_sha(ops_gitlab_client, deployment_info[:source].sha)
335
+ target_gitlab_ee_sha = fetch_deployment_gitlab_ee_sha(ops_gitlab_client, deployment_info[:target].sha)
336
+
337
+ if source_gitlab_ee_sha == target_gitlab_ee_sha
338
+ "No diff"
339
+ else
340
+ "https://gitlab.com/gitlab-org/security/gitlab/-/compare/#{target_gitlab_ee_sha}...#{source_gitlab_ee_sha}"
341
+ end
342
+ end
343
+
344
+ def fetch_deployment_info(pipeline)
345
+ pipeline_deploy_version = Runtime::Env.ci_pipeline_name.match(/(\d+\.\d+\.\d+)(?:-|$)/)&.captures&.first
346
+ deployments = fetch_deployments(ops_gitlab_client, pipeline)
347
+ found_deployment = find_matching_deployment(pipeline_deploy_version, deployments)
348
+
349
+ return 'No matching deployment found to generate a diff link.' unless found_deployment
350
+
351
+ {
352
+ source: found_deployment[:deployment],
353
+ target: deployments[found_deployment[:index] + 1]
354
+ }
355
+ end
356
+
357
+ def fetch_deployments(client, pipeline)
358
+ ops_environment = pipeline.web_url.match(%r{gitlab-org/quality/([^/-]+(?:-[^/-]+)*?)(?:/-)?/pipelines})[1]
359
+
360
+ raise "Environment '#{ops_environment}' is not supported" unless ENVIRONMENT_MAPPING.key?(ops_environment)
361
+
362
+ environment = ENVIRONMENT_MAPPING[ops_environment]
363
+
364
+ client.find_deployments(
365
+ OPS_RELEASES_METADATA_PROJECT,
366
+ environment: environment,
367
+ status: 'success'
368
+ )
369
+ end
370
+
371
+ def initialize_gitlab_ops_client
372
+ @ops_gitlab_client = GitlabClient::IssuesClient.new(
373
+ endpoint: Runtime::Env.ci_api_v4_url,
374
+ token: Runtime::Env.gitlab_ci_token,
375
+ project: OPS_RELEASES_METADATA_PROJECT
376
+ )
377
+ end
378
+
379
+ def find_matching_deployment(pipeline_deploy_version, deployments)
380
+ return nil unless pipeline_deploy_version
381
+ return nil unless deployments
382
+
383
+ target_timestamp = extract_timestamp(pipeline_deploy_version)
384
+ return nil unless target_timestamp
385
+
386
+ matching_deployment = nil
387
+
388
+ deployments.each_with_index do |deployment, index|
389
+ deployment_version = extract_deployment_version(ops_gitlab_client, deployment)
390
+ next unless deployment_version
391
+
392
+ deployment_timestamp = extract_timestamp(deployment_version)
393
+ next unless deployment_timestamp
394
+
395
+ # Stop searching if the deployment timestamp is older than the target timestamp
396
+ break if deployment_timestamp && deployment_timestamp < target_timestamp
397
+
398
+ if deployment_version == pipeline_deploy_version
399
+ matching_deployment = { deployment: deployment, index: index }
400
+ break
401
+ end
402
+ end
403
+
404
+ matching_deployment
405
+ end
406
+
407
+ def extract_timestamp(version)
408
+ version.match(/\d{12}$/)&.to_s
409
+ end
410
+
411
+ def extract_deployment_version(client, deployment)
412
+ commit = client.find_commit(OPS_RELEASES_METADATA_PROJECT, deployment.sha)
413
+ version_match = commit.message&.match(/Product-Version: ([\d.]+)/)
414
+ version_match&.[](1)
415
+ end
416
+
417
+ def fetch_deployment_gitlab_ee_sha(client, deployment_sha)
418
+ commit_diff = client.find_commit_diff(OPS_RELEASES_METADATA_PROJECT, deployment_sha).first
419
+ diffs_content = commit_diff.diff.lines.select { |line| line.start_with?('+') }.map { |line| line[1..] }.join
420
+
421
+ begin
422
+ JSON.parse(diffs_content).dig('releases', 'gitlab-ee', 'sha')
423
+ rescue JSON::ParserError
424
+ raise "Failed to parse the diffs content"
425
+ end
426
+ end
427
+
428
+ def generate_gitlab_diff(pipeline)
429
+ pipeline_sha = pipeline.sha
292
430
  parent_sha = gitlab.find_commit_parent(project, pipeline_sha)
293
431
  diff_project = if DIFF_PROJECT_MAPPINGS.key?(project)
294
432
  DIFF_PROJECT_MAPPINGS[project]
@@ -296,7 +434,7 @@ module GitlabQuality
296
434
  raise "Project #{project} is not supported for commit diff links"
297
435
  end
298
436
 
299
- "### Commit diff\nhttps://gitlab.com/#{diff_project}/-/compare/#{parent_sha}...#{pipeline_sha}"
437
+ "https://gitlab.com/#{diff_project}/-/compare/#{parent_sha}...#{pipeline_sha}"
300
438
  end
301
439
 
302
440
  def system_log_errors_section(test)
@@ -318,10 +456,6 @@ module GitlabQuality
318
456
  section
319
457
  end
320
458
 
321
- def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
322
- (Set.new(base_issue_labels) + (super << pipeline_name_label)).to_a
323
- end
324
-
325
459
  def new_issue_assignee_id(test)
326
460
  return unless test.product_group?
327
461
 
@@ -144,6 +144,9 @@ module GitlabQuality
144
144
  gitlab.edit_issue(iid: issue.iid, options: { labels: labels.to_a })
145
145
  end
146
146
 
147
+ # Infer labels from the test, and optionally from the issue and new_labels in arguments
148
+ #
149
+ # Called when we're updating a test health issue with a new test report.
147
150
  def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
148
151
  labels = issue_labels(issue)
149
152
  labels |= new_labels.to_set
@@ -34,6 +34,10 @@ module GitlabQuality
34
34
  IDENTITY_LABELS
35
35
  end
36
36
 
37
+ def new_issue_labels(test)
38
+ up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS)
39
+ end
40
+
37
41
  def report_section_header
38
42
  REPORT_SECTION_HEADER
39
43
  end
@@ -42,12 +46,16 @@ module GitlabQuality
42
46
  REPORTS_DOCUMENTATION
43
47
  end
44
48
 
45
- def health_problem_status_label_quick_action(reports_list, **)
49
+ def health_problem_status_label_quick_action(reports_list, options: {})
46
50
  case reports_list.reports_count
47
51
  when 6099..Float::INFINITY
48
- '/label ~"slowness::1"'
52
+ label_names = Set.new(['slowness::1'])
53
+ label_names += group_and_category_labels_for_test(options[:test]) if options.key?(:test)
54
+ label_names_to_label_quick_action(label_names)
49
55
  when 2177..6098
50
- '/label ~"slowness::2"'
56
+ label_names = Set.new(['slowness::2'])
57
+ label_names += group_and_category_labels_for_test(options[:test]) if options.key?(:test)
58
+ label_names_to_label_quick_action(label_names)
51
59
  when 521..2176
52
60
  '/label ~"slowness::3"'
53
61
  else
@@ -19,9 +19,11 @@ module GitlabQuality
19
19
  'CI_PROJECT_NAME' => :ci_project_name,
20
20
  'CI_PROJECT_PATH' => :ci_project_path,
21
21
  'CI_PIPELINE_ID' => :ci_pipeline_id,
22
+ 'CI_PIPELINE_NAME' => :ci_pipeline_name,
22
23
  'CI_PIPELINE_URL' => :ci_pipeline_url,
23
24
  'SLACK_QA_CHANNEL' => :slack_qa_channel,
24
- 'DEPLOY_VERSION' => :deploy_version
25
+ 'DEPLOY_VERSION' => :deploy_version,
26
+ 'QA_GITLAB_CI_TOKEN' => :gitlab_ci_token
25
27
  }.freeze
26
28
 
27
29
  ENV_VARIABLES.each do |env_name, method_name|
@@ -11,7 +11,9 @@ module GitlabQuality
11
11
  "unexpected token at 'GitLab is not responding'",
12
12
  "GitLab: Internal API error (502).",
13
13
  "could not be found (502)",
14
- "Error reference number: 502"
14
+ "Error reference number: 502",
15
+ "(502): `GitLab is not responding`",
16
+ "<head><title>502 Bad Gateway</title></head>"
15
17
  ].freeze
16
18
 
17
19
  SHARED_EXAMPLES_CALLERS = %w[include_examples it_behaves_like].freeze
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "2.6.0"
5
+ VERSION = "2.8.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: 2.6.0
4
+ version: 2.8.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: 2025-01-24 00:00:00.000000000 Z
11
+ date: 2025-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control