gitlab_quality-test_tooling 3.20.2 → 3.21.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: 6d63cdc47b44dd111330eaffb4e37c889d8785eb395094eec7398c97870f889f
4
- data.tar.gz: bbe3389c97486d566bb8a948da3a88cf94633857d8eee5ad9fbb53e6ba38aef5
3
+ metadata.gz: 6fa78c58b83ed94504f42df7a78f5bdbddea78f9466134618b6c9b34fa99d679
4
+ data.tar.gz: bb3b04f2dee89712fd561a944de2d397db62867351f562ac0b0e7cac721424d2
5
5
  SHA512:
6
- metadata.gz: 81d28ad1a352c06db086546c5eef55f9f82aa982904e4f3e03ab1c7e509d0a18fde12f6e77e7a09eda3c549dd15ff1d0090f532a2da60eda68d31eba77cee93f
7
- data.tar.gz: 8aeb35ec5c0fc54e86c9cb029f44c62feb9dbc1e5031f6d4aaba07a9a3e3791a739841da7a1080bf1c28c05c81baee57a42742dca5ab60d1420e8e74360b9b9c
6
+ metadata.gz: d969c70fbf9efb0aac4020367999aca505d226125a63daeaa8dc6f5ad409f84d8f9bc6a411ada6c9aa5c91627ef8bec768a165bcf4258df0e7e65426d63776c3
7
+ data.tar.gz: d3329d8d499320cd0fdad6a8a2c9ea669d7310b1076aa5c8130e3c4b79e6f12e2fc2a32ecaa0a11f057860f8c8f82db9551120f5f0b5ce28f9a1898597a74842
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (3.20.2)
4
+ gitlab_quality-test_tooling (3.21.0)
5
5
  activesupport (>= 7.0)
6
6
  amatch (~> 0.4.1)
7
7
  fog-google (~> 1.24, >= 1.24.1)
data/exe/test-coverage CHANGED
@@ -73,7 +73,9 @@ options = OptionParser.new do |opts|
73
73
  'Inserts rows into code_coverage.test_coverage_per_file and runs the daily ' \
74
74
  'test_health_risk aggregation unless --skip-aggregation. Needs only the ' \
75
75
  '--clickhouse-* options; --test-reports and --jest-quarantine-file are ' \
76
- 'optional enrichment. (e.g., "tmp/per-test-coverage-*.ndjson")') do |pattern|
76
+ 'optional enrichment. --test-reports also requires --clickhouse-shared-database, ' \
77
+ 'since category ownership is read from the shared database. ' \
78
+ '(e.g., "tmp/per-test-coverage-*.ndjson")') do |pattern|
77
79
  params[:per_test_coverage] = pattern
78
80
  end
79
81
 
@@ -135,7 +137,16 @@ mode =
135
137
  clickhouse_required = [:clickhouse_url, :clickhouse_database, :clickhouse_username]
136
138
  full_export_required =
137
139
  [:test_reports, :coverage_report, :test_map, :responsibility_patterns, :clickhouse_shared_database] + clickhouse_required
138
- required_params = mode == :full_export ? full_export_required : clickhouse_required
140
+ # Per-test mode reads category_owners from the shared database only when it enriches
141
+ # rows (--test-reports present), so require the shared database exactly then.
142
+ per_test_enriching = mode == :per_test && params[:test_reports]
143
+ required_params =
144
+ case mode
145
+ when :full_export
146
+ full_export_required
147
+ else
148
+ per_test_enriching ? clickhouse_required + [:clickhouse_shared_database] : clickhouse_required
149
+ end
139
150
 
140
151
  unless params.any? && (required_params - params.keys).none?
141
152
  puts "Missing argument(s). Required arguments are: #{required_params}\nPassed arguments are: #{params}\n"
@@ -149,7 +160,13 @@ if clickhouse_password.to_s.strip.empty?
149
160
  exit 1
150
161
  end
151
162
 
152
- non_empty_params = mode == :full_export ? clickhouse_required + [:clickhouse_shared_database] : clickhouse_required
163
+ non_empty_params =
164
+ if mode == :full_export || per_test_enriching
165
+ clickhouse_required + [:clickhouse_shared_database]
166
+ else
167
+ clickhouse_required
168
+ end
169
+
153
170
  non_empty_params.each do |param|
154
171
  next unless params[param].to_s.strip.empty?
155
172
 
