gitlab_quality-test_tooling 1.7.0 → 1.8.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6924fc592c0dbb5e1ae0aed8710f7f7714c336bdd1d1d31b343e6edddd358ead
4
- data.tar.gz: 0ebb5fbe0aeff0417193d4521cf52a78d849b83d116e08118b9cf87ee2655a71
3
+ metadata.gz: 4c8eda4a61584293cfb2f20a4ece0c5afd8963be75c56c5c3a1f71cbbf04a2ed
4
+ data.tar.gz: 72ea08e5a2fac3b5d9f0d5dada3bb71c7b655acbd7c03f4533e0bbe951be954e
5
5
  SHA512:
6
- metadata.gz: f9a64cbae7e3a34ae66450ae7fe20181560dc6860950a92e53c5aaf61ab10343372044968b5a726bef51b082a45dd9150d6f161d93a45a4ccf75d550cf981be1
7
- data.tar.gz: a77ea69469a02b3cbd089cade6be20347abc03cada1cf93fec8380456f000d083a914296e0b35faff573e60d73e4759abd1b5d224cb04e64b38862fe720cf65c
6
+ metadata.gz: fe64d9f93ff1343c36d1d478f63e9a4614587897b6414ec3a1f4c28fdd90ee1d245134e9350f546373350acf1f1355dd50d31da162a899d096ceb1114029767e
7
+ data.tar.gz: d4dd2ba2714e54c766592734481f7ba373692375f4c2011578f1b22da36fae3b8d58e721677e47ba214805d3798737c5ad6dec7711d586a46727029e555fb72e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (1.7.0)
4
+ gitlab_quality-test_tooling (1.8.1)
5
5
  activesupport (>= 6.1, < 7.2)
6
6
  amatch (~> 0.4.1)
7
7
  gitlab (~> 4.19)
data/README.md CHANGED
@@ -77,6 +77,8 @@ Usage: exe/prepare-stage-reports [options]
77
77
  Purpose: Relate test failures to failure issues from RSpec report files (JSON or JUnit XML)
78
78
  Usage: exe/relate-failure-issue [options]
79
79
  -i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
80
+ -m METRICS_FILES, Test metrics files (JSON)
81
+ --metrics-files
80
82
  --max-diff-ratio MAX_DIFF_RATO
81
83
  Max stacktrace diff ratio for failure issues detection
82
84
  -p, --project PROJECT Can be an integer or a group/project string
@@ -128,11 +130,13 @@ Usage: exe/update-screenshot-paths [options]
128
130
 
129
131
  ```shell
130
132
  Purpose: Create slow test issues from JSON RSpec report files
131
- Usage: exe/slow-test-issue [options]
133
+ Usage: exe/slow-test-issues [options]
132
134
  -i, --input-files INPUT_FILES JSON RSpec report files JSON
133
135
  -p, --project PROJECT Can be an integer or a group/project string
134
136
  -t, --token TOKEN A valid access token with `api` scope and Maintainer permission in PROJECT
135
- --dry-run Perform a dry-run (don't create note)
137
+ -r RELATED_ISSUES_FILE, The file path for the related issues
138
+ --related-issues-file
139
+ --dry-run Perform a dry-run (don't create issues)
136
140
  -v, --version Show the version
137
141
  -h, --help Show the usage
138
142
  ```
@@ -141,13 +145,13 @@ Usage: exe/slow-test-issue [options]
141
145
 
142
146
  ```shell
143
147
  Purpose: Purpose: Create flaky test issues for any passed test coming from rspec-retry JSON report files
144
- Usage: exe/flaky-test-issue [options]
148
+ Usage: exe/flaky-test-issues [options]
145
149
  -i, --input-files INPUT_FILES JSON rspec-retry report files
146
150
  -p, --project PROJECT Can be an integer or a group/project string
147
151
  -m MERGE_REQUEST_IID, An integer merge request IID
148
152
  --merge_request_iid
149
153
  -t, --token TOKEN A valid access token with `api` scope and Maintainer permission in PROJECT
150
- --dry-run Perform a dry-run (don't create note)
154
+ --dry-run Perform a dry-run (don't create issues)
151
155
  -v, --version Show the version
152
156
  -h, --help Show the usage
153
157
  ```
@@ -158,11 +162,11 @@ Usage: exe/flaky-test-issue [options]
158
162
  Purpose: Create slow test note on merge requests from JSON RSpec report files
159
163
  Usage: exe/slow-test-merge-request-report-note [options]
160
164
  -i, --input-files INPUT_FILES JSON RSpec report files JSON
161
- --project PROJECT Can be an integer or a group/project string
165
+ -p, --project PROJECT Can be an integer or a group/project string
162
166
  -m MERGE_REQUEST_IID, An integer merge request IID
