gitlab_quality-test_tooling 2.10.0 → 2.18.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 +3 -3
- data/README.md +22 -5
- data/exe/{feature-readiness-check → feature-readiness-checklist} +2 -2
- data/exe/feature-readiness-evaluation +62 -0
- data/exe/relate-failure-issue +5 -0
- data/lib/gitlab_quality/test_tooling/feature_readiness/analyzed_items/analyzed_epic.rb +94 -0
- data/lib/gitlab_quality/test_tooling/feature_readiness/analyzed_items/analyzed_issue.rb +92 -0
- data/lib/gitlab_quality/test_tooling/feature_readiness/analyzed_items/analyzed_merge_request.rb +139 -0
- data/lib/gitlab_quality/test_tooling/feature_readiness/concerns/work_item_concern.rb +26 -12
- data/lib/gitlab_quality/test_tooling/feature_readiness/evaluation.rb +82 -0
- data/lib/gitlab_quality/test_tooling/feature_readiness/operational_readiness_check.rb +4 -4
- data/lib/gitlab_quality/test_tooling/gitlab_client/issues_client.rb +7 -1
- data/lib/gitlab_quality/test_tooling/gitlab_client/merge_requests_client.rb +21 -0
- data/lib/gitlab_quality/test_tooling/gitlab_client/merge_requests_dry_client.rb +0 -10
- data/lib/gitlab_quality/test_tooling/gitlab_client/work_items_client.rb +71 -34
- data/lib/gitlab_quality/test_tooling/report/concerns/results_reporter.rb +1 -1
- data/lib/gitlab_quality/test_tooling/report/concerns/utils.rb +3 -3
- data/lib/gitlab_quality/test_tooling/report/feature_readiness/report_on_epic.rb +174 -0
- data/lib/gitlab_quality/test_tooling/report/flaky_test_issue.rb +1 -1
- data/lib/gitlab_quality/test_tooling/report/generate_test_session.rb +1 -1
- data/lib/gitlab_quality/test_tooling/report/group_issues/error_message_normalizer.rb +49 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/error_pattern_matcher.rb +36 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/failure_processor.rb +73 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/group_results_in_issues.rb +48 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/incident_checker.rb +61 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/issue_base.rb +48 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/issue_creator.rb +44 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/issue_finder.rb +79 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/issue_formatter.rb +83 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/issue_manager.rb +33 -0
- data/lib/gitlab_quality/test_tooling/report/group_issues/issue_updater.rb +87 -0
- data/lib/gitlab_quality/test_tooling/report/relate_failure_issue.rb +149 -12
- data/lib/gitlab_quality/test_tooling/runtime/env.rb +1 -1
- data/lib/gitlab_quality/test_tooling/test_meta/processor/add_to_blocking_processor.rb +1 -1
- data/lib/gitlab_quality/test_tooling/test_meta/processor/add_to_quarantine_processor.rb +1 -1
- data/lib/gitlab_quality/test_tooling/test_meta/test_meta_updater.rb +38 -8
- data/lib/gitlab_quality/test_tooling/test_result/base_test_result.rb +17 -4
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- data/lib/gitlab_quality/test_tooling.rb +2 -0
- metadata +34 -10
@@ -3,6 +3,10 @@
|
|
3
3
|
require 'nokogiri'
|
4
4
|
require 'rubygems/text'
|
5
5
|
|
6
|
+
require_relative 'group_issues/error_pattern_matcher'
|
7
|
+
require_relative 'group_issues/error_message_normalizer'
|
8
|
+
require_relative 'group_issues/group_results_in_issues'
|
9
|
+
|
6
10
|
module GitlabQuality
|
7
11
|
module TestTooling
|
8
12
|
module Report
|
@@ -12,6 +16,7 @@ module GitlabQuality
|
|
12
16
|
# - Takes a project where failure issues should be created
|
13
17
|
# - Find issue by title (with test description or test file), then further filter by stack trace, then pick the better-matching one
|
14
18
|
# - Add the failed job to the issue description, and update labels
|
19
|
+
# - Can group similar failures together when group_similar option is enabled
|
15
20
|
class RelateFailureIssue < ReportAsIssue
|
16
21
|
include TestTooling::Concerns::FindSetDri
|
17
22
|
include Concerns::GroupAndCategoryLabels
|
@@ -23,16 +28,23 @@ module GitlabQuality
|
|
23
28
|
FAILURE_STACKTRACE_REGEX = %r{(?:(?:.*Failure/Error:(?<stacktrace>.+))|(?<stacktrace>.+))}m
|
24
29
|
ISSUE_STACKTRACE_REGEX = /### Stack trace\s*(```)#{FAILURE_STACKTRACE_REGEX}(```)\n*\n###/m
|
25
30
|
|
26
|
-
NEW_ISSUE_LABELS = Set.new(%w[test failure::new priority::2 automation:bot-authored]).freeze
|
31
|
+
NEW_ISSUE_LABELS = Set.new(%w[test failure::new priority::2 automation:bot-authored type::maintenance]).freeze
|
27
32
|
SCREENSHOT_IGNORED_ERRORS = ['500 Internal Server Error', 'fabricate_via_api!', 'Error Code 500'].freeze
|
28
|
-
|
33
|
+
FAILURE_ISSUE_GUIDE_URL = "https://handbook.gitlab.com/handbook/engineering/testing/guide-to-e2e-test-failure-issues/"
|
34
|
+
FAILURE_ISSUE_HANDBOOK_GUIDE = "**:rotating_light: [End-to-End Test Failure Issue Debugging Guide](#{FAILURE_ISSUE_GUIDE_URL}) :rotating_light:**\n".freeze
|
29
35
|
# Map commits to security fork (gitlab-org/security/gitlab) for gitlab-org/gitlab since security patches exist
|
30
36
|
# there before being released to the public repository
|
31
37
|
DIFF_PROJECT_MAPPINGS = {
|
38
|
+
'gitlab-org/quality/e2e-test-issues' => 'gitlab-org/security/gitlab',
|
32
39
|
'gitlab-org/gitlab' => 'gitlab-org/security/gitlab',
|
33
40
|
'gitlab-org/customers-gitlab-com' => 'gitlab-org/customers-gitlab-com'
|
34
41
|
}.freeze
|
35
42
|
|
43
|
+
# Don't use the E2E test issues project for commit parent
|
44
|
+
COMMIT_PROJECT_MAPPINGS = {
|
45
|
+
'gitlab-org/quality/e2e-test-issues' => 'gitlab-org/gitlab'
|
46
|
+
}.freeze
|
47
|
+
|
36
48
|
# The project contains record of the deployments we use to determine the commit diff
|
37
49
|
OPS_RELEASES_METADATA_PROJECT = 'gitlab-org/release/metadata'
|
38
50
|
|
@@ -56,6 +68,7 @@ module GitlabQuality
|
|
56
68
|
base_issue_labels: nil,
|
57
69
|
exclude_labels_for_search: nil,
|
58
70
|
metrics_files: [],
|
71
|
+
group_similar: false,
|
59
72
|
**kwargs)
|
60
73
|
super
|
61
74
|
@max_diff_ratio = max_diff_ratio.to_f
|
@@ -65,19 +78,106 @@ module GitlabQuality
|
|
65
78
|
@issue_type = 'issue'
|
66
79
|
@commented_issue_list = Set.new
|
67
80
|
@metrics_files = Array(metrics_files)
|
81
|
+
@group_similar = group_similar
|
68
82
|
end
|
69
83
|
|
70
84
|
private
|
71
85
|
|
72
|
-
attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search, :metrics_files, :ops_gitlab_client
|
86
|
+
attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search, :metrics_files, :ops_gitlab_client, :group_similar
|
73
87
|
|
74
88
|
def run!
|
75
89
|
puts "Reporting test failures in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
|
76
90
|
|
91
|
+
if group_similar
|
92
|
+
run_with_grouping!
|
93
|
+
else
|
94
|
+
TestResults::Builder.new(token: token, project: project, file_glob: files).test_results_per_file do |test_results|
|
95
|
+
puts "=> Reporting #{test_results.count} tests in #{test_results.path}"
|
96
|
+
process_test_results(test_results)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def grouper
|
102
|
+
@grouper ||= GitlabQuality::TestTooling::Report::GroupIssues::GroupResultsInIssues.new(
|
103
|
+
gitlab: gitlab,
|
104
|
+
config: grouper_config
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
def run_with_grouping!
|
109
|
+
Runtime::Logger.info "=> Grouping similar failures where possible"
|
110
|
+
|
111
|
+
all_test_results = collect_all_test_results
|
112
|
+
return if all_test_results.empty?
|
113
|
+
|
114
|
+
Runtime::Logger.info "=> Processing #{all_test_results.count} failures with GroupResultsInIssues"
|
115
|
+
|
116
|
+
failure_data = convert_test_results_to_failure_data(all_test_results)
|
117
|
+
|
118
|
+
grouper.process_failures(failure_data)
|
119
|
+
grouper.process_issues
|
120
|
+
end
|
121
|
+
|
122
|
+
def collect_all_test_results
|
123
|
+
all_test_results = []
|
124
|
+
|
77
125
|
TestResults::Builder.new(token: token, project: project, file_glob: files).test_results_per_file do |test_results|
|
78
|
-
|
79
|
-
|
126
|
+
Runtime::Logger.info "=> Collecting #{test_results.count} tests from #{test_results.path}"
|
127
|
+
all_test_results.concat(test_results.select(&:failures?))
|
80
128
|
end
|
129
|
+
|
130
|
+
all_test_results
|
131
|
+
end
|
132
|
+
|
133
|
+
def convert_test_results_to_failure_data(test_results)
|
134
|
+
test_results.map do |test|
|
135
|
+
{
|
136
|
+
description: test.name,
|
137
|
+
full_description: test.name,
|
138
|
+
file_path: test.relative_file,
|
139
|
+
line_number: extract_line_number(test),
|
140
|
+
exception: extract_exception_data(test),
|
141
|
+
ci_job_url: test.ci_job_url,
|
142
|
+
testcase: extract_test_id_or_name(test),
|
143
|
+
product_group: extract_product_group(test),
|
144
|
+
level: extract_level(test)
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def extract_line_number(test)
|
150
|
+
test.respond_to?(:line_number) ? test.line_number : nil
|
151
|
+
end
|
152
|
+
|
153
|
+
def extract_exception_data(test)
|
154
|
+
{
|
155
|
+
'message' => test.failures.first&.dig('message') || test.full_stacktrace || 'Unknown error'
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
def extract_product_group(test)
|
160
|
+
test.respond_to?(:product_group) ? test.product_group : nil
|
161
|
+
end
|
162
|
+
|
163
|
+
def extract_level(test)
|
164
|
+
test.respond_to?(:level) ? test.level : nil
|
165
|
+
end
|
166
|
+
|
167
|
+
def grouper_config
|
168
|
+
{
|
169
|
+
thresholds: {
|
170
|
+
min_failures_to_group: 2
|
171
|
+
}
|
172
|
+
}
|
173
|
+
end
|
174
|
+
|
175
|
+
def extract_test_id_or_name(test)
|
176
|
+
return test.example_id if test.respond_to?(:example_id)
|
177
|
+
return test.id if test.respond_to?(:id)
|
178
|
+
return test.name if test.respond_to?(:name)
|
179
|
+
|
180
|
+
"#{test.relative_file}:#{test.respond_to?(:line_number) ? test.line_number : 'unknown'}"
|
81
181
|
end
|
82
182
|
|
83
183
|
def new_issue_labels(test)
|
@@ -179,7 +279,9 @@ module GitlabQuality
|
|
179
279
|
end
|
180
280
|
|
181
281
|
created_issue = super
|
182
|
-
|
282
|
+
|
283
|
+
# On a dry run, created_issue may not be populated
|
284
|
+
test.failure_issue ||= created_issue&.web_url
|
183
285
|
|
184
286
|
created_issue
|
185
287
|
end
|
@@ -300,7 +402,7 @@ module GitlabQuality
|
|
300
402
|
end
|
301
403
|
|
302
404
|
def new_issue_description(test)
|
303
|
-
super + [
|
405
|
+
FAILURE_ISSUE_HANDBOOK_GUIDE + super + [
|
304
406
|
"\n#{commit_diff_section}",
|
305
407
|
"### Stack trace",
|
306
408
|
"```\n#{test.full_stacktrace}\n```",
|
@@ -318,10 +420,10 @@ module GitlabQuality
|
|
318
420
|
initialize_gitlab_ops_client
|
319
421
|
|
320
422
|
if Runtime::Env.ci_pipeline_url.include?('ops.gitlab.net')
|
321
|
-
pipeline = ops_gitlab_client.find_pipeline(
|
423
|
+
pipeline = ops_gitlab_client.find_pipeline(Runtime::Env.ci_project_path, Runtime::Env.ci_pipeline_id.to_i)
|
322
424
|
generate_ops_gitlab_diff(pipeline)
|
323
425
|
else
|
324
|
-
pipeline = gitlab.find_pipeline(
|
426
|
+
pipeline = gitlab.find_pipeline(Runtime::Env.ci_project_path, Runtime::Env.ci_pipeline_id.to_i)
|
325
427
|
generate_gitlab_diff(pipeline)
|
326
428
|
end
|
327
429
|
end
|
@@ -342,6 +444,8 @@ module GitlabQuality
|
|
342
444
|
end
|
343
445
|
|
344
446
|
def fetch_deployment_info(pipeline)
|
447
|
+
return 'No pipeline name set.' unless Runtime::Env.ci_pipeline_name
|
448
|
+
|
345
449
|
pipeline_deploy_version = Runtime::Env.ci_pipeline_name.match(/(\d+\.\d+\.\d+)(?:-|$)/)&.captures&.first
|
346
450
|
deployments = fetch_deployments(ops_gitlab_client, pipeline)
|
347
451
|
found_deployment = find_matching_deployment(pipeline_deploy_version, deployments)
|
@@ -427,7 +531,8 @@ module GitlabQuality
|
|
427
531
|
|
428
532
|
def generate_gitlab_diff(pipeline)
|
429
533
|
pipeline_sha = pipeline.sha
|
430
|
-
|
534
|
+
commit_project = COMMIT_PROJECT_MAPPINGS.fetch(project, project)
|
535
|
+
parent_sha = gitlab.find_commit_parent(commit_project, pipeline_sha)
|
431
536
|
diff_project = if DIFF_PROJECT_MAPPINGS.key?(project)
|
432
537
|
DIFF_PROJECT_MAPPINGS[project]
|
433
538
|
else
|
@@ -457,10 +562,40 @@ module GitlabQuality
|
|
457
562
|
end
|
458
563
|
|
459
564
|
def new_issue_assignee_id(test)
|
460
|
-
|
565
|
+
assignee_id = try_feature_category_assignment(test)
|
566
|
+
return assignee_id if assignee_id
|
567
|
+
|
568
|
+
try_product_group_assignment(test)
|
569
|
+
end
|
570
|
+
|
571
|
+
def try_feature_category_assignment(test)
|
572
|
+
unless test.respond_to?(:feature_category) && test.feature_category?
|
573
|
+
Runtime::Logger.info("No feature_category found for DRI assignment")
|
574
|
+
return
|
575
|
+
end
|
576
|
+
|
577
|
+
labels_inference = GitlabQuality::TestTooling::LabelsInference.new
|
578
|
+
product_group = labels_inference.product_group_from_feature_category(test.feature_category)
|
579
|
+
|
580
|
+
unless product_group
|
581
|
+
Runtime::Logger.warn("Could not map feature_category '#{test.feature_category}' to product_group")
|
582
|
+
return
|
583
|
+
end
|
584
|
+
|
585
|
+
dri = test_dri(product_group, test.stage, test.section)
|
586
|
+
Runtime::Logger.info("Assigning #{dri} as DRI for the issue (via feature_category).")
|
587
|
+
|
588
|
+
gitlab.find_user_id(username: dri)
|
589
|
+
end
|
590
|
+
|
591
|
+
def try_product_group_assignment(test)
|
592
|
+
unless test.respond_to?(:product_group) && test.product_group?
|
593
|
+
Runtime::Logger.info("No product_group found for DRI assignment")
|
594
|
+
return
|
595
|
+
end
|
461
596
|
|
462
597
|
dri = test_dri(test.product_group, test.stage, test.section)
|
463
|
-
|
598
|
+
Runtime::Logger.info("Assigning #{dri} as DRI for the issue (via product_group).")
|
464
599
|
|
465
600
|
gitlab.find_user_id(username: dri)
|
466
601
|
end
|
@@ -542,6 +677,8 @@ module GitlabQuality
|
|
542
677
|
end
|
543
678
|
|
544
679
|
def screenshot_artifact_url(test)
|
680
|
+
return "" unless test.screenshot_image
|
681
|
+
|
545
682
|
ci_job_url = test.ci_job_url
|
546
683
|
screenshot_path = test.screenshot_image[%r{qa/.*$}]
|
547
684
|
|
@@ -97,7 +97,7 @@ module GitlabQuality
|
|
97
97
|
|
98
98
|
This MR was created based on data from reliable e2e test report: #{context.report_issue}
|
99
99
|
|
100
|
-
/label ~"
|
100
|
+
/label ~"E2E" ~"type::maintenance"
|
101
101
|
/label ~"devops::#{devops_stage}"
|
102
102
|
#{context.label_from_product_group(product_group)}
|
103
103
|
|
@@ -137,7 +137,7 @@ module GitlabQuality
|
|
137
137
|
- [ ] To ensure a faster turnaround, ask in the `#quality_maintainers` Slack channel for someone to review and merge the merge request, rather than assigning it directly.
|
138
138
|
|
139
139
|
<!-- Base labels. -->
|
140
|
-
/label ~"
|
140
|
+
/label ~"E2E" ~"type::maintenance" ~"maintenance::pipelines"
|
141
141
|
|
142
142
|
<!--
|
143
143
|
Choose the stage that appears in the test path, e.g. ~"devops::create" for
|
@@ -8,7 +8,7 @@ module GitlabQuality
|
|
8
8
|
class TestMetaUpdater
|
9
9
|
include TestTooling::Concerns::FindSetDri
|
10
10
|
|
11
|
-
attr_reader :project, :ref, :report_issue, :processed_commits
|
11
|
+
attr_reader :project, :ref, :report_issue, :processed_commits, :token, :specs_file, :dry_run, :processor
|
12
12
|
|
13
13
|
TEST_PLATFORM_MAINTAINERS_SLACK_CHANNEL_ID = 'C0437FV9KBN' # test-platform-maintainers
|
14
14
|
|
@@ -269,12 +269,15 @@ module GitlabQuality
|
|
269
269
|
# Fetch the id for the dri of the product group and stage
|
270
270
|
# The first item returned is the id of the assignee and the second item is the handle
|
271
271
|
#
|
272
|
-
# @param [
|
272
|
+
# @param [Hash] test object
|
273
273
|
# @param [String] devops_stage
|
274
|
+
# @param [String] section
|
274
275
|
# @return [Array<Integer, String>]
|
275
|
-
def fetch_dri_id(
|
276
|
-
|
276
|
+
def fetch_dri_id(test, devops_stage, section)
|
277
|
+
product_group = determine_product_group(test)
|
278
|
+
return unless product_group
|
277
279
|
|
280
|
+
assignee_handle = ENV.fetch('QA_TEST_DRI_HANDLE', nil) || test_dri(product_group, devops_stage, section)
|
278
281
|
[user_id_for_username(assignee_handle), assignee_handle]
|
279
282
|
end
|
280
283
|
|
@@ -335,6 +338,16 @@ module GitlabQuality
|
|
335
338
|
label ? %(/label ~"#{label}") : ''
|
336
339
|
end
|
337
340
|
|
341
|
+
# Infers the group label from the provided feature category
|
342
|
+
#
|
343
|
+
# @param [String] feature_category feature category
|
344
|
+
# @return [String]
|
345
|
+
def label_from_feature_category(feature_category)
|
346
|
+
labels = labels_inference.infer_labels_from_feature_category(feature_category)
|
347
|
+
group_label = labels.find { |label| label.start_with?('group::') }
|
348
|
+
group_label ? %(/label ~"#{group_label}") : ''
|
349
|
+
end
|
350
|
+
|
338
351
|
# Returns the link to the Grafana dashboard for single spec metrics
|
339
352
|
#
|
340
353
|
# @param [String] example_name the full example name
|
@@ -344,10 +357,6 @@ module GitlabQuality
|
|
344
357
|
base_url + CGI.escape(example_name)
|
345
358
|
end
|
346
359
|
|
347
|
-
private
|
348
|
-
|
349
|
-
attr_reader :token, :specs_file, :dry_run, :processor
|
350
|
-
|
351
360
|
# Returns any test description string within single or double quotes
|
352
361
|
#
|
353
362
|
# @param [String] line the line to check for any quoted string
|
@@ -380,6 +389,27 @@ module GitlabQuality
|
|
380
389
|
def labels_inference
|
381
390
|
@labels_inference ||= GitlabQuality::TestTooling::LabelsInference.new
|
382
391
|
end
|
392
|
+
|
393
|
+
private
|
394
|
+
|
395
|
+
def determine_product_group(test)
|
396
|
+
return map_feature_category_to_product_group(test) if has_feature_category?(test)
|
397
|
+
return test.product_group if has_product_group?(test)
|
398
|
+
|
399
|
+
nil
|
400
|
+
end
|
401
|
+
|
402
|
+
def has_feature_category?(test)
|
403
|
+
test.respond_to?(:feature_category) && test.feature_category?
|
404
|
+
end
|
405
|
+
|
406
|
+
def has_product_group?(test)
|
407
|
+
test.respond_to?(:product_group) && test.product_group?
|
408
|
+
end
|
409
|
+
|
410
|
+
def map_feature_category_to_product_group(test)
|
411
|
+
labels_inference.product_group_from_feature_category(test.feature_category)
|
412
|
+
end
|
383
413
|
end
|
384
414
|
end
|
385
415
|
end
|
@@ -14,7 +14,8 @@ module GitlabQuality
|
|
14
14
|
"Error reference number: 502",
|
15
15
|
"(502): `GitLab is not responding`",
|
16
16
|
"<head><title>502 Bad Gateway</title></head>",
|
17
|
-
"14:connections to all backends failing"
|
17
|
+
"14:connections to all backends failing",
|
18
|
+
"gitlab_canary=true cookie was set in browser but 'Next' badge was not shown on UI"
|
18
19
|
].freeze
|
19
20
|
|
20
21
|
SHARED_EXAMPLES_CALLERS = %w[include_examples it_behaves_like].freeze
|
@@ -72,6 +73,10 @@ module GitlabQuality
|
|
72
73
|
product_group != ''
|
73
74
|
end
|
74
75
|
|
76
|
+
def feature_category?
|
77
|
+
feature_category && !feature_category.empty?
|
78
|
+
end
|
79
|
+
|
75
80
|
def failure_issue
|
76
81
|
report['failure_issue']
|
77
82
|
end
|
@@ -114,7 +119,7 @@ module GitlabQuality
|
|
114
119
|
end
|
115
120
|
|
116
121
|
def file_base_url
|
117
|
-
@file_base_url ||= "https://gitlab.com/#{project}/-/blob/#{ref}/"
|
122
|
+
@file_base_url ||= "https://gitlab.com/#{project == 'gitlab-org/quality/e2e-test-issues' ? 'gitlab-org/gitlab' : project}/-/blob/#{ref}/"
|
118
123
|
end
|
119
124
|
|
120
125
|
def test_file_link
|
@@ -143,15 +148,23 @@ module GitlabQuality
|
|
143
148
|
def files_client
|
144
149
|
@files_client ||= GitlabClient::RepositoryFilesClient.new(
|
145
150
|
token: token,
|
146
|
-
project:
|
151
|
+
project: mapped_project,
|
147
152
|
file_path: file,
|
148
|
-
ref: ref)
|
153
|
+
ref: ref.nil? || ref.empty? ? 'master' : ref)
|
149
154
|
end
|
150
155
|
|
151
156
|
private
|
152
157
|
|
153
158
|
attr_reader :token, :project, :ref
|
154
159
|
|
160
|
+
def mapped_project
|
161
|
+
if project == 'gitlab-org/quality/e2e-test-issues'
|
162
|
+
'gitlab-org/gitlab'
|
163
|
+
else
|
164
|
+
project
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
155
168
|
def screenshot
|
156
169
|
report.fetch('screenshot', nil)
|
157
170
|
end
|
@@ -7,6 +7,8 @@ module GitlabQuality
|
|
7
7
|
module TestTooling
|
8
8
|
Error = Class.new(StandardError)
|
9
9
|
loader = Zeitwerk::Loader.new
|
10
|
+
loader.push_dir(__dir__.to_s, namespace: GitlabQuality)
|
11
|
+
loader.ignore("#{__dir__}/test_tooling.rb")
|
10
12
|
loader.push_dir("#{__dir__}/test_tooling", namespace: GitlabQuality::TestTooling)
|
11
13
|
loader.ignore("#{__dir__}/test_tooling/version.rb")
|
12
14
|
|
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.
|
4
|
+
version: 2.18.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
|
+
date: 2025-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: climate_control
|
@@ -263,7 +263,7 @@ dependencies:
|
|
263
263
|
version: '4.19'
|
264
264
|
- - "<"
|
265
265
|
- !ruby/object:Gem::Version
|
266
|
-
version: '
|
266
|
+
version: '7.0'
|
267
267
|
type: :runtime
|
268
268
|
prerelease: false
|
269
269
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -273,7 +273,7 @@ dependencies:
|
|
273
273
|
version: '4.19'
|
274
274
|
- - "<"
|
275
275
|
- !ruby/object:Gem::Version
|
276
|
-
version: '
|
276
|
+
version: '7.0'
|
277
277
|
- !ruby/object:Gem::Dependency
|
278
278
|
name: http
|
279
279
|
requirement: !ruby/object:Gem::Requirement
|
@@ -380,16 +380,22 @@ dependencies:
|
|
380
380
|
name: rspec-parameterized
|
381
381
|
requirement: !ruby/object:Gem::Requirement
|
382
382
|
requirements:
|
383
|
-
- - "
|
383
|
+
- - ">="
|
384
|
+
- !ruby/object:Gem::Version
|
385
|
+
version: '1.0'
|
386
|
+
- - "<"
|
384
387
|
- !ruby/object:Gem::Version
|
385
|
-
version:
|
388
|
+
version: '3.0'
|
386
389
|
type: :runtime
|
387
390
|
prerelease: false
|
388
391
|
version_requirements: !ruby/object:Gem::Requirement
|
389
392
|
requirements:
|
390
|
-
- - "
|
393
|
+
- - ">="
|
394
|
+
- !ruby/object:Gem::Version
|
395
|
+
version: '1.0'
|
396
|
+
- - "<"
|
391
397
|
- !ruby/object:Gem::Version
|
392
|
-
version:
|
398
|
+
version: '3.0'
|
393
399
|
- !ruby/object:Gem::Dependency
|
394
400
|
name: table_print
|
395
401
|
requirement: !ruby/object:Gem::Requirement
|
@@ -431,7 +437,8 @@ executables:
|
|
431
437
|
- detect-infrastructure-failures
|
432
438
|
- existing-test-health-issue
|
433
439
|
- failed-test-issues
|
434
|
-
- feature-readiness-
|
440
|
+
- feature-readiness-checklist
|
441
|
+
- feature-readiness-evaluation
|
435
442
|
- flaky-test-issues
|
436
443
|
- generate-test-session
|
437
444
|
- knapsack-report-issues
|
@@ -463,7 +470,8 @@ files:
|
|
463
470
|
- exe/detect-infrastructure-failures
|
464
471
|
- exe/existing-test-health-issue
|
465
472
|
- exe/failed-test-issues
|
466
|
-
- exe/feature-readiness-
|
473
|
+
- exe/feature-readiness-checklist
|
474
|
+
- exe/feature-readiness-evaluation
|
467
475
|
- exe/flaky-test-issues
|
468
476
|
- exe/generate-test-session
|
469
477
|
- exe/knapsack-report-issues
|
@@ -479,8 +487,12 @@ files:
|
|
479
487
|
- lib/gitlab_quality/test_tooling.rb
|
480
488
|
- lib/gitlab_quality/test_tooling/concerns/find_set_dri.rb
|
481
489
|
- lib/gitlab_quality/test_tooling/failed_jobs_table.rb
|
490
|
+
- lib/gitlab_quality/test_tooling/feature_readiness/analyzed_items/analyzed_epic.rb
|
491
|
+
- lib/gitlab_quality/test_tooling/feature_readiness/analyzed_items/analyzed_issue.rb
|
492
|
+
- lib/gitlab_quality/test_tooling/feature_readiness/analyzed_items/analyzed_merge_request.rb
|
482
493
|
- lib/gitlab_quality/test_tooling/feature_readiness/concerns/issue_concern.rb
|
483
494
|
- lib/gitlab_quality/test_tooling/feature_readiness/concerns/work_item_concern.rb
|
495
|
+
- lib/gitlab_quality/test_tooling/feature_readiness/evaluation.rb
|
484
496
|
- lib/gitlab_quality/test_tooling/feature_readiness/operational_readiness_check.rb
|
485
497
|
- lib/gitlab_quality/test_tooling/gitlab_client/branches_client.rb
|
486
498
|
- lib/gitlab_quality/test_tooling/gitlab_client/branches_dry_client.rb
|
@@ -507,8 +519,20 @@ files:
|
|
507
519
|
- lib/gitlab_quality/test_tooling/report/concerns/results_reporter.rb
|
508
520
|
- lib/gitlab_quality/test_tooling/report/concerns/utils.rb
|
509
521
|
- lib/gitlab_quality/test_tooling/report/failed_test_issue.rb
|
522
|
+
- lib/gitlab_quality/test_tooling/report/feature_readiness/report_on_epic.rb
|
510
523
|
- lib/gitlab_quality/test_tooling/report/flaky_test_issue.rb
|
511
524
|
- lib/gitlab_quality/test_tooling/report/generate_test_session.rb
|
525
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/error_message_normalizer.rb
|
526
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/error_pattern_matcher.rb
|
527
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/failure_processor.rb
|
528
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/group_results_in_issues.rb
|
529
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/incident_checker.rb
|
530
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/issue_base.rb
|
531
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/issue_creator.rb
|
532
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/issue_finder.rb
|
533
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/issue_formatter.rb
|
534
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/issue_manager.rb
|
535
|
+
- lib/gitlab_quality/test_tooling/report/group_issues/issue_updater.rb
|
512
536
|
- lib/gitlab_quality/test_tooling/report/health_problem_reporter.rb
|
513
537
|
- lib/gitlab_quality/test_tooling/report/issue_logger.rb
|
514
538
|
- lib/gitlab_quality/test_tooling/report/knapsack_report_issue.rb
|