gitlab_quality-test_tooling 3.0.0 → 3.7.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -4
  3. data/README.md +47 -14
  4. data/exe/sync-category-owners +95 -0
  5. data/exe/test-coverage +59 -15
  6. data/lib/gitlab_quality/test_tooling/code_coverage/README.md +162 -0
  7. data/lib/gitlab_quality/test_tooling/code_coverage/artifacts.rb +5 -2
  8. data/lib/gitlab_quality/test_tooling/code_coverage/category_owners.rb +32 -28
  9. data/lib/gitlab_quality/test_tooling/code_coverage/click_house/category_owners_table.rb +102 -35
  10. data/lib/gitlab_quality/test_tooling/code_coverage/click_house/coverage_metrics_table.rb +44 -37
  11. data/lib/gitlab_quality/test_tooling/code_coverage/click_house/table.rb +17 -0
  12. data/lib/gitlab_quality/test_tooling/code_coverage/click_house/test_file_mappings_table.rb +52 -0
  13. data/lib/gitlab_quality/test_tooling/code_coverage/coverage_data.rb +77 -34
  14. data/lib/gitlab_quality/test_tooling/code_coverage/lcov_file.rb +11 -1
  15. data/lib/gitlab_quality/test_tooling/code_coverage/responsibility_classifier.rb +47 -0
  16. data/lib/gitlab_quality/test_tooling/code_coverage/responsibility_patterns_config.rb +46 -0
  17. data/lib/gitlab_quality/test_tooling/code_coverage/test_file_mapping_data.rb +46 -0
  18. data/lib/gitlab_quality/test_tooling/report/results_in_test_cases.rb +2 -4
  19. data/lib/gitlab_quality/test_tooling/runtime/env.rb +4 -0
  20. data/lib/gitlab_quality/test_tooling/test_meta/processor/meta_processor.rb +1 -1
  21. data/lib/gitlab_quality/test_tooling/test_meta/test_meta_updater.rb +4 -4
  22. data/lib/gitlab_quality/test_tooling/test_metrics_exporter/config.rb +8 -0
  23. data/lib/gitlab_quality/test_tooling/test_metrics_exporter/test_metrics.rb +36 -10
  24. data/lib/gitlab_quality/test_tooling/test_metrics_exporter/utils.rb +2 -0
  25. data/lib/gitlab_quality/test_tooling/test_quarantine/quarantine_formatter.rb +38 -0
  26. data/lib/gitlab_quality/test_tooling/test_quarantine/quarantine_helper.rb +76 -0
  27. data/lib/gitlab_quality/test_tooling/test_result/base_test_result.rb +15 -1
  28. data/lib/gitlab_quality/test_tooling/version.rb +1 -1
  29. metadata +11 -28
  30. data/exe/existing-test-health-issue +0 -59
  31. data/exe/generate-test-session +0 -70
  32. data/lib/gitlab_quality/test_tooling/report/generate_test_session.rb +0 -288
  33. data/lib/gitlab_quality/test_tooling/report/test_health_issue_finder.rb +0 -79
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GitlabQuality
4
+ module TestTooling
5
+ module CodeCoverage
6
+ class TestFileMappingData
7
+ # @param [Hash<String, Array<String>>] test_to_sources Test files
8
+ # mapped to all source files they cover
9
+ # @param [Hash<String, Array<String>>] tests_to_categories Test files
10
+ # mapped to their feature categories
11
+ # @param [Hash<String, Hash>] feature_categories_to_teams Feature categories
12
+ # mapped to their org hierarchy (group, stage, section)
13
+ def initialize(test_to_sources, tests_to_categories: {}, feature_categories_to_teams: {})
14
+ @test_to_sources = test_to_sources
15
+ @tests_to_categories = tests_to_categories
16
+ @feature_categories_to_teams = feature_categories_to_teams
17
+ end
18
+
19
+ # @return [Array<Hash<Symbol, String>>] Mapping data formatted for database insertion
20
+ # @example Return value
21
+ # [
22
+ # { test_file: "spec/models/user_spec.rb", source_file: "app/models/user.rb",
23
+ # category: "team_planning", group: "project_management", stage: "plan", section: "dev" },
24
+ # ...
25
+ # ]
26
+ def as_db_table
27
+ @test_to_sources.flat_map do |test_file, source_files|
28
+ category = @tests_to_categories[test_file]&.first || ''
29
+ team = @feature_categories_to_teams[category] || {}
30
+
31
+ source_files.map do |source_file|
32
+ {
33
+ test_file: test_file,
34
+ source_file: source_file,
35
+ category: category,
36
+ group: team[:group] || '',
37
+ stage: team[:stage] || '',
38
+ section: team[:section] || ''
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'erb'
4
-
5
3
  module GitlabQuality
6
4
  module TestTooling
7
5
  module Report
@@ -68,12 +66,12 @@ module GitlabQuality
68
66
  end
69
67
 
70
68
  def execution_graph_section(test)
71
- formatted_title = ERB::Util.url_encode(test.name)
69
+ formatted_path = CGI.escape(test.relative_file)
72
70
 
73
71
  <<~MKDOWN.strip
74
72
  ### Executions
75
73
 
76
- [Spec metrics on all environments](https://dashboards.quality.gitlab.net/d/cW0UMgv7k/single-spec-metrics?orgId=1&var-run_type=All&var-name=#{formatted_title})
74
+ [Spec metrics on all environments](https://dashboards.devex.gitlab.net/d/739c1bdd-a436-452b-bddc-fccb4d055768/single-test-overview?var-file_path=#{formatted_path})
77
75
  MKDOWN
78
76
  end
79
77
 
@@ -103,6 +103,10 @@ module GitlabQuality
103
103
  "#{ci_project_name}-#{test_subset}"
104
104
  end
105
105
 
106
+ def quarantine_disabled?
107
+ enabled?(ENV.fetch('GLCI_DISABLE_QUARANTINE', nil), default: false)
108
+ end
109
+
106
110
  private
107
111
 
108
112
  def enabled?(value, default: true)
@@ -45,7 +45,7 @@ module GitlabQuality
45
45
  commits.each_with_index.map do |(changed_line_number, spec), index|
46
46
  <<~MARKDOWN
47
47
  #{index + 1}. [`#{spec['name']}`](https://gitlab.com/#{context.project}/-/blob/#{context.ref}/#{spec['file_path']}#L#{changed_line_number.to_i + 1})
48
- | [Testcase](#{spec['testcase']}) | [Spec metrics](#{context.single_spec_metrics_link(spec['name'])})
48
+ | [Testcase](#{spec['testcase']}) | [Spec metrics](#{context.single_spec_metrics_link(spec['file_path'])})
49
49
  #{failure_issue_text(spec)}
50
50
  MARKDOWN
51
51
  end.join("\n")
@@ -348,11 +348,11 @@ module GitlabQuality
348
348
 
349
349
  # Returns the link to the Grafana dashboard for single spec metrics
350
350
  #
351
- # @param [String] example_name the full example name
351
+ # @param [String] file_path the full path of spec
352
352
  # @return [String]
353
- def single_spec_metrics_link(example_name)
354
- base_url = "https://dashboards.quality.gitlab.net/d/cW0UMgv7k/single-spec-metrics?orgId=1&var-run_type=All&var-name="
355
- base_url + CGI.escape(example_name)
353
+ def single_spec_metrics_link(file_path)
354
+ base_url = "https://dashboards.devex.gitlab.net/d/739c1bdd-a436-452b-bddc-fccb4d055768/single-test-overview?var-file_path="
355
+ base_url + CGI.escape(file_path)
356
356
  end
357
357
 
358
358
  # Returns any test description string within single or double quotes
@@ -52,6 +52,7 @@ module GitlabQuality
52
52
  :skip_record_proc,
53
53
  :test_retried_proc,
54
54
  :custom_metrics_proc,
55
+ :spec_file_path_prefix,
55
56
  :logger
56
57
 
57
58
  # rubocop:disable Style/TrivialAccessors -- allows documenting that setting config enables the export as well as document input class type
@@ -108,6 +109,13 @@ module GitlabQuality
108
109
  @extra_rspec_metadata_keys ||= []
109
110
  end
110
111
 
112
+ # Extra path prefix for constructing full file path within mono-repository setups
113
+ #
114
+ # @return [String]
115
+ def spec_file_path_prefix
116
+ @spec_file_path_prefix ||= ""
117
+ end
118
+
111
119
  # A lambda that determines whether to skip recording a test result
112
120
  #
113
121
  # This is useful when you would want to skip initial failure when retrying specs is set up in a separate process
@@ -46,12 +46,16 @@ module GitlabQuality
46
46
  status: example.execution_result.status,
47
47
  run_time: (example.execution_result.run_time * 1000).round,
48
48
  location: example_location,
49
- exception_class: exception_class,
49
+ # TODO: remove exception_class once migration to exception_classes is fully complete on clickhouse side
50
+ exception_class: example.execution_result.exception&.class&.to_s,
51
+ exception_classes: exception_classes.map { |e| e.class.to_s }.uniq,
50
52
  failure_exception: failure_exception,
51
53
  quarantined: quarantined?,
54
+ quarantine_issue_url: quarantine_issue_url || "",
52
55
  feature_category: example.metadata[:feature_category] || "",
53
56
  test_retried: config.test_retried_proc.call(example),
54
- run_type: run_type
57
+ run_type: run_type,
58
+ spec_file_path_prefix: config.spec_file_path_prefix
55
59
  }
56
60
  end
57
61
 
@@ -95,6 +99,25 @@ module GitlabQuality
95
99
  example.execution_result.status == :pending
96
100
  end
97
101
 
102
+ # Extract quarantine issue URL from metadata
103
+ #
104
+ # @return [String, nil]
105
+ def quarantine_issue_url
106
+ return nil unless example.metadata.key?(:quarantine)
107
+
108
+ metadata = example.metadata[:quarantine]
109
+ case metadata
110
+ when String
111
+ # Direct URL: quarantine: 'https://gitlab.com/.../issues/123'
112
+ metadata if metadata.start_with?('http')
113
+ when Hash
114
+ # Hash format: quarantine: { issue: 'https://...', reason: '...' }
115
+ issue = metadata[:issue] || metadata['issue']
116
+ # Handle array of URLs (take the first one)
117
+ issue.is_a?(Array) ? issue.first : issue
118
+ end
119
+ end
120
+
98
121
  # Base ci job name
99
122
  #
100
123
  # @return [String]
@@ -127,22 +150,25 @@ module GitlabQuality
127
150
  @file_path ||= example_location.gsub(/:\d+$/, "")
128
151
  end
129
152
 
130
- # Failure exception class
153
+ # Failure exception classes
131
154
  #
132
- # @return [String]
133
- def exception_class
134
- example.execution_result.exception&.class&.to_s
155
+ # @return [Array<Exception>]
156
+ def exception_classes
157
+ exception = example.execution_result.exception
158
+ return [] unless exception
159
+ return [exception] unless exception.respond_to?(:all_exceptions)
160
+
161
+ exception.all_exceptions.flatten
135
162
  end
136
163
 
137
164
  # Truncated exception stacktrace
138
165
  #
139
166
  # @return [String]
140
167
  def failure_exception
141
- example.execution_result.exception.then do |exception|
142
- next unless exception
168
+ exception = example.execution_result.exception
169
+ return unless exception
143
170
 
144
- exception.to_s.tr("\n", " ").slice(0, 1000)
145
- end
171
+ exception.to_s.tr("\n", " ").slice(0, 1000)
146
172
  end
147
173
 
148
174
  # Test run type | suite name
@@ -65,6 +65,7 @@ module GitlabQuality
65
65
  test_retried Bool,
66
66
  feature_category LowCardinality(String) DEFAULT 'unknown',
67
67
  run_type LowCardinality(String) DEFAULT 'unknown',
68
+ spec_file_path_prefix LowCardinality(String) DEFAULT '',
68
69
  ci_project_id UInt32,
69
70
  ci_job_name LowCardinality(String),
70
71
  ci_job_id UInt64,
@@ -75,6 +76,7 @@ module GitlabQuality
75
76
  ci_target_branch LowCardinality(String),
76
77
  ci_server_url LowCardinality(String) DEFAULT 'https://gitlab.com',
77
78
  exception_class String DEFAULT '',
79
+ exception_classes Array(String) DEFAULT [],
78
80
  failure_exception String DEFAULT ''
79
81
  )
80
82
  ENGINE = MergeTree()
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/core/formatters/base_formatter"
4
+
5
+ module GitlabQuality
6
+ module TestTooling
7
+ module TestQuarantine
8
+ class QuarantineFormatter < ::RSpec::Core::Formatters::BaseFormatter
9
+ include QuarantineHelper
10
+
11
+ ::RSpec::Core::Formatters.register(
12
+ self,
13
+ :example_group_started,
14
+ :example_started
15
+ )
16
+
17
+ # Starts example group
18
+ # @param [RSpec::Core::Notifications::GroupNotification] example_group_notification
19
+ # @return [void]
20
+ def example_group_started(example_group_notification)
21
+ group = example_group_notification.group
22
+
23
+ skip_or_run_quarantined_tests_or_contexts(group)
24
+ end
25
+
26
+ # Starts example
27
+ # @param [RSpec::Core::Notifications::ExampleNotification] example_notification
28
+ # @return [void]
29
+ def example_started(example_notification)
30
+ example = example_notification.example
31
+
32
+ # if skip propagated from example_group, do not reset skip metadata
33
+ skip_or_run_quarantined_tests_or_contexts(example) unless example.metadata[:skip]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core'
4
+
5
+ module GitlabQuality
6
+ module TestTooling
7
+ module TestQuarantine
8
+ module QuarantineHelper
9
+ include ::RSpec::Core::Pending
10
+
11
+ extend self
12
+
13
+ # Skip tests in quarantine unless we explicitly focus on them or quarantine disabled
14
+ def skip_or_run_quarantined_tests_or_contexts(example)
15
+ return if Runtime::Env.quarantine_disabled?
16
+
17
+ if filters.key?(:quarantine)
18
+ included_filters = filters_other_than_quarantine
19
+
20
+ # If :quarantine is focused, skip the test/context unless its metadata
21
+ # includes quarantine and any other filters
22
+ # E.g., Suppose a test is tagged :smoke and :quarantine, and another is tagged
23
+ # :ldap and :quarantine. If we wanted to run just quarantined smoke tests
24
+ # using `--tag quarantine --tag smoke`, without this check we'd end up
25
+ # running that ldap test as well because of the :quarantine metadata.
26
+ # We could use an exclusion filter, but this way the test report will list
27
+ # the quarantined tests when they're not run so that we're aware of them
28
+ if should_skip_when_focused?(example.metadata, included_filters)
29
+ example.metadata[:skip] = "Only running tests tagged with :quarantine and any of #{included_filters.keys}"
30
+ end
31
+ elsif example.metadata.key?(:quarantine)
32
+ quarantine_tag = example.metadata[:quarantine]
33
+
34
+ example.metadata[:skip] = quarantine_message(quarantine_tag)
35
+ end
36
+ end
37
+
38
+ def filters_other_than_quarantine
39
+ filters.except(:quarantine)
40
+ end
41
+
42
+ def quarantine_message(quarantine_tag)
43
+ quarantine_message = %w[In quarantine]
44
+ quarantine_message << case quarantine_tag
45
+ when String
46
+ ": #{quarantine_tag}"
47
+ when Hash
48
+ quarantine_tag.key?(:issue) ? ": #{quarantine_tag[:issue]}" : ''
49
+ else
50
+ ''
51
+ end
52
+
53
+ quarantine_message.join(' ').strip
54
+ end
55
+
56
+ # Checks if a test or context should be skipped.
57
+ #
58
+ # Returns true if
59
+ # - the metadata does not includes the :quarantine tag
60
+ # or if
61
+ # - the metadata includes the :quarantine tag
62
+ # - and the filter includes other tags that aren't in the metadata
63
+ def should_skip_when_focused?(metadata, included_filters)
64
+ return true unless metadata.key?(:quarantine)
65
+ return false if included_filters.empty?
66
+
67
+ !metadata.keys.intersect?(included_filters.keys)
68
+ end
69
+
70
+ def filters
71
+ @filters ||= ::RSpec.configuration.inclusion_filter.rules
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -8,11 +8,13 @@ module GitlabQuality
8
8
  "Net::ReadTimeout",
9
9
  "403 Forbidden - Your account has been blocked",
10
10
  "API failed (502) with `GitLab is not responding",
11
+ "Error Code: 502",
11
12
  "unexpected token at 'GitLab is not responding'",
12
13
  "GitLab: Internal API error (502).",
13
14
  "could not be found (502)",
14
15
  "Error reference number: 502",
15
16
  "(502): `GitLab is not responding`",
17
+ "(502): `502 Bad Gateway`",
16
18
  "<head><title>502 Bad Gateway</title></head>",
17
19
  "14:connections to all backends failing",
18
20
  "gitlab_canary=true cookie was set in browser but 'Next' badge was not shown on UI"
@@ -127,14 +129,26 @@ module GitlabQuality
127
129
  end
128
130
 
129
131
  def full_stacktrace
132
+ page_error_failure = ""
133
+ first_non_ignored_failure = ""
134
+
130
135
  failures.each do |failure|
131
136
  message = failure['message'] || ""
132
137
  message_lines = failure['message_lines'] || []
133
138
 
134
139
  next if IGNORED_FAILURES.any? { |e| message.include?(e) }
135
140
 
136
- return message_lines.empty? ? message : message_lines.join("\n")
141
+ formatted_failure = message_lines.empty? ? message : message_lines.join("\n")
142
+
143
+ if message.include?("PageErrorChecker")
144
+ page_error_failure = formatted_failure
145
+ elsif first_non_ignored_failure.empty?
146
+ first_non_ignored_failure = formatted_failure
147
+ end
137
148
  end
149
+
150
+ # Return PageErrorChecker failure if found, otherwise first non-ignored failure
151
+ page_error_failure.empty? ? first_non_ignored_failure : page_error_failure
138
152
  end
139
153
 
140
154
  def calls_shared_examples?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "3.0.0"
5
+ VERSION = "3.7.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: 3.0.0
4
+ version: 3.7.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-11-17 00:00:00.000000000 Z
11
+ date: 2026-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control
@@ -227,9 +227,6 @@ dependencies:
227
227
  - - ">="
228
228
  - !ruby/object:Gem::Version
229
229
  version: '7.0'
230
- - - "<"
231
- - !ruby/object:Gem::Version
232
- version: '7.3'
233
230
  type: :runtime
234
231
  prerelease: false
235
232
  version_requirements: !ruby/object:Gem::Requirement
@@ -237,9 +234,6 @@ dependencies:
237
234
  - - ">="
238
235
  - !ruby/object:Gem::Version
239
236
  version: '7.0'
240
- - - "<"
241
- - !ruby/object:Gem::Version
242
- version: '7.3'
243
237
  - !ruby/object:Gem::Dependency
244
238
  name: amatch
245
239
  requirement: !ruby/object:Gem::Requirement
@@ -308,20 +302,6 @@ dependencies:
308
302
  - - "~>"
309
303
  - !ruby/object:Gem::Version
310
304
  version: '5.0'
311
- - !ruby/object:Gem::Dependency
312
- name: influxdb-client
313
- requirement: !ruby/object:Gem::Requirement
314
- requirements:
315
- - - "~>"
316
- - !ruby/object:Gem::Version
317
- version: '3.1'
318
- type: :runtime
319
- prerelease: false
320
- version_requirements: !ruby/object:Gem::Requirement
321
- requirements:
322
- - - "~>"
323
- - !ruby/object:Gem::Version
324
- version: '3.1'
325
305
  - !ruby/object:Gem::Dependency
326
306
  name: nokogiri
327
307
  requirement: !ruby/object:Gem::Requirement
@@ -436,12 +416,10 @@ email:
436
416
  executables:
437
417
  - detect-infrastructure-failures
438
418
  - epic-readiness-notification
439
- - existing-test-health-issue
440
419
  - failed-test-issues
441
420
  - feature-readiness-checklist
442
421
  - feature-readiness-evaluation
443
422
  - flaky-test-issues
444
- - generate-test-session
445
423
  - knapsack-report-issues
446
424
  - post-to-slack
447
425
  - prepare-stage-reports
@@ -449,6 +427,7 @@ executables:
449
427
  - report-results
450
428
  - slow-test-issues
451
429
  - slow-test-merge-request-report-note
430
+ - sync-category-owners
452
431
  - test-coverage
453
432
  - update-screenshot-paths
454
433
  - update-test-meta
@@ -471,12 +450,10 @@ files:
471
450
  - Rakefile
472
451
  - exe/detect-infrastructure-failures
473
452
  - exe/epic-readiness-notification
474
- - exe/existing-test-health-issue
475
453
  - exe/failed-test-issues
476
454
  - exe/feature-readiness-checklist
477
455
  - exe/feature-readiness-evaluation
478
456
  - exe/flaky-test-issues
479
- - exe/generate-test-session
480
457
  - exe/knapsack-report-issues
481
458
  - exe/post-to-slack
482
459
  - exe/prepare-stage-reports
@@ -484,21 +461,27 @@ files:
484
461
  - exe/report-results
485
462
  - exe/slow-test-issues
486
463
  - exe/slow-test-merge-request-report-note
464
+ - exe/sync-category-owners
487
465
  - exe/test-coverage
488
466
  - exe/update-screenshot-paths
489
467
  - exe/update-test-meta
490
468
  - lefthook.yml
491
469
  - lib/gitlab_quality/test_tooling.rb
492
470
  - lib/gitlab_quality/test_tooling/click_house/client.rb
471
+ - lib/gitlab_quality/test_tooling/code_coverage/README.md
493
472
  - lib/gitlab_quality/test_tooling/code_coverage/artifacts.rb
494
473
  - lib/gitlab_quality/test_tooling/code_coverage/category_owners.rb
495
474
  - lib/gitlab_quality/test_tooling/code_coverage/click_house/category_owners_table.rb
496
475
  - lib/gitlab_quality/test_tooling/code_coverage/click_house/coverage_metrics_table.rb
497
476
  - lib/gitlab_quality/test_tooling/code_coverage/click_house/table.rb
477
+ - lib/gitlab_quality/test_tooling/code_coverage/click_house/test_file_mappings_table.rb
498
478
  - lib/gitlab_quality/test_tooling/code_coverage/coverage_data.rb
499
479
  - lib/gitlab_quality/test_tooling/code_coverage/lcov_file.rb
480
+ - lib/gitlab_quality/test_tooling/code_coverage/responsibility_classifier.rb
481
+ - lib/gitlab_quality/test_tooling/code_coverage/responsibility_patterns_config.rb
500
482
  - lib/gitlab_quality/test_tooling/code_coverage/rspec_report.rb
501
483
  - lib/gitlab_quality/test_tooling/code_coverage/source_file_classifier.rb
484
+ - lib/gitlab_quality/test_tooling/code_coverage/test_file_mapping_data.rb
502
485
  - lib/gitlab_quality/test_tooling/code_coverage/test_map.rb
503
486
  - lib/gitlab_quality/test_tooling/code_coverage/test_report.rb
504
487
  - lib/gitlab_quality/test_tooling/code_coverage/utils.rb
@@ -541,7 +524,6 @@ files:
541
524
  - lib/gitlab_quality/test_tooling/report/failed_test_issue.rb
542
525
  - lib/gitlab_quality/test_tooling/report/feature_readiness/report_on_epic.rb
543
526
  - lib/gitlab_quality/test_tooling/report/flaky_test_issue.rb
544
- - lib/gitlab_quality/test_tooling/report/generate_test_session.rb
545
527
  - lib/gitlab_quality/test_tooling/report/group_issues/error_message_normalizer.rb
546
528
  - lib/gitlab_quality/test_tooling/report/group_issues/error_pattern_matcher.rb
547
529
  - lib/gitlab_quality/test_tooling/report/group_issues/failure_processor.rb
@@ -564,7 +546,6 @@ files:
564
546
  - lib/gitlab_quality/test_tooling/report/results_in_issues.rb
565
547
  - lib/gitlab_quality/test_tooling/report/results_in_test_cases.rb
566
548
  - lib/gitlab_quality/test_tooling/report/slow_test_issue.rb
567
- - lib/gitlab_quality/test_tooling/report/test_health_issue_finder.rb
568
549
  - lib/gitlab_quality/test_tooling/report/update_screenshot_path.rb
569
550
  - lib/gitlab_quality/test_tooling/runtime/env.rb
570
551
  - lib/gitlab_quality/test_tooling/runtime/logger.rb
@@ -595,6 +576,8 @@ files:
595
576
  - lib/gitlab_quality/test_tooling/test_metrics_exporter/formatter.rb
596
577
  - lib/gitlab_quality/test_tooling/test_metrics_exporter/test_metrics.rb
597
578
  - lib/gitlab_quality/test_tooling/test_metrics_exporter/utils.rb
579
+ - lib/gitlab_quality/test_tooling/test_quarantine/quarantine_formatter.rb
580
+ - lib/gitlab_quality/test_tooling/test_quarantine/quarantine_helper.rb
598
581
  - lib/gitlab_quality/test_tooling/test_result/base_test_result.rb
599
582
  - lib/gitlab_quality/test_tooling/test_result/j_unit_test_result.rb
600
583
  - lib/gitlab_quality/test_tooling/test_result/json_test_result.rb
@@ -1,59 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "optparse"
6
-
7
- require_relative "../lib/gitlab_quality/test_tooling"
8
-
9
- params = {}
10
- HEALTH_PROBLEM_TYPES = GitlabQuality::TestTooling::Report::TestHealthIssueFinder::HEALTH_PROBLEM_TYPE_TO_LABEL.keys
11
-
12
- options = OptionParser.new do |opts|
13
- opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
14
-
15
- opts.on('-i', '--input-files INPUT_FILES', String, 'JSON rspec-retry report files') do |input_files|
16
- params[:input_files] = input_files
17
- end
18
-
19
- opts.on('-p', '--project PROJECT', String, 'Can be an integer or a group/project string') do |project|
20
- params[:project] = project
21
- end
22
-
23
- opts.on('-t', '--token TOKEN', String, 'A valid access token with `api` scope and Maintainer permission in PROJECT') do |token|
24
- params[:token] = token
25
- end
26
-
27
- opts.on("--health-problem-type PROBLEM_TYPE", String, "Look for the given health problem type (#{HEALTH_PROBLEM_TYPES.join(', ')})") do |value|
28
- raise ArgumentError, "Invalid health problem type: #{value}. Valid options are: #{HEALTH_PROBLEM_TYPES.join(', ')}" unless HEALTH_PROBLEM_TYPES.include?(value)
29
-
30
- params[:health_problem_type] = value
31
- end
32
-
33
- opts.on_tail('-v', '--version', 'Show the version') do
34
- require_relative "../lib/gitlab_quality/test_tooling/version"
35
- puts "#{$PROGRAM_NAME} : #{GitlabQuality::TestTooling::VERSION}"
36
- exit
37
- end
38
-
39
- opts.on_tail('-h', '--help', 'Show the usage') do
40
- puts "Purpose: Checks whether tests coming from the rspec JSON report files has an existing test health issue opened."
41
- puts opts
42
- exit
43
- end
44
-
45
- opts.parse(ARGV)
46
- end
47
-
48
- if params.any?
49
- raise ArgumentError, "No health problem type given. Valid options are: #{HEALTH_PROBLEM_TYPES.join(', ')}" unless params.key?(:health_problem_type)
50
-
51
- if GitlabQuality::TestTooling::Report::TestHealthIssueFinder.new(**params).found_existing_unhealthy_test_issue?
52
- exit 0
53
- else
54
- exit 1
55
- end
56
- else
57
- puts options
58
- exit 1
59
- end
@@ -1,70 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "optparse"
6
-
7
- require_relative "../lib/gitlab_quality/test_tooling"
8
-
9
- params = {}
10
-
11
- options = OptionParser.new do |opts|
12
- opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
13
-
14
- opts.on('-i', '--input-files INPUT_FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
15
- params[:input_files] = input_files
16
- end
17
-
18
- opts.on('-p', '--project PROJECT', String, 'Can be an integer or a group/project string') do |project|
19
- params[:project] = project
20
- end
21
-
22
- opts.on('-t', '--token TOKEN', String, 'A valid access token with `api` scope and Reporter permission in PROJECT') do |token|
23
- params[:token] = token
24
- end
25
-
26
- opts.on('-c', '--ci-project-token CI_PROJECT_TOKEN', String, 'A valid access token with `read_api` scope permission in current ENV["CI_PROJECT_ID"]') do |ci_project_token|
27
- params[:ci_project_token] = ci_project_token
28
- end
29
-
30
- opts.on('-f', '--issue-url-file ISSUE_URL_FILE', 'Output the created test session issue URL') do |issue_url_file|
31
- params[:issue_url_file] = issue_url_file
32
- end
33
-
34
- opts.on('--pipeline-stages STAGES', String, 'Comma-separated list of pipeline stages to include in test session issue') do |pipeline_stages|
35
- params[:pipeline_stages] = pipeline_stages.split(',')
36
- end
37
-
38
- opts.on('--confidential', "Makes test session issue confidential") do
39
- params[:confidential] = true
40
- end
41
-
42
- opts.on('--dry-run', "Perform a dry-run (don't create or update issues or test cases)") do
43
- params[:dry_run] = true
44
- end
45
-
46
- opts.on_tail('-v', '--version', 'Show the version') do
47
- require_relative "../lib/gitlab_quality/test_tooling/version"
48
- puts "#{$PROGRAM_NAME} : #{GitlabQuality::TestTooling::VERSION}"
49
- exit
50
- end
51
-
52
- opts.on_tail('-h', '--help', 'Show the usage') do
53
- puts "Purpose: Generate test session report based on RSpec report files (JSON or JUnit XML)"
54
- puts opts
55
- exit
56
- end
57
-
58
- opts.parse(ARGV)
59
- end
60
-
61
- issue_url_file = params.delete(:issue_url_file)
62
-
63
- if params.any?
64
- issue_url = GitlabQuality::TestTooling::Report::GenerateTestSession.new(**params).invoke!
65
-
66
- File.write(issue_url_file, issue_url) if issue_url_file && issue_url
67
- else
68
- puts options
69
- exit 1
70
- end