@@ -189,6 +206,7 @@ when :per_test
189
206
  GitlabQuality::TestTooling::CodeCoverage::PerTestCoverageExporter.new(
190
207
  coverage_glob: params[:per_test_coverage],
191
208
  clickhouse: clickhouse_data,
209
+ clickhouse_shared_database: params[:clickhouse_shared_database],
192
210
  test_reports: params[:test_reports],
193
211
  jest_quarantine_file: params[:jest_quarantine_file],
194
212
  skip_aggregation: params.fetch(:skip_aggregation, false)
@@ -23,12 +23,15 @@ module GitlabQuality
23
23
  # aggregation once at the end.
24
24
  class PerTestCoverageExporter
25
25
  # @param clickhouse [Hash] connection params (:url, :database, :username, :password)
26
+ # @param clickhouse_shared_database [String, nil] the shared database holding the
27
+ # canonical `category_owners`. Required only when enriching (test_reports present).
26
28
  def initialize(
27
- coverage_glob:, clickhouse:,
29
+ coverage_glob:, clickhouse:, clickhouse_shared_database: nil,
28
30
  test_reports: nil, jest_quarantine_file: nil,
29
31
  captured_sha: ENV.fetch('CI_COMMIT_SHA', ''), skip_aggregation: false, logger: nil)
30
32
  @coverage_glob = coverage_glob
31
33
  @clickhouse = clickhouse
34
+ @clickhouse_shared_database = clickhouse_shared_database
32
35
  @test_reports = test_reports
33
36
  @jest_quarantine_file = jest_quarantine_file
34
37
  @captured_sha = captured_sha.to_s
@@ -65,8 +68,8 @@ module GitlabQuality
65
68
 
66
69
  private
67
70
 
68
- attr_reader :coverage_glob, :clickhouse, :test_reports, :jest_quarantine_file,
69
- :captured_sha, :skip_aggregation, :logger
71
+ attr_reader :coverage_glob, :clickhouse, :clickhouse_shared_database, :test_reports,
72
+ :jest_quarantine_file, :captured_sha, :skip_aggregation, :logger
70
73
 
71
74
  def insert(coverage_files)
72
75
  tests_to_categories, feature_categories_to_teams = resolve_categories
@@ -144,14 +147,21 @@ module GitlabQuality
144
147
  [tests_to_categories_from(report_files), feature_categories_to_teams]
145
148
  end
146
149
 
147
- # Category to group/stage/section, read from `code_coverage.category_owners`
148
- # (populated by sync-category-owners). This is the source the full
149
- # coverage export already uses, and it retains categories the live
150
- # stages.yml fetch has since dropped (global_search and the Duo/AI groups),
151
- # so more rows resolve to a real group instead of blank. `owner_records`
152
- # gives string-keyed values; PerTestCoverageData reads symbol keys.
150
+ # Category to group/stage/section, read from `category_owners` in the shared
151
+ # database, the same source the full coverage export uses. The shared copy is
152
+ # refreshed by sync-category-owners; the legacy `code_coverage.category_owners`
153
+ # stopped updating in December 2025, so reading it would drop every category
154
+ # added since. `owner_records` gives string-keyed values; PerTestCoverageData
155
+ # reads symbol keys.
153
156
  def feature_categories_to_teams
154
- ClickHouse::CategoryOwnersTable.new(**clickhouse_credentials).owner_records.transform_values do |owner|
157
+ if clickhouse_shared_database.to_s.strip.empty?
158
+ raise ArgumentError,
159
+ 'clickhouse_shared_database is required to enrich per-test rows with category owners'
160
+ end
161
+
162
+ shared_credentials = clickhouse_credentials.merge(database: clickhouse_shared_database)
163
+
164
+ ClickHouse::CategoryOwnersTable.new(**shared_credentials).owner_records.transform_values do |owner|
155
165
  { group: owner["group"], stage: owner["stage"], section: owner["section"] }
156
166
  end
157
167
  end
@@ -151,7 +151,6 @@ module GitlabQuality
151
151
  line_number: extract_line_number(test),
152
152
  exception: extract_exception_data(test),
153
153
  ci_job_url: test.ci_job_url,
154
- testcase: extract_test_id_or_name(test),
155
154
  product_group: extract_product_group(test),
156
155
  level: extract_level(test)
157
156
  }
@@ -184,14 +183,6 @@ module GitlabQuality
184
183
  }
185
184
  end
186
185
 
