gitlab_quality-test_tooling 3.18.0 → 3.18.2
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/gitlab_quality/test_tooling/code_coverage/click_house/per_test_coverage_table.rb +41 -8
- data/lib/gitlab_quality/test_tooling/code_coverage/per_test_coverage_data.rb +16 -0
- data/lib/gitlab_quality/test_tooling/code_coverage/per_test_coverage_exporter.rb +5 -1
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 779e0b86d15303be62790f4c55f12654922e2de18fe3505d4305e8a4f4f6320e
|
|
4
|
+
data.tar.gz: e2a2fc54bb3ee013dfad631c8433df72b07a68d9a20502b4ac7310a8d1500c9f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 026a676af6f0ccc7bef7e19778309843d19a17ab96a4d467d9be03def4c683f44ceb36d470611d0405083a4f1738d7bc6f8efd3ec604037c518234d86157f586
|
|
7
|
+
data.tar.gz: 74f87d3383d15086afacaa0dd7cb16336bb16cbe26e1fa32978f0a3cc41757d6e9015d31b0144848ad56efb6855d50aa8e5e00fc002e3bf798af13d456e1c8e2
|
data/Gemfile.lock
CHANGED
|
@@ -20,7 +20,15 @@ module GitlabQuality
|
|
|
20
20
|
# unioned into one row by the loader, not handed in as duplicates.
|
|
21
21
|
class PerTestCoverageTable < GitlabQuality::TestTooling::CodeCoverage::ClickHouse::Table
|
|
22
22
|
TABLE_NAME = "test_coverage_per_file"
|
|
23
|
-
|
|
23
|
+
# Cap each INSERT by rendered byte size rather than a fixed row count.
|
|
24
|
+
# test_coverage_per_file is a SharedReplacingMergeTree partitioned by
|
|
25
|
+
# month, so every INSERT lands a part in one partition; hundreds of
|
|
26
|
+
# tiny inserts pile up parts faster than background merges collapse
|
|
27
|
+
# them, and ClickHouse throttles inserts once the per-partition part
|
|
28
|
+
# count climbs. Batching by bytes keeps the part count low while
|
|
29
|
+
# bounding each statement well within ClickHouse's limits, regardless
|
|
30
|
+
# of how wide a row's covered-line bitmap is.
|
|
31
|
+
MAX_BATCH_BYTES = 4 * 1024 * 1024
|
|
24
32
|
# Intentionally generous ceiling on line numbers. Real source files
|
|
25
33
|
# are thousands of lines; generated artifacts (large GraphQL schemas,
|
|
26
34
|
# bundled JS, JSON manifests) can run past 100k. The cap is set to
|
|
@@ -45,10 +53,11 @@ module GitlabQuality
|
|
|
45
53
|
|
|
46
54
|
return logger.warn("#{LOG_PREFIX} No valid data found after sanitization, skipping ClickHouse export!") if sanitized_data.empty?
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
sanitized_data
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
batch_index = 0
|
|
57
|
+
each_byte_limited_batch(sanitized_data) do |rows_sql|
|
|
58
|
+
batch_index += 1
|
|
59
|
+
logger.debug("#{LOG_PREFIX} Pushing batch #{batch_index} (#{rows_sql.size} rows)")
|
|
60
|
+
client.query(build_insert_sql(rows_sql), format: "TabSeparated")
|
|
52
61
|
end
|
|
53
62
|
logger.info("#{LOG_PREFIX} Successfully pushed #{sanitized_data.size} records to #{full_table_name}")
|
|
54
63
|
rescue StandardError => e
|
|
@@ -115,16 +124,40 @@ module GitlabQuality
|
|
|
115
124
|
}
|
|
116
125
|
end
|
|
117
126
|
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
# Render an INSERT from already-built per-row SQL fragments. Callers
|
|
128
|
+
# group the fragments by byte size via `each_byte_limited_batch`.
|
|
129
|
+
def build_insert_sql(rows_sql)
|
|
120
130
|
<<~SQL
|
|
121
131
|
INSERT INTO #{full_table_name}
|
|
122
132
|
(timestamp, ci_project_path, test_file, source_file, covered_lines, total_lines, feature_category, `group`, stage, section, captured_sha)
|
|
123
133
|
VALUES
|
|
124
|
-
#{rows_sql}
|
|
134
|
+
#{rows_sql.join(",\n")}
|
|
125
135
|
SQL
|
|
126
136
|
end
|
|
127
137
|
|
|
138
|
+
# Yield arrays of rendered row SQL grouped so each INSERT stays under
|
|
139
|
+
# MAX_BATCH_BYTES. A record whose own rendered size exceeds the cap is
|
|
140
|
+
# still emitted alone rather than dropped.
|
|
141
|
+
def each_byte_limited_batch(records)
|
|
142
|
+
batch = []
|
|
143
|
+
batch_bytes = 0
|
|
144
|
+
|
|
145
|
+
records.each do |record|
|
|
146
|
+
row_sql = build_row_sql(record)
|
|
147
|
+
|
|
148
|
+
if batch.any? && batch_bytes + row_sql.bytesize > MAX_BATCH_BYTES
|
|
149
|
+
yield batch
|
|
150
|
+
batch = []
|
|
151
|
+
batch_bytes = 0
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
batch << row_sql
|
|
155
|
+
batch_bytes += row_sql.bytesize
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
yield batch if batch.any?
|
|
159
|
+
end
|
|
160
|
+
|
|
128
161
|
# Precondition: `record[:covered_lines]` is the sanitised integer
|
|
129
162
|
# array produced upstream by `sanitize_lines` (via
|
|
130
163
|
# `sanitized_data_record`). Values are positive integers within
|
|
@@ -50,6 +50,12 @@ module GitlabQuality
|
|
|
50
50
|
# catching unrelated standard exceptions.
|
|
51
51
|
ParseError = Class.new(StandardError)
|
|
52
52
|
|
|
53
|
+
# Source files we never want in coverage risk. Vendored gems (bundled
|
|
54
|
+
# into vendor/ruby in CI) are touched by nearly every test, which both
|
|
55
|
+
# inflates the export volume and pollutes the coverage-risk metrics with
|
|
56
|
+
# third-party code we don't own. Dropped before aggregation.
|
|
57
|
+
EXCLUDED_SOURCE_PREFIXES = %w[vendor/].freeze
|
|
58
|
+
|
|
53
59
|
# @param coverage_files [Array<String>] paths to per-test coverage JSON artifacts
|
|
54
60
|
# @param tests_to_categories [Hash<String, Array<String>>] test_file => [feature_category]
|
|
55
61
|
# @param feature_categories_to_teams [Hash<String, Hash>] category => {group:, stage:, section:}
|
|
@@ -73,6 +79,8 @@ module GitlabQuality
|
|
|
73
79
|
each_example(path) do |example_id, files|
|
|
74
80
|
test_file = extract_test_file_path(example_id)
|
|
75
81
|
files.each do |source_file, line_hits|
|
|
82
|
+
next if excluded_source_file?(source_file)
|
|
83
|
+
|
|
76
84
|
covered, total = parse_line_hits(line_hits)
|
|
77
85
|
next if covered.empty?
|
|
78
86
|
|
|
@@ -168,6 +176,14 @@ module GitlabQuality
|
|
|
168
176
|
end
|
|
169
177
|
[covered, total]
|
|
170
178
|
end
|
|
179
|
+
|
|
180
|
+
# True for source files excluded from coverage entirely (e.g. vendored
|
|
181
|
+
# gems). Strips a leading ./ so both "vendor/..." and "./vendor/..."
|
|
182
|
+
# match.
|
|
183
|
+
def excluded_source_file?(source_file)
|
|
184
|
+
normalized = source_file.to_s.delete_prefix('./')
|
|
185
|
+
EXCLUDED_SOURCE_PREFIXES.any? { |prefix| normalized.start_with?(prefix) }
|
|
186
|
+
end
|
|
171
187
|
end
|
|
172
188
|
end
|
|
173
189
|
end
|
|
@@ -33,7 +33,11 @@ module GitlabQuality
|
|
|
33
33
|
@jest_quarantine_file = jest_quarantine_file
|
|
34
34
|
@captured_sha = captured_sha.to_s
|
|
35
35
|
@skip_aggregation = skip_aggregation
|
|
36
|
-
|
|
36
|
+
# Default to INFO. The export logs every batched INSERT at debug via
|
|
37
|
+
# the ClickHouse client, and at full-bucket scale that floods the CI
|
|
38
|
+
# job log past its size limit and buries real errors. Callers can pass
|
|
39
|
+
# a debug logger explicitly when they need the SQL.
|
|
40
|
+
@logger = logger || ::Logger.new($stdout, level: ::Logger::INFO)
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
# @return [void]
|
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.18.
|
|
4
|
+
version: 3.18.2
|
|
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-06-
|
|
11
|
+
date: 2026-06-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: climate_control
|