gitlab-qa 10.0.0 → 10.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/gitlab/qa/report/relate_failure_issue.rb +21 -3
- data/lib/gitlab/qa/report/test_result.rb +2 -1
- data/lib/gitlab/qa/reporter.rb +8 -0
- data/lib/gitlab/qa/system_logs/finders/json_log_finder.rb +65 -0
- data/lib/gitlab/qa/system_logs/finders/rails/api_log_finder.rb +21 -0
- data/lib/gitlab/qa/system_logs/finders/rails/application_log_finder.rb +21 -0
- data/lib/gitlab/qa/system_logs/finders/rails/exception_log_finder.rb +21 -0
- data/lib/gitlab/qa/system_logs/finders/rails/graphql_log_finder.rb +21 -0
- data/lib/gitlab/qa/system_logs/log_types/log.rb +38 -0
- data/lib/gitlab/qa/system_logs/log_types/rails/api_log.rb +34 -0
- data/lib/gitlab/qa/system_logs/log_types/rails/application_log.rb +27 -0
- data/lib/gitlab/qa/system_logs/log_types/rails/exception_log.rb +23 -0
- data/lib/gitlab/qa/system_logs/log_types/rails/graphql_log.rb +30 -0
- data/lib/gitlab/qa/system_logs/shared_fields.rb +29 -0
- data/lib/gitlab/qa/system_logs/system_logs_formatter.rb +65 -0
- data/lib/gitlab/qa/version.rb +1 -1
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3d71c9b26ee6da1b637bd155fc3dca98e47f739435802737110b8c76273068f
|
4
|
+
data.tar.gz: 4ede3accf59fadf7ba32c05cb49e0ba53eb3e9c809aa4c0978edb650e04ae529
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70441f243143e6d241f91729d1f35ba1d1668438bbd61bfe534e616e501c989af6382606986fdf593043d2a70a7e7dd59c9d7af5ccf52f93245b29a32dcf2bb7
|
7
|
+
data.tar.gz: 00ecb2e2599f15295e57bfda8313b9312e780693ddc9015b344a21f25d7b0ece878789e9ee6772825617abe8ae7d262429082fe7884cc4c8e8f07ff99a5a6018
|
data/Gemfile.lock
CHANGED
@@ -23,8 +23,9 @@ module Gitlab
|
|
23
23
|
|
24
24
|
MultipleIssuesFound = Class.new(StandardError)
|
25
25
|
|
26
|
-
def initialize(max_diff_ratio: DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION, **kwargs)
|
26
|
+
def initialize(system_logs: [], max_diff_ratio: DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION, **kwargs)
|
27
27
|
super
|
28
|
+
@system_logs = Dir.glob(system_logs)
|
28
29
|
@max_diff_ratio = max_diff_ratio.to_f
|
29
30
|
@issue_type = 'issue'
|
30
31
|
@commented_issue_list = Set.new
|
@@ -217,7 +218,7 @@ module Gitlab
|
|
217
218
|
stacktrace_match = stacktrace.match(regex)
|
218
219
|
|
219
220
|
if stacktrace_match
|
220
|
-
stacktrace_match[:stacktrace].gsub(/^\s*#.*$/, '').gsub(/^[[:space:]]+/, '').strip
|
221
|
+
stacktrace_match[:stacktrace].split('First happened in')[0].gsub(/^\s*#.*$/, '').gsub(/^[[:space:]]+/, '').strip
|
221
222
|
else
|
222
223
|
puts " => [DEBUG] Stacktrace doesn't match the expected regex (#{regex}):\n----------------\n#{stacktrace}\n----------------\n"
|
223
224
|
end
|
@@ -252,10 +253,27 @@ module Gitlab
|
|
252
253
|
"```\n#{full_stacktrace(test)}\n```",
|
253
254
|
"First happened in #{test.ci_job_url}.",
|
254
255
|
"Related test case: #{test.testcase}.",
|
255
|
-
screenshot_section(test)
|
256
|
+
screenshot_section(test),
|
257
|
+
system_log_errors_section(test)
|
256
258
|
].join("\n\n")
|
257
259
|
end
|
258
260
|
|
261
|
+
def system_log_errors_section(test)
|
262
|
+
correlation_id = test.failures.first['correlation_id']
|
263
|
+
section = ''
|
264
|
+
|
265
|
+
if @system_logs.any? && !correlation_id.nil?
|
266
|
+
section = SystemLogs::SystemLogsFormatter.new(
|
267
|
+
@system_logs,
|
268
|
+
correlation_id
|
269
|
+
).system_logs_summary_markdown
|
270
|
+
end
|
271
|
+
|
272
|
+
puts " => No system logs or correlation id provided, skipping this section in issue description" if section.empty?
|
273
|
+
|
274
|
+
section
|
275
|
+
end
|
276
|
+
|
259
277
|
def new_issue_labels(test)
|
260
278
|
up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS)
|
261
279
|
end
|
@@ -128,7 +128,8 @@ module Gitlab
|
|
128
128
|
{
|
129
129
|
'message' => "#{exception['class']}: #{exception['message']}",
|
130
130
|
'message_lines' => exception['message_lines'],
|
131
|
-
'stacktrace' => "#{format_message_lines(exception['message_lines'])}\n#{exception['backtrace'].slice(0..spec_file_first_index).join("\n")}"
|
131
|
+
'stacktrace' => "#{format_message_lines(exception['message_lines'])}\n#{exception['backtrace'].slice(0..spec_file_first_index).join("\n")}",
|
132
|
+
'correlation_id' => exception['correlation_id']
|
132
133
|
}
|
133
134
|
end
|
134
135
|
end
|
data/lib/gitlab/qa/reporter.rb
CHANGED
@@ -7,6 +7,7 @@ module Gitlab
|
|
7
7
|
class Reporter
|
8
8
|
# rubocop:disable Metrics/AbcSize
|
9
9
|
# rubocop:disable Metrics/PerceivedComplexity
|
10
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
10
11
|
def self.invoke(args)
|
11
12
|
report_options = {}
|
12
13
|
slack_options = {}
|
@@ -65,6 +66,12 @@ module Gitlab
|
|
65
66
|
slack_options[:message] = slack_options[:message] + "\n\n" + Gitlab::QA::Report::SummaryTable.create(input_files: files)
|
66
67
|
end
|
67
68
|
|
69
|
+
opts.on('--include-system-log-errors FILES', String, 'Include errors from system logs in failure issues. To be used with --relate-failure-issue') do |files|
|
70
|
+
raise 'This option should be used with --relate-failure-issue.' unless report_options[:relate_failure_issue]
|
71
|
+
|
72
|
+
report_options[:system_logs] = files if files
|
73
|
+
end
|
74
|
+
|
68
75
|
opts.on('--update-screenshot-path FILES', "Update the path to screenshots to container's host") do |files|
|
69
76
|
report_options[:update_screenshot_path] = true
|
70
77
|
report_options[:files] = files
|
@@ -116,6 +123,7 @@ module Gitlab
|
|
116
123
|
exit 1
|
117
124
|
end
|
118
125
|
end
|
126
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
119
127
|
# rubocop:enable Metrics/PerceivedComplexity
|
120
128
|
# rubocop:enable Metrics/AbcSize
|
121
129
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Gitlab
|
6
|
+
module QA
|
7
|
+
module SystemLogs
|
8
|
+
module Finders
|
9
|
+
class JsonLogFinder
|
10
|
+
def initialize(base_path, file_path)
|
11
|
+
@base_path = base_path
|
12
|
+
@file_path = file_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def find(correlation_id)
|
16
|
+
log_file_path = "#{@base_path}/#{@file_path}"
|
17
|
+
logs = []
|
18
|
+
|
19
|
+
if File.exist?(log_file_path) && !correlation_id.nil?
|
20
|
+
File.foreach(log_file_path) do |line|
|
21
|
+
begin
|
22
|
+
json_line = JSON.parse(line, symbolize_names: true)
|
23
|
+
rescue JSON::ParserError
|
24
|
+
Runtime::Logger.debug("JsonLogFinder#find attempted to parse invalid JSON: #{line}")
|
25
|
+
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
if (json_line[:correlation_id])&.casecmp?(correlation_id)
|
30
|
+
normalized_line = normalize_keys(json_line)
|
31
|
+
logs << new_log(normalized_line)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
logs
|
37
|
+
end
|
38
|
+
|
39
|
+
def new_log(data)
|
40
|
+
raise 'abstract method new_log must be defined!'
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def normalize_keys(json_line)
|
46
|
+
normalized_hash = {}
|
47
|
+
|
48
|
+
json_line.each_key do |old_key|
|
49
|
+
key_string = old_key.to_s
|
50
|
+
|
51
|
+
if key_string.include?('.')
|
52
|
+
normalized_key = key_string.tr('.', '_').to_sym
|
53
|
+
normalized_hash[normalized_key] = json_line[old_key]
|
54
|
+
else
|
55
|
+
normalized_hash[old_key] = json_line[old_key]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
normalized_hash
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module Finders
|
7
|
+
module Rails
|
8
|
+
class ApiLogFinder < JsonLogFinder
|
9
|
+
def initialize(base_path, file_path = 'gitlab-rails/api_json.log')
|
10
|
+
super(base_path, file_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_log(data)
|
14
|
+
LogTypes::Rails::ApiLog.new(data)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module Finders
|
7
|
+
module Rails
|
8
|
+
class ApplicationLogFinder < JsonLogFinder
|
9
|
+
def initialize(base_path, file_path = 'gitlab-rails/application_json.log')
|
10
|
+
super(base_path, file_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_log(data)
|
14
|
+
LogTypes::Rails::ApplicationLog.new(data)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module Finders
|
7
|
+
module Rails
|
8
|
+
class ExceptionLogFinder < JsonLogFinder
|
9
|
+
def initialize(base_path, file_path = 'gitlab-rails/exceptions_json.log')
|
10
|
+
super(base_path, file_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_log(data)
|
14
|
+
LogTypes::Rails::ExceptionLog.new(data)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module Finders
|
7
|
+
module Rails
|
8
|
+
class GraphqlLogFinder < JsonLogFinder
|
9
|
+
def initialize(base_path, file_path = 'gitlab-rails/graphql_json.log')
|
10
|
+
super(base_path, file_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_log(data)
|
14
|
+
LogTypes::Rails::GraphqlLog.new(data)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module LogTypes
|
7
|
+
class Log
|
8
|
+
def initialize(name, data)
|
9
|
+
@name = name
|
10
|
+
@data = data
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :name, :data
|
14
|
+
|
15
|
+
def summary_fields
|
16
|
+
[
|
17
|
+
:severity,
|
18
|
+
:correlation_id,
|
19
|
+
:time,
|
20
|
+
:message
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
def summary
|
25
|
+
summary = {}
|
26
|
+
|
27
|
+
summary_fields.each do |field|
|
28
|
+
value = data[field]
|
29
|
+
summary[field] = value unless value.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
summary
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module LogTypes
|
7
|
+
module Rails
|
8
|
+
class ApiLog < Log
|
9
|
+
include SharedFields::Exception
|
10
|
+
include SharedFields::Meta
|
11
|
+
|
12
|
+
def initialize(data)
|
13
|
+
super('Rails API', data)
|
14
|
+
end
|
15
|
+
|
16
|
+
def summary_fields
|
17
|
+
super.concat(
|
18
|
+
[
|
19
|
+
:method,
|
20
|
+
:path,
|
21
|
+
:status,
|
22
|
+
:params,
|
23
|
+
:api_error
|
24
|
+
],
|
25
|
+
exception_fields,
|
26
|
+
meta_fields
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module LogTypes
|
7
|
+
module Rails
|
8
|
+
class ApplicationLog < Log
|
9
|
+
include SharedFields::Exception
|
10
|
+
include SharedFields::Meta
|
11
|
+
|
12
|
+
def initialize(data)
|
13
|
+
super('Rails Application', data)
|
14
|
+
end
|
15
|
+
|
16
|
+
def summary_fields
|
17
|
+
super.concat(
|
18
|
+
exception_fields,
|
19
|
+
meta_fields
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module LogTypes
|
7
|
+
module Rails
|
8
|
+
class ExceptionLog < Log
|
9
|
+
include SharedFields::Exception
|
10
|
+
|
11
|
+
def initialize(data)
|
12
|
+
super('Rails Exceptions', data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def summary_fields
|
16
|
+
super.concat(exception_fields)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module LogTypes
|
7
|
+
module Rails
|
8
|
+
class GraphqlLog < Log
|
9
|
+
include SharedFields::Meta
|
10
|
+
|
11
|
+
def initialize(data)
|
12
|
+
super('Rails GraphQL', data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def summary_fields
|
16
|
+
super.concat(
|
17
|
+
[
|
18
|
+
:operation_name,
|
19
|
+
:query_string,
|
20
|
+
:variables
|
21
|
+
],
|
22
|
+
meta_fields
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
module SharedFields
|
7
|
+
module Meta
|
8
|
+
def meta_fields
|
9
|
+
[
|
10
|
+
:meta_user,
|
11
|
+
:meta_project,
|
12
|
+
:meta_caller_id
|
13
|
+
]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Exception
|
18
|
+
def exception_fields
|
19
|
+
[
|
20
|
+
:exception_class,
|
21
|
+
:exception_message,
|
22
|
+
:exception_backtrace
|
23
|
+
]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module SystemLogs
|
6
|
+
class SystemLogsFormatter
|
7
|
+
NUM_OF_LOG_SECTIONS = 4
|
8
|
+
|
9
|
+
def initialize(base_paths, correlation_id)
|
10
|
+
@base_paths = base_paths
|
11
|
+
@correlation_id = correlation_id
|
12
|
+
end
|
13
|
+
|
14
|
+
def system_logs_summary_markdown
|
15
|
+
log_sections = Array.new(NUM_OF_LOG_SECTIONS) { [] }
|
16
|
+
|
17
|
+
@base_paths.each do |base_path|
|
18
|
+
all_logs = [
|
19
|
+
Finders::Rails::ApiLogFinder.new(base_path).find(@correlation_id),
|
20
|
+
Finders::Rails::ExceptionLogFinder.new(base_path).find(@correlation_id),
|
21
|
+
Finders::Rails::ApplicationLogFinder.new(base_path).find(@correlation_id),
|
22
|
+
Finders::Rails::GraphqlLogFinder.new(base_path).find(@correlation_id)
|
23
|
+
]
|
24
|
+
|
25
|
+
create_log_summary_sections!(all_logs, log_sections)
|
26
|
+
end
|
27
|
+
|
28
|
+
log_sections.prepend('### System Logs') unless log_sections.all?(&:empty?)
|
29
|
+
log_sections.join("\n").rstrip
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def create_log_summary_sections!(all_logs, sections)
|
35
|
+
sections.zip(all_logs) do |section, logs|
|
36
|
+
unless logs.empty?
|
37
|
+
section_title = "\n#### #{logs.first.name}"
|
38
|
+
section.append(section_title) unless section.include?(section_title)
|
39
|
+
section.append(create_log_summaries(logs))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_log_summaries(logs)
|
45
|
+
section = []
|
46
|
+
|
47
|
+
logs.each do |log|
|
48
|
+
log_summary = <<~MARKDOWN.chomp
|
49
|
+
<details><summary>Click to expand</summary>
|
50
|
+
|
51
|
+
```json
|
52
|
+
#{JSON.pretty_generate(log.summary)}
|
53
|
+
```
|
54
|
+
</details>
|
55
|
+
MARKDOWN
|
56
|
+
|
57
|
+
section.append(log_summary)
|
58
|
+
end
|
59
|
+
|
60
|
+
section.join("\n\n")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/gitlab/qa/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitlab-qa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.
|
4
|
+
version: 10.1.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: 2023-04-
|
11
|
+
date: 2023-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: climate_control
|
@@ -485,6 +485,18 @@ files:
|
|
485
485
|
- lib/gitlab/qa/support/invalid_response_error.rb
|
486
486
|
- lib/gitlab/qa/support/shell_command.rb
|
487
487
|
- lib/gitlab/qa/support/shellout.rb
|
488
|
+
- lib/gitlab/qa/system_logs/finders/json_log_finder.rb
|
489
|
+
- lib/gitlab/qa/system_logs/finders/rails/api_log_finder.rb
|
490
|
+
- lib/gitlab/qa/system_logs/finders/rails/application_log_finder.rb
|
491
|
+
- lib/gitlab/qa/system_logs/finders/rails/exception_log_finder.rb
|
492
|
+
- lib/gitlab/qa/system_logs/finders/rails/graphql_log_finder.rb
|
493
|
+
- lib/gitlab/qa/system_logs/log_types/log.rb
|
494
|
+
- lib/gitlab/qa/system_logs/log_types/rails/api_log.rb
|
495
|
+
- lib/gitlab/qa/system_logs/log_types/rails/application_log.rb
|
496
|
+
- lib/gitlab/qa/system_logs/log_types/rails/exception_log.rb
|
497
|
+
- lib/gitlab/qa/system_logs/log_types/rails/graphql_log.rb
|
498
|
+
- lib/gitlab/qa/system_logs/shared_fields.rb
|
499
|
+
- lib/gitlab/qa/system_logs/system_logs_formatter.rb
|
488
500
|
- lib/gitlab/qa/test_logger.rb
|
489
501
|
- lib/gitlab/qa/version.rb
|
490
502
|
- scripts/build-package-and-test-env
|