187
- def extract_test_id_or_name(test)
188
- return test.example_id if test.respond_to?(:example_id)
189
- return test.id if test.respond_to?(:id)
190
- return test.name if test.respond_to?(:name)
191
-
192
- "#{test.relative_file}:#{test.respond_to?(:line_number) ? test.line_number : 'unknown'}"
193
- end
194
-
195
186
  def new_issue_labels(test)
196
187
  up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS + group_and_category_labels_for_test(test))
197
188
  end
@@ -63,7 +63,6 @@ module GitlabQuality
63
63
  | Test level | `#{test.level}` |
64
64
  | Hash | `#{test_hash(test)}` |
65
65
  | Max expected duration | < #{test.max_duration_for_test} seconds |
66
- #{"| Test case | #{test.testcase} |" if test.testcase}
67
66
  <!-- Don't modify this section as it's auto-generated -->
68
67
  DESCRIPTION
69
68
  end
@@ -49,16 +49,11 @@ module GitlabQuality
49
49
 
50
50
  report_test(test)
51
51
  end
52
-
53
- test_results.write
54
52
  end
55
53
  end
56
54
 
57
55
  def report_test(test)
58
56
  testcase = testcase_project_reporter.find_or_create_testcase(test)
59
- # The API returns the test case with an issue URL since it is technically a type of issue.
60
- # This updates the URL to a valid test case link.
61
- test.testcase = testcase.web_url.sub('/issues/', '/quality/test_cases/')
62
57
 
63
58
  result_issue, is_new = results_issue_project_reporter.get_related_issue(testcase, test)
64
59
 
@@ -18,18 +18,17 @@ module GitlabQuality
18
18
  find_testcase(test) || create_issue(test)
19
19
  end
20
20
 
21
- def add_result_issue_link_to_testcase(testcase, result_issue, test)
21
+ def add_result_issue_link_to_testcase(testcase, result_issue, _test)
22
22
  results_section = testcase.description.include?(TEST_CASE_RESULTS_SECTION_TEMPLATE) ? '' : TEST_CASE_RESULTS_SECTION_TEMPLATE
23
23
 
24
24
  gitlab.edit_issue(iid: testcase.iid,
25
25
  options: { description: (testcase.description + results_section + "\n\n#{result_issue.web_url}") })
26
- # We are using test.testcase for the url here instead of testcase.web_url since it has the updated test case path
27
- puts "Added results issue #{result_issue.web_url} link to test case #{test.testcase}"
26
+ puts "Added results issue #{result_issue.web_url} link to test case #{testcase.web_url}"
28
27
  end
29
28
 
30
29
  def update_testcase(testcase, test)
31
- puts "Labels updated for test case #{test.testcase}." if update_labels(testcase, test)
32
- puts "Quarantine section updated for test case #{test.testcase}." if update_quarantine_section(testcase, test)
30
+ puts "Labels updated for test case #{testcase.web_url}." if update_labels(testcase, test)
31
+ puts "Quarantine section updated for test case #{testcase.web_url}." if update_quarantine_section(testcase, test)
33
32
  end
34
33
 
35
34
  private
@@ -37,7 +37,7 @@ module GitlabQuality
37
37
  description_start_index + description_length
38
38
  end
39
39
 
40
- # List specs in markdown with details such as link to code, testcase, metrics and failure issue
40
+ # List specs in markdown with details such as link to code, metrics and failure issue
41
41
  #
42
42
  # @param [Hash<String,Hash>] commits The commits hash to use for spec details
43
43
  # @return String
@@ -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['file_path'])})
48
+ | [Spec metrics](#{context.single_spec_metrics_link(spec['file_path'])})
49
49
  #{failure_issue_text(spec)}
50
50
  MARKDOWN
51
51
  end.join("\n")
@@ -4,8 +4,6 @@ module GitlabQuality
4
4
  module TestTooling
5
5
  module TestResult
6
6
  class JUnitTestResult < BaseTestResult
7
- attr_accessor :testcase # Ignore it for now
8
-
9
7
  def name
10
8
  report['name']
11
9
  end
@@ -60,14 +60,6 @@ module GitlabQuality
60
60
  report.fetch('ci_job_url', '')
61
61
  end
62
62
 
63
- def testcase
64
- report.fetch('testcase', '')
65
- end
66
-
67
- def testcase=(new_testcase)
68
- report['testcase'] = new_testcase
69
- end
70
-
71
63
  def quarantine_type
72
64
  quarantine['type'] if quarantine?
73
65
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "3.20.2"
5
+ VERSION = "3.21.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.20.2
4
+ version: 3.21.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: 2026-07-16 00:00:00.000000000 Z
11
+ date: 2026-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control