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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14c426ca85861845164d12c2bfe65ba51aeb3791d383920ce872b9066f7d50ca
4
- data.tar.gz: 33e80bd2dd23bc1949018fe46f70bb892fecf0a9789f0365e0ccef6c01334267
3
+ metadata.gz: d3d71c9b26ee6da1b637bd155fc3dca98e47f739435802737110b8c76273068f
4
+ data.tar.gz: 4ede3accf59fadf7ba32c05cb49e0ba53eb3e9c809aa4c0978edb650e04ae529
5
5
  SHA512:
6
- metadata.gz: 560b02f9b0a4321cb1b7be3c1e482f73a306b4c171bcc0bff4c6527fdd9fdabd68fb33ee042a4033cd047f3a23e8e5d84ae8017936ed6885cfd1de0c0c3eb646
7
- data.tar.gz: 149bfc867c9913c3af4865964e12ba21d96509eaf0d4c1feb2bcf8c19c3d7da1933a68fa790bb41724ae824f4090f818d4240d5562a532e1fd2461a50138d21c
6
+ metadata.gz: 70441f243143e6d241f91729d1f35ba1d1668438bbd61bfe534e616e501c989af6382606986fdf593043d2a70a7e7dd59c9d7af5ccf52f93245b29a32dcf2bb7
7
+ data.tar.gz: 00ecb2e2599f15295e57bfda8313b9312e780693ddc9015b344a21f25d7b0ece878789e9ee6772825617abe8ae7d262429082fe7884cc4c8e8f07ff99a5a6018
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-qa (10.0.0)
4
+ gitlab-qa (10.1.0)
5
5
  activesupport (~> 6.1)
6
6
  gitlab (~> 4.18.0)
7
7
  http (~> 5.0)
@@ -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
@@ -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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module QA
5
- VERSION = '10.0.0'
5
+ VERSION = '10.1.0'
6
6
  end
7
7
  end
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.0.0
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-07 00:00:00.000000000 Z
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