gitlab_quality-test_tooling 3.11.0 → 3.13.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 +4 -4
- data/Gemfile.lock +2 -1
- data/lib/gitlab_quality/test_tooling/labels_inference.rb +28 -1
- data/lib/gitlab_quality/test_tooling/report/merge_request_slow_tests_report.rb +22 -7
- data/lib/gitlab_quality/test_tooling/test_metrics_exporter/config.rb +17 -47
- data/lib/gitlab_quality/test_tooling/test_metrics_exporter/config_helper.rb +152 -0
- data/lib/gitlab_quality/test_tooling/test_metrics_exporter/formatter.rb +3 -19
- data/lib/gitlab_quality/test_tooling/test_metrics_exporter/utils.rb +5 -16
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +23 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e1284d833aad5c38a45cff835cf3e701193117aa9694293b42fee9ce60345b0d
|
|
4
|
+
data.tar.gz: e209cf22987a7a19c58a4675ad529a6910ec387117a49fbcef97aadef9230c6f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '09ded437ab350eddf3736017e844865ef0a5ca311c6d62e800b87b272e691eab904ae12c6241f202f76ae1afa1e717880b99984e640fbd9728791e684fbfbbed'
|
|
7
|
+
data.tar.gz: a9064f95ca94ef8d8d476f097f3ee9412d71dca931a715e9f446a81f8646e75e14ab141b93fe83ebd1bf898d32503b4806179ac2f9b3233fe69c95024c693491
|
data/Gemfile.lock
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gitlab_quality-test_tooling (3.
|
|
4
|
+
gitlab_quality-test_tooling (3.13.0)
|
|
5
5
|
activesupport (>= 7.0)
|
|
6
6
|
amatch (~> 0.4.1)
|
|
7
7
|
fog-google (~> 1.24, >= 1.24.1)
|
|
8
8
|
gitlab (>= 4.19, < 7.0)
|
|
9
9
|
http (~> 5.0)
|
|
10
|
+
http-cookie (>= 1.0, < 1.1.1)
|
|
10
11
|
nokogiri (~> 1.10)
|
|
11
12
|
parallel (>= 1, < 2)
|
|
12
13
|
rainbow (>= 3, < 4)
|
|
@@ -34,6 +34,29 @@ module GitlabQuality
|
|
|
34
34
|
categories_mapping.dig(feature_category, 'group')
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def group_data_from_label(label)
|
|
38
|
+
return unless label
|
|
39
|
+
|
|
40
|
+
groups_mapping.each do |key, data|
|
|
41
|
+
next unless label.casecmp?(data['label'])
|
|
42
|
+
|
|
43
|
+
return data.merge('key' => key)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def product_managers_from_product_group(product_group)
|
|
50
|
+
group_data = groups_mapping[product_group]
|
|
51
|
+
return [] unless group_data
|
|
52
|
+
|
|
53
|
+
normalize_mentions(Array(group_data['product_managers']).compact)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def all_group_labels
|
|
57
|
+
groups_mapping.filter_map { |_key, data| data['label'] }.uniq
|
|
58
|
+
end
|
|
59
|
+
|
|
37
60
|
def engineering_managers_from_product_group(product_group, *scopes)
|
|
38
61
|
group_data = groups_mapping[product_group]
|
|
39
62
|
return [] unless group_data
|
|
@@ -42,11 +65,15 @@ module GitlabQuality
|
|
|
42
65
|
scopes = [:all] if default_scope
|
|
43
66
|
ems = resolve_ems(group_data, scopes, default_scope)
|
|
44
67
|
|
|
45
|
-
ems
|
|
68
|
+
normalize_mentions(ems)
|
|
46
69
|
end
|
|
47
70
|
|
|
48
71
|
private
|
|
49
72
|
|
|
73
|
+
def normalize_mentions(names)
|
|
74
|
+
names.uniq.sort.map { |name| name.start_with?('@') ? name : "@#{name}" }
|
|
75
|
+
end
|
|
76
|
+
|
|
50
77
|
def resolve_ems(group_data, scopes, default_scope)
|
|
51
78
|
keys = scopes.flat_map { |scope| EM_KEYS.fetch(scope) { [] } }
|
|
52
79
|
ems = group_data.values_at(*keys).flatten.compact
|
|
@@ -7,6 +7,8 @@ module GitlabQuality
|
|
|
7
7
|
SLOW_TEST_MESSAGE = '<!-- slow-test -->'
|
|
8
8
|
SLOW_TEST_LABEL = '/label ~"rspec:slow test detected"'
|
|
9
9
|
SLOW_TEST_NOTE_SOURCE_CODE = 'Generated by [`gitlab_quality-test_tooling`](https://gitlab.com/gitlab-org/ruby/gems/gitlab_quality-test_tooling/-/blob/main/lib/gitlab_quality/test_tooling/report/merge_request_slow_tests_report.rb).'
|
|
10
|
+
SLOW_TEST_UNHEALTHY_PATTERNS = 'https://docs.gitlab.com/development/testing_guide/unhealthy_tests/#common-patterns-that-cause-slow-tests'
|
|
11
|
+
SLOW_TEST_BEST_PRACTICES = 'https://docs.gitlab.com/development/testing_guide/best_practices/#test-slowness'
|
|
10
12
|
|
|
11
13
|
def initialize(token:, input_files:, merge_request_iid:, project: nil, dry_run: false, **_kwargs)
|
|
12
14
|
@token = token
|
|
@@ -70,23 +72,36 @@ module GitlabQuality
|
|
|
70
72
|
SLOW_TEST_LABEL,
|
|
71
73
|
":tools: #{SLOW_TEST_NOTE_SOURCE_CODE}\n",
|
|
72
74
|
"---\n",
|
|
73
|
-
":snail: Slow tests detected in this merge request. These slow tests might be related to this merge request's changes."
|
|
74
|
-
"<details><summary>Click to expand</summary>\n",
|
|
75
|
-
'| Job | File | Name | Duration | Expected duration |',
|
|
76
|
-
'| --- | --- | --- | --- | --- |'
|
|
75
|
+
":snail: Slow tests detected in this merge request. These slow tests might be related to this merge request's changes."
|
|
77
76
|
]
|
|
78
77
|
end
|
|
79
78
|
|
|
79
|
+
def handbook_guidance
|
|
80
|
+
":books: For guidance on improving test performance, see " \
|
|
81
|
+
"[Common Patterns That Cause Slow Tests](#{SLOW_TEST_UNHEALTHY_PATTERNS}) " \
|
|
82
|
+
"and [Best Practices – Test Slowness](#{SLOW_TEST_BEST_PRACTICES})."
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def feature_spec?(slow_test)
|
|
86
|
+
slow_test.file.include?('spec/features/')
|
|
87
|
+
end
|
|
88
|
+
|
|
80
89
|
def slow_test_rows(slow_test)
|
|
81
90
|
slow_test.map do |test|
|
|
82
91
|
slow_test_table_row(test)
|
|
83
92
|
end
|
|
84
93
|
end
|
|
85
94
|
|
|
86
|
-
def build_note(
|
|
87
|
-
rows = note_header
|
|
95
|
+
def build_note(slow_tests)
|
|
96
|
+
rows = note_header
|
|
97
|
+
rows << "\n#{handbook_guidance}" if slow_tests.any? { |t| feature_spec?(t) }
|
|
98
|
+
rows += [
|
|
99
|
+
"<details><summary>Click to expand</summary>\n",
|
|
100
|
+
'| Job | File | Name | Duration | Expected duration |',
|
|
101
|
+
'| --- | --- | --- | --- | --- |'
|
|
102
|
+
]
|
|
88
103
|
|
|
89
|
-
rows.join("\n")
|
|
104
|
+
(rows + slow_test_rows(slow_tests) + ["\n</details>"]).join("\n")
|
|
90
105
|
end
|
|
91
106
|
|
|
92
107
|
def note_comment_includes_slow_test?(gitlab_note, slow_test)
|
|
@@ -8,34 +8,6 @@ module GitlabQuality
|
|
|
8
8
|
class Config
|
|
9
9
|
include Singleton
|
|
10
10
|
|
|
11
|
-
# GCS client configuration object used to push metrics as json file to gcs bucket
|
|
12
|
-
#
|
|
13
|
-
class GCS
|
|
14
|
-
def initialize(project_id:, credentials:, bucket_name:, metrics_file_name:, dry_run: false)
|
|
15
|
-
@project_id = project_id
|
|
16
|
-
@credentials = credentials
|
|
17
|
-
@bucket_name = bucket_name
|
|
18
|
-
@metrics_file_name = metrics_file_name
|
|
19
|
-
@dry_run = dry_run
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
attr_reader :project_id, :credentials, :bucket_name, :metrics_file_name, :dry_run
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# ClickHouse client configuration object
|
|
26
|
-
#
|
|
27
|
-
class ClickHouse
|
|
28
|
-
def initialize(url:, database:, table_name:, username:, password:)
|
|
29
|
-
@url = url
|
|
30
|
-
@database = database
|
|
31
|
-
@table_name = table_name
|
|
32
|
-
@username = username
|
|
33
|
-
@password = password
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
attr_reader :url, :database, :table_name, :username, :password
|
|
37
|
-
end
|
|
38
|
-
|
|
39
11
|
class << self
|
|
40
12
|
def configuration
|
|
41
13
|
Config.instance
|
|
@@ -46,8 +18,13 @@ module GitlabQuality
|
|
|
46
18
|
end
|
|
47
19
|
end
|
|
48
20
|
|
|
49
|
-
attr_reader :
|
|
50
|
-
attr_accessor :run_type
|
|
21
|
+
attr_reader :initial_run
|
|
22
|
+
attr_accessor :run_type,
|
|
23
|
+
:clickhouse_url,
|
|
24
|
+
:clickhouse_database,
|
|
25
|
+
:clickhouse_table_name,
|
|
26
|
+
:clickhouse_username,
|
|
27
|
+
:clickhouse_password
|
|
51
28
|
attr_writer :extra_rspec_metadata_keys,
|
|
52
29
|
:skip_record_proc,
|
|
53
30
|
:test_retried_proc,
|
|
@@ -55,23 +32,7 @@ module GitlabQuality
|
|
|
55
32
|
:spec_file_path_prefix,
|
|
56
33
|
:logger
|
|
57
34
|
|
|
58
|
-
# rubocop:disable Style/TrivialAccessors -- allows
|
|
59
|
-
|
|
60
|
-
# Enable metrics export to gcs bucket by setting configuration object
|
|
61
|
-
#
|
|
62
|
-
# @param config [Config::GCS]
|
|
63
|
-
# @return [GCS]
|
|
64
|
-
def gcs_config=(config)
|
|
65
|
-
@gcs_config = config
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Enable metrics export to clickhouse by setting configuration object
|
|
69
|
-
#
|
|
70
|
-
# @param config [Config::ClickHouse]
|
|
71
|
-
# @return [ClickHouse]
|
|
72
|
-
def clickhouse_config=(config)
|
|
73
|
-
@clickhouse_config = config
|
|
74
|
-
end
|
|
35
|
+
# rubocop:disable Style/TrivialAccessors -- allows adding documentation for extra_metadata_columns
|
|
75
36
|
|
|
76
37
|
# Additional columns to be created in the table if initial_run setup is used
|
|
77
38
|
# Columns should be defined in the format used for ALTER TABLE query, example;
|
|
@@ -88,6 +49,15 @@ module GitlabQuality
|
|
|
88
49
|
|
|
89
50
|
# rubocop:enable Style/TrivialAccessors
|
|
90
51
|
|
|
52
|
+
# Whether ClickHouse export is configured
|
|
53
|
+
#
|
|
54
|
+
# Export is considered enabled when all required attributes are set
|
|
55
|
+
#
|
|
56
|
+
# @return [Boolean]
|
|
57
|
+
def clickhouse_configured?
|
|
58
|
+
[clickhouse_url, clickhouse_database, clickhouse_table_name, clickhouse_username, clickhouse_password].none?(&:blank?)
|
|
59
|
+
end
|
|
60
|
+
|
|
91
61
|
# Marks execution as initial run and performs setup tasks before running tests, like creating database in ClickHouse
|
|
92
62
|
#
|
|
93
63
|
# @return [Boolean]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
|
4
|
+
|
|
5
|
+
module GitlabQuality
|
|
6
|
+
module TestTooling
|
|
7
|
+
module TestMetricsExporter
|
|
8
|
+
class ConfigHelper
|
|
9
|
+
REQUIRED_CLICKHOUSE_ENV_VARS = %w[
|
|
10
|
+
GLCI_DA_CLICKHOUSE_URL
|
|
11
|
+
GLCI_CLICKHOUSE_METRICS_USERNAME
|
|
12
|
+
GLCI_CLICKHOUSE_METRICS_PASSWORD
|
|
13
|
+
GLCI_CLICKHOUSE_METRICS_DB
|
|
14
|
+
GLCI_CLICKHOUSE_METRICS_TABLE
|
|
15
|
+
GLCI_CLICKHOUSE_SHARED_DB
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def configure!(run_type = test_run_type)
|
|
20
|
+
return unless ENV.fetch("CI", nil) && ENV["GLCI_EXPORT_TEST_METRICS"] == "true" && run_type
|
|
21
|
+
|
|
22
|
+
RSpec.configure do |rspec_config|
|
|
23
|
+
next if rspec_config.dry_run?
|
|
24
|
+
|
|
25
|
+
Config.configure do |exporter_config|
|
|
26
|
+
self.logger = exporter_config.logger
|
|
27
|
+
next warn_missing_clickhouse_variables unless clickhouse_env_vars_present?
|
|
28
|
+
|
|
29
|
+
yield(exporter_config) if block_given?
|
|
30
|
+
configure_exporter!(exporter_config, run_type)
|
|
31
|
+
|
|
32
|
+
rspec_config.add_formatter Formatter
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
attr_writer :logger
|
|
40
|
+
|
|
41
|
+
def logger
|
|
42
|
+
@logger ||= Logger.new($stdout)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def clickhouse_env_vars_present?
|
|
46
|
+
REQUIRED_CLICKHOUSE_ENV_VARS.all? { |var| ENV.fetch(var, nil) && !ENV[var].empty? }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def owner_records
|
|
50
|
+
@owner_records ||= GitlabQuality::TestTooling::CodeCoverage::ClickHouse::CategoryOwnersTable.new(
|
|
51
|
+
database: ENV.fetch("GLCI_CLICKHOUSE_SHARED_DB", nil),
|
|
52
|
+
url: clickhouse_url,
|
|
53
|
+
username: clickhouse_username,
|
|
54
|
+
password: clickhouse_password
|
|
55
|
+
).owner_records
|
|
56
|
+
rescue StandardError => e
|
|
57
|
+
logger.error("Failed to retrieve owner data: #{e}")
|
|
58
|
+
@owner_records = {}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def configure_exporter!(config, run_type)
|
|
62
|
+
config.run_type = run_type
|
|
63
|
+
config.custom_metrics_proc = custom_metrics_proc
|
|
64
|
+
|
|
65
|
+
configure_clickhouse!(config)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def configure_clickhouse!(config)
|
|
69
|
+
config.clickhouse_database = ENV.fetch("GLCI_CLICKHOUSE_METRICS_DB", nil)
|
|
70
|
+
config.clickhouse_table_name = ENV.fetch("GLCI_CLICKHOUSE_METRICS_TABLE", nil)
|
|
71
|
+
config.clickhouse_url = clickhouse_url
|
|
72
|
+
config.clickhouse_username = clickhouse_username
|
|
73
|
+
config.clickhouse_password = clickhouse_password
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def warn_missing_clickhouse_variables
|
|
77
|
+
missing = REQUIRED_CLICKHOUSE_ENV_VARS.reject { |var| ENV.fetch(var, nil) && !ENV[var].empty? }
|
|
78
|
+
logger.warn("Test metrics export is enabled but missing environment variables: #{missing.join(', ')}")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def custom_metrics_proc
|
|
82
|
+
proc do |example|
|
|
83
|
+
feature_category = example.metadata[:feature_category]
|
|
84
|
+
|
|
85
|
+
owners = if feature_category.blank?
|
|
86
|
+
logger.warn("Example '#{example.description}' is missing feature category metadata!")
|
|
87
|
+
{}
|
|
88
|
+
elsif unowned?(feature_category)
|
|
89
|
+
# currently will default to shared or tooling
|
|
90
|
+
{ group: feature_category, stage: feature_category, section: feature_category }
|
|
91
|
+
else
|
|
92
|
+
owner_records.fetch(feature_category.to_s, {}).tap do |o|
|
|
93
|
+
logger.warn("Feature category '#{feature_category}' has no owner data") if o.empty?
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
{ pipeline_type: pipeline_type, ci_pipeline_id: ci_pipeline_id, **owners }
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def default_branch?
|
|
102
|
+
ENV["CI_COMMIT_REF_NAME"] == ENV["CI_DEFAULT_BRANCH"]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def pipeline_type
|
|
106
|
+
@pipeline_type ||= if default_branch? && ENV["SCHEDULE_TYPE"].present?
|
|
107
|
+
"default_branch_scheduled_pipeline"
|
|
108
|
+
elsif default_branch?
|
|
109
|
+
"default_branch_pipeline"
|
|
110
|
+
elsif ENV["CI_COMMIT_REF_NAME"]&.match?(/^[\d-]+-stable-ee$/)
|
|
111
|
+
"stable_branch_pipeline"
|
|
112
|
+
elsif ENV["CI_MERGE_REQUEST_TARGET_BRANCH_NAME"]&.match?(/^[\d-]+-stable-ee$/)
|
|
113
|
+
"backport_merge_request_pipeline"
|
|
114
|
+
elsif ENV["CI_MERGE_REQUEST_IID"].present?
|
|
115
|
+
"merge_request_pipeline"
|
|
116
|
+
elsif ENV["CI_PIPELINE_SOURCE"] == "pipeline"
|
|
117
|
+
"downstream_pipeline"
|
|
118
|
+
else
|
|
119
|
+
"unknown"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def unowned?(feature_category)
|
|
124
|
+
GitlabQuality::TestTooling::CodeCoverage::ClickHouse::CategoryOwnersTable::KNOWN_UNOWNED.include?(
|
|
125
|
+
feature_category.to_s
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def test_run_type
|
|
130
|
+
@run_type ||= ENV.fetch("GLCI_TEST_METRICS_RUN_TYPE", nil)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def clickhouse_url
|
|
134
|
+
ENV.fetch("GLCI_DA_CLICKHOUSE_URL", nil)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def clickhouse_username
|
|
138
|
+
ENV.fetch("GLCI_CLICKHOUSE_METRICS_USERNAME", nil)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def clickhouse_password
|
|
142
|
+
ENV.fetch("GLCI_CLICKHOUSE_METRICS_PASSWORD", nil)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def ci_pipeline_id
|
|
146
|
+
(ENV["PARENT_PIPELINE_ID"] || ENV.fetch("CI_PIPELINE_ID", nil)).to_i
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -16,7 +16,7 @@ module GitlabQuality
|
|
|
16
16
|
return unless config.initial_run
|
|
17
17
|
|
|
18
18
|
logger.info("#{LOG_PREFIX} Running initial setup for metrics export")
|
|
19
|
-
raise "Initial setup is enabled, but clickhouse configuration is missing!" unless
|
|
19
|
+
raise "Initial setup is enabled, but clickhouse configuration is missing!" unless config.clickhouse_configured?
|
|
20
20
|
|
|
21
21
|
create_clickhouse_metrics_table
|
|
22
22
|
rescue StandardError => e
|
|
@@ -32,14 +32,11 @@ module GitlabQuality
|
|
|
32
32
|
end
|
|
33
33
|
return logger.warn("#{LOG_PREFIX} No test execution records found, metrics will not be exported!") if data.empty?
|
|
34
34
|
|
|
35
|
-
push_to_gcs(data)
|
|
36
35
|
push_to_clickhouse(data)
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
private
|
|
40
39
|
|
|
41
|
-
delegate :gcs_config, :clickhouse_config, to: :config
|
|
42
|
-
|
|
43
40
|
# Single common timestamp for all exported example metrics to keep data points consistently grouped
|
|
44
41
|
#
|
|
45
42
|
# @return [String]
|
|
@@ -50,27 +47,14 @@ module GitlabQuality
|
|
|
50
47
|
@time = (ci_created_at ? Time.strptime(ci_created_at, '%Y-%m-%dT%H:%M:%S%z') : Time.now.utc).strftime('%Y-%m-%dT%H:%M:%S.%6N')
|
|
51
48
|
end
|
|
52
49
|
|
|
53
|
-
# Push data to gcs
|
|
54
|
-
#
|
|
55
|
-
# @param data [Array]
|
|
56
|
-
# @return [void]
|
|
57
|
-
def push_to_gcs(data)
|
|
58
|
-
return logger.debug("#{LOG_PREFIX} GCS configuration missing, skipping gcs export!") unless gcs_config
|
|
59
|
-
|
|
60
|
-
gcs_client.put_object(gcs_config.bucket_name, gcs_config.metrics_file_name, data.to_json)
|
|
61
|
-
logger.info("#{LOG_PREFIX} Successfully pushed #{data.size} entries to GCS bucket!")
|
|
62
|
-
rescue StandardError => e
|
|
63
|
-
logger.error("#{LOG_PREFIX} Error occurred while pushing metrics to GCS: #{e.message}")
|
|
64
|
-
end
|
|
65
|
-
|
|
66
50
|
# Push data to clickhouse
|
|
67
51
|
#
|
|
68
52
|
# @param data [Array<Hash>]
|
|
69
53
|
# @return [void]
|
|
70
54
|
def push_to_clickhouse(data)
|
|
71
|
-
return logger.debug("ClickHouse configuration missing, skipping ClickHouse export!") unless
|
|
55
|
+
return logger.debug("ClickHouse configuration missing, skipping ClickHouse export!") unless config.clickhouse_configured?
|
|
72
56
|
|
|
73
|
-
clickhouse_client.insert_json_data(
|
|
57
|
+
clickhouse_client.insert_json_data(config.clickhouse_table_name, data)
|
|
74
58
|
logger.info("#{LOG_PREFIX} Successfully pushed #{data.size} entries to ClickHouse!")
|
|
75
59
|
rescue StandardError => e
|
|
76
60
|
logger.error("#{LOG_PREFIX} Error occurred while pushing metrics to ClickHouse: #{e.message}")
|
|
@@ -23,32 +23,21 @@ module GitlabQuality
|
|
|
23
23
|
# @return [ClickHouse::Client]
|
|
24
24
|
def clickhouse_client
|
|
25
25
|
ClickHouse::Client.new(
|
|
26
|
-
url: config.
|
|
27
|
-
database: config.
|
|
28
|
-
username: config.
|
|
29
|
-
password: config.
|
|
26
|
+
url: config.clickhouse_url,
|
|
27
|
+
database: config.clickhouse_database,
|
|
28
|
+
username: config.clickhouse_username,
|
|
29
|
+
password: config.clickhouse_password,
|
|
30
30
|
logger: logger
|
|
31
31
|
)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# GCS client instance
|
|
35
|
-
#
|
|
36
|
-
# @return [Fog::Storage::Google, GcsTools::GCSMockClient]
|
|
37
|
-
def gcs_client
|
|
38
|
-
GcsTools.gcs_client(
|
|
39
|
-
project_id: config.gcs_config.project_id,
|
|
40
|
-
credentials: config.gcs_config.credentials,
|
|
41
|
-
dry_run: config.gcs_config.dry_run
|
|
42
|
-
)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
34
|
# Create table for metrics export using current ClickHouse configuration
|
|
46
35
|
#
|
|
47
36
|
# This method is mostly for schema documentation but it can be used together with initial_run! method in
|
|
48
37
|
#
|
|
49
38
|
# @return [void]
|
|
50
39
|
def create_clickhouse_metrics_table
|
|
51
|
-
table_name = config.
|
|
40
|
+
table_name = config.clickhouse_table_name
|
|
52
41
|
|
|
53
42
|
clickhouse_client.query(<<~SQL)
|
|
54
43
|
CREATE TABLE IF NOT EXISTS #{table_name}
|
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.
|
|
4
|
+
version: 3.13.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-04-
|
|
11
|
+
date: 2026-04-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: climate_control
|
|
@@ -302,6 +302,26 @@ dependencies:
|
|
|
302
302
|
- - "~>"
|
|
303
303
|
- !ruby/object:Gem::Version
|
|
304
304
|
version: '5.0'
|
|
305
|
+
- !ruby/object:Gem::Dependency
|
|
306
|
+
name: http-cookie
|
|
307
|
+
requirement: !ruby/object:Gem::Requirement
|
|
308
|
+
requirements:
|
|
309
|
+
- - ">="
|
|
310
|
+
- !ruby/object:Gem::Version
|
|
311
|
+
version: '1.0'
|
|
312
|
+
- - "<"
|
|
313
|
+
- !ruby/object:Gem::Version
|
|
314
|
+
version: 1.1.1
|
|
315
|
+
type: :runtime
|
|
316
|
+
prerelease: false
|
|
317
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
318
|
+
requirements:
|
|
319
|
+
- - ">="
|
|
320
|
+
- !ruby/object:Gem::Version
|
|
321
|
+
version: '1.0'
|
|
322
|
+
- - "<"
|
|
323
|
+
- !ruby/object:Gem::Version
|
|
324
|
+
version: 1.1.1
|
|
305
325
|
- !ruby/object:Gem::Dependency
|
|
306
326
|
name: nokogiri
|
|
307
327
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -569,6 +589,7 @@ files:
|
|
|
569
589
|
- lib/gitlab_quality/test_tooling/test_metric/json_test_metric.rb
|
|
570
590
|
- lib/gitlab_quality/test_tooling/test_metrics/json_test_metric_collection.rb
|
|
571
591
|
- lib/gitlab_quality/test_tooling/test_metrics_exporter/config.rb
|
|
592
|
+
- lib/gitlab_quality/test_tooling/test_metrics_exporter/config_helper.rb
|
|
572
593
|
- lib/gitlab_quality/test_tooling/test_metrics_exporter/formatter.rb
|
|
573
594
|
- lib/gitlab_quality/test_tooling/test_metrics_exporter/test_metrics.rb
|
|
574
595
|
- lib/gitlab_quality/test_tooling/test_metrics_exporter/utils.rb
|