163
167
  --merge_request_iid
164
168
  -t, --token TOKEN A valid access token with `api` scope and Maintainer permission in PROJECT
165
- --dry-run Perform a dry-run (don't create issues)
169
+ --dry-run Perform a dry-run (don't create note)
166
170
  -v, --version Show the version
167
171
  -h, --help Show the usage
168
172
  ```
@@ -15,6 +15,10 @@ options = OptionParser.new do |opts|
15
15
  params[:input_files] = input_files
16
16
  end
17
17
 
18
+ opts.on('-m', '--metrics-files METRICS_FILES', String, 'Test metrics files (JSON)') do |metrics_files|
19
+ params[:metrics_files] = metrics_files
20
+ end
21
+
18
22
  opts.on('--max-diff-ratio MAX_DIFF_RATO', Float, 'Max stacktrace diff ratio for failure issues detection') do |max_diff_ratio|
19
23
  params[:max_diff_ratio] = max_diff_ratio
20
24
  end
@@ -41,6 +41,7 @@ module GitlabQuality
41
41
  system_logs: [],
42
42
  base_issue_labels: nil,
43
43
  exclude_labels_for_search: nil,
44
+ metrics_files: [],
44
45
  **kwargs)
45
46
  super
46
47
  @max_diff_ratio = max_diff_ratio.to_f
@@ -49,11 +50,12 @@ module GitlabQuality
49
50
  @exclude_labels_for_search = Set.new(exclude_labels_for_search)
50
51
  @issue_type = 'issue'
51
52
  @commented_issue_list = Set.new
53
+ @metrics_files = Array(metrics_files)
52
54
  end
53
55
 
54
56
  private
55
57
 
56
- attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search
58
+ attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search, :metrics_files
57
59
 
58
60
  def run!
59
61
  puts "Reporting test failures in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
@@ -66,16 +68,39 @@ module GitlabQuality
66
68
  write_issues_log_file
67
69
  end
68
70
 
71
+ def test_metric_collections
72
+ @test_metric_collections ||= Dir.glob(metrics_files).map do |path|
73
+ TestMetrics::JsonTestMetricCollection.new(path)
74
+ end
75
+ end
76
+
69
77
  def process_test_results(test_results)
70
78
  systemic_failures = systemic_failures_for_test_results(test_results)
71
79
 
72
80
  test_results.each do |test|
73
81
  collect_issues(test, relate_failure_to_issue(test)) if should_report?(test, systemic_failures)
82
+
83
+ copy_failure_issue_to_test_metrics(test) if metrics_files.any?
74
84
  end
75
85
 
76
86
  test_results.write
77
87
  end
78
88
 
89
+ def copy_failure_issue_to_test_metrics(test)
90
+ failure_issue = test.failure_issue
91
+
92
+ return unless failure_issue
93
+
94
+ test_metric_collections.find do |test_metric_collection|
95
+ test_metric = test_metric_collection.metric_for_test_id(test.example_id)
96
+
97
+ if test_metric
98
+ test_metric.fields['failure_issue'] = failure_issue
99
+ test_metric_collection.write
100
+ end
101
+ end
102
+ end
103
+
79
104
  def systemic_failures_for_test_results(test_results)
80
105
  test_results
81
106
  .flat_map { |test| test.failures.map { |failure| failure['message'].lines.first.chomp } }
@@ -142,9 +167,7 @@ module GitlabQuality
142
167
  def pipeline_issues_with_similar_stacktrace(test)
143
168
  search_labels = (base_issue_labels + Set.new(%w[test failure::new])).to_a
144
169
  not_labels = exclude_labels_for_search.to_a
145
- gitlab.find_issues(options: { labels: search_labels,
146
- not: { labels: not_labels },
147
- created_after: past_timestamp(2) }).select do |issue|
170
+ find_issues_created_after(past_timestamp(2), state: 'opened', labels: search_labels, not_labels: not_labels).select do |issue|
148
171
  job_url_from_issue = failed_issue_job_url(issue)
149
172
 
150
173
  next if pipeline != pipeline_env_from_job_url(job_url_from_issue)
@@ -171,6 +194,7 @@ module GitlabQuality
171
194
  def failure_issues(test)
172
195
  find_issues_for_test(
173
196
  test,
197
+ state: 'opened',
174
198
  labels: base_issue_labels + Set.new(%w[test]),
175
199
  not_labels: exclude_labels_for_search
176
200
  )
@@ -145,10 +145,19 @@ module GitlabQuality
145
145
  def find_issues_for_test(test, labels:, not_labels: Set.new, state: nil)
146
146
  search_options = { labels: labels.to_a, not: { labels: not_labels.to_a } }
147
147
  search_options[:state] = state if state
148
+ search_options[:search] = test.file.to_s.empty? ? test.name : partial_file_path(test.file)
149
+ search_options[:in] = 'title'
148
150
 
149
151
  gitlab.find_issues(options: search_options).find_all { |issue| issue_match_test?(issue, test) }
150
152
  end
151
153
 
154
+ def find_issues_created_after(timestamp, labels:, not_labels: Set.new, state: nil)
155
+ search_options = { labels: labels.to_a, not: { labels: not_labels.to_a }, created_after: timestamp }
156
+ search_options[:state] = state if state
157
+
158
+ gitlab.find_issues(options: search_options)
159
+ end
160
+
152
161
  def issue_match_test?(issue, test)
153
162
  issue_title = issue.title.strip
154
163
  test_file_path_found = !test.file.to_s.empty? && issue_title.include?(partial_file_path(test.file))
@@ -65,10 +65,18 @@ module GitlabQuality
65
65
  "1. #{Time.new.utc.strftime('%F')}: #{test.ci_job_url} (#{ENV.fetch('CI_PIPELINE_URL', 'pipeline url is missing')})"
66
66
  end
67
67
 
68
+ def slow_test_issues(test)
69
+ find_issues_for_test(
70
+ test,
71
+ state: 'opened',
72
+ labels: SEARCH_LABELS
73
+ )
74
+ end
75
+
68
76
  def create_slow_issue(test)
69
77
  puts " => Finding existing issues for slow test '#{test.name}' (run time: #{test.run_time} seconds)..."
70
78
 
71
- issues = find_issues_for_test(test, labels: SEARCH_LABELS, state: 'opened')
79
+ issues = slow_test_issues(test)
72
80
 
73
81
  if issues.blank?
74
82
  issues << create_issue(test)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GitlabQuality
4
+ module TestTooling
5
+ module TestMetric
6
+ class JsonTestMetric
7
+ attr_reader :metric
8
+
9
+ def initialize(metric)
10
+ @metric = metric
11
+ end
12
+
13
+ def name
14
+ metric.fetch('name')
15
+ end
16
+
17
+ def time
18
+ metric.fetch('time')
19
+ end
20
+
21
+ def tags
22
+ @tags ||= metric.fetch('tags')
23
+ end
24
+
25
+ def fields
26
+ @fields ||= metric.fetch('fields')
27
+ end
28
+
29
+ def to_json(*options)
30
+ as_json.to_json(*options)
31
+ end
32
+
33
+ private
34
+
35
+ def as_json
36
+ {
37
+ name: name,
38
+ time: time,
39
+ tags: tags,
40
+ fields: fields
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module GitlabQuality
6
+ module TestTooling
7
+ module TestMetrics
8
+ class JsonTestMetricCollection
9
+ include Enumerable
10
+
11
+ attr_reader :path, :metrics
12
+
13
+ def initialize(path)
14
+ @path = path
15
+ @metrics = process
16
+ end
17
+
18
+ def metric_for_test_id(test_id)
19
+ metrics.find do |metric|
20
+ metric.fields['id'] == test_id
21
+ end
22
+ end
23
+
24
+ def write
25
+ File.write(path, JSON.pretty_generate(metrics))
26
+ end
27
+
28
+ private
29
+
30
+ def parse
31
+ JSON.parse(File.read(path))
32
+ rescue JSON::ParserError
33
+ Runtime::Logger.debug("#{self.class.name}##{__method__} attempted to parse invalid JSON at path: #{path}")
34
+ {}
35
+ end
36
+
37
+ def process
38
+ parse.map do |test|
39
+ GitlabQuality::TestTooling::TestMetric::JsonTestMetric.new(test)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "1.7.0"
5
+ VERSION = "1.8.1"
6
6
  end
7
7
  end
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: 1.7.0
4
+ version: 1.8.1
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-11-29 00:00:00.000000000 Z
11
+ date: 2023-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control
@@ -422,6 +422,8 @@ files:
422
422
  - lib/gitlab_quality/test_tooling/system_logs/log_types/rails/graphql_log.rb
423
423
  - lib/gitlab_quality/test_tooling/system_logs/shared_fields.rb
424
424
  - lib/gitlab_quality/test_tooling/system_logs/system_logs_formatter.rb
425
+ - lib/gitlab_quality/test_tooling/test_metric/json_test_metric.rb
426
+ - lib/gitlab_quality/test_tooling/test_metrics/json_test_metric_collection.rb
425
427
  - lib/gitlab_quality/test_tooling/test_result/base_test_result.rb
426
428
  - lib/gitlab_quality/test_tooling/test_result/j_unit_test_result.rb
427
429
  - lib/gitlab_quality/test_tooling/test_result/json_test_result.rb