gitlab_quality-test_tooling 1.32.1 → 1.34.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: e3c5680095668ee71c082a8183693ec031714d59641fbd0ba7f2ef32555a73dc
4
- data.tar.gz: 42c9bc53f92cb752fddb7cbf529e08f951245c751dcfac35835fd002a307ed30
3
+ metadata.gz: 6d3f45e3af6f11c3ebca5f44f3d717960c1ac20cffdc13db75a16d68c9eecfbd
4
+ data.tar.gz: 0edf629fc7f432a779141be67a231887224a78793defedad416df50b327ecbcb
5
5
  SHA512:
6
- metadata.gz: a1f2f1791fd8e59b4e4b8e2a3ef5ca1d0c501d34ccdb9525eb621b3776495d28ac810c1280a5a0b3007b7c73aa9b08775ce87c9da5ef01cda1d396c7c79f1840
7
- data.tar.gz: e7d5b62b448ce3e48a50368feebc11bd5d2956f61c34628de7484ad658fdc6d1ab027eee716d754b8d16d2732245820ee220a809199b1ef9295c7457b54f7ea4
6
+ metadata.gz: 7570cde0cd99ea0fe3148f9a8c1f9a7035c165fb0f5506623a79d3f2c3227581d6de878fd56c9a5d5f4c4bae22191d688f49355c74e4b4926b6362ef5d3f8d06
7
+ data.tar.gz: 0112df035902806c60a82433118669b43bcd9feff89fd8dc7061ee6ffcda9c53ead791c7df4c188567b2b16ee3be8880e269088f4bee944b944aa2dafb60bfef
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (1.32.1)
4
+ gitlab_quality-test_tooling (1.34.0)
5
5
  activesupport (>= 7.0, < 7.2)
6
6
  amatch (~> 0.4.1)
7
7
  gitlab (~> 4.19)
@@ -4,19 +4,39 @@ module GitlabQuality
4
4
  module TestTooling
5
5
  module KnapsackReports
6
6
  class SpecRunTime
7
- attr_reader :project, :file, :expected, :actual, :expected_suite_duration, :actual_suite_duration
7
+ attr_reader :file, :expected, :actual, :expected_suite_duration, :actual_suite_duration, :project, :ref
8
8
 
9
9
  ACTUAL_TO_EXPECTED_SPEC_RUN_TIME_RATIO_THRESHOLD = 1.5 # actual run time is longer than expected by 50% +
10
10
  SPEC_WEIGHT_PERCENTAGE_TRESHOLD = 15 # a spec file takes 15%+ of the total test suite run time
11
11
  SUITE_DURATION_THRESHOLD = 70 * 60 # if test suite takes more than 70 minutes, job risks timing out
12
-
13
- def initialize(project:, file:, expected:, actual:, expected_suite_duration:, actual_suite_duration:)
14
- @project = project
12
+ FEATURE_CATEGORY_METADATA_REGEX = /(?<=feature_category: :)(?<feature_category>\w+)/
13
+
14
+ def initialize(
15
+ file:,
16
+ expected:,
17
+ actual:,
18
+ expected_suite_duration:,
19
+ actual_suite_duration:,
20
+ token: '',
21
+ project: Runtime::Env.ci_project_path,
22
+ ref: Runtime::Env.ci_commit_ref_name)
15
23
  @file = file
16
24
  @expected = expected.to_f
17
25
  @actual = actual.to_f
18
26
  @expected_suite_duration = expected_suite_duration.to_f
19
27
  @actual_suite_duration = actual_suite_duration.to_f
28
+ @token = token
29
+ @project = project
30
+ @ref = ref
31
+ end
32
+
33
+ def feature_category
34
+ file_lines.each do |line|
35
+ match = FEATURE_CATEGORY_METADATA_REGEX.match(line)
36
+ next unless match
37
+
38
+ break match[:feature_category]
39
+ end
20
40
  end
21
41
 
22
42
  def should_report?
@@ -50,6 +70,8 @@ module GitlabQuality
50
70
 
51
71
  private
52
72
 
73
+ attr_reader :token
74
+
53
75
  def exceed_actual_to_expected_ratio_threshold?
54
76
  actual / expected >= ACTUAL_TO_EXPECTED_SPEC_RUN_TIME_RATIO_THRESHOLD
55
77
  end
@@ -80,6 +102,18 @@ module GitlabQuality
80
102
  def file_link
81
103
  "https://gitlab.com/#{project}/-/blob/#{Runtime::Env.ci_commit_ref_name}/#{file}"
82
104
  end
105
+
106
+ def file_lines
107
+ files_client.file_contents.lines(chomp: true)
108
+ end
109
+
110
+ def files_client
111
+ @files_client ||= GitlabClient::RepositoryFilesClient.new(
112
+ token: token,
113
+ project: project,
114
+ file_path: file,
115
+ ref: ref)
116
+ end
83
117
  end
84
118
  end
85
119
  end
@@ -8,10 +8,11 @@ module GitlabQuality
8
8
  class SpecRunTimeReport
9
9
  attr_reader :project, :expected_report, :actual_report
10
10
 
11
- def initialize(project:, expected_report_path:, actual_report_path:)
11
+ def initialize(project:, expected_report_path:, actual_report_path:, token: '')
12
12
  @project = project
13
13
  @expected_report = parse(expected_report_path)
14
14
  @actual_report = parse(actual_report_path)
15
+ @token = token
15
16
  end
16
17
 
17
18
  def filtered_report
@@ -25,6 +26,7 @@ module GitlabQuality
25
26
  end
26
27
 
27
28
  spec_run_time = SpecRunTime.new(
29
+ token: token,
28
30
  project: project,
29
31
  file: spec_file,
30
32
  expected: expected_run_time,
@@ -39,6 +41,8 @@ module GitlabQuality
39
41
 
40
42
  private
41
43
 
44
+ attr_reader :token
45
+
42
46
  def parse(report_path)
43
47
  JSON.parse(File.read(report_path))
44
48
  end
@@ -10,7 +10,6 @@ module GitlabQuality
10
10
  WWW_GITLAB_COM_SITE = 'https://about.gitlab.com'
11
11
  WWW_GITLAB_COM_GROUPS_JSON = "#{WWW_GITLAB_COM_SITE}/groups.json".freeze
12
12
  WWW_GITLAB_COM_CATEGORIES_JSON = "#{WWW_GITLAB_COM_SITE}/categories.json".freeze
13
- FEATURE_CATEGORY_METADATA_REGEX = /(?<=feature_category: :)\w+/
14
13
 
15
14
  def infer_labels_from_product_group(product_group)
16
15
  [groups_mapping.dig(product_group, 'label')].compact.to_set
@@ -10,11 +10,14 @@ module GitlabQuality
10
10
  end
11
11
 
12
12
  def new_issue_labels(test)
13
- puts " => [DEBUG] product_group: #{test.product_group}; feature_category: #{test.feature_category}"
13
+ debug_line = ' => [DEBUG] '
14
+ debug_line += "product_group: #{test&.product_group}; " if test.respond_to?(:product_group)
15
+ debug_line += "feature_category: #{test&.feature_category}" if test.respond_to?(:feature_category)
16
+ puts debug_line
14
17
 
15
- new_labels = self.class::NEW_ISSUE_LABELS +
16
- labels_inference.infer_labels_from_product_group(test.product_group) +
17
- labels_inference.infer_labels_from_feature_category(test.feature_category)
18
+ new_labels = self.class::NEW_ISSUE_LABELS
19
+ new_labels += labels_inference.infer_labels_from_product_group(test.product_group) if test.respond_to?(:product_group)
20
+ new_labels += labels_inference.infer_labels_from_feature_category(test.feature_category) if test.respond_to?(:feature_category)
18
21
  up_to_date_labels(test: test, new_labels: new_labels)
19
22
  end
20
23
  end
@@ -14,6 +14,8 @@ module GitlabQuality
14
14
  # - If not found:
15
15
  # - Create a new issue with the run time data
16
16
  class KnapsackReportIssue < ReportAsIssue
17
+ include Concerns::GroupAndCategoryLabels
18
+
17
19
  NEW_ISSUE_LABELS = Set.new(['test', 'type::maintenance', 'maintenance::performance', 'priority::3', 'severity::3', 'knapsack_report']).freeze
18
20
  SEARCH_LABELS = %w[test maintenance::performance knapsack_report].freeze
19
21
  JOB_TIMEOUT_EPIC_URL = 'https://gitlab.com/groups/gitlab-org/quality/engineering-productivity/-/epics/19'
@@ -36,6 +38,7 @@ module GitlabQuality
36
38
 
37
39
  def search_and_create_issue
38
40
  filtered_report = KnapsackReports::SpecRunTimeReport.new(
41
+ token: token,
39
42
  project: project,
40
43
  expected_report_path: expected_report_path,
41
44
  actual_report_path: actual_report_path
@@ -67,10 +70,6 @@ module GitlabQuality
67
70
  files.first
68
71
  end
69
72
 
70
- def new_issue_labels(_spec_run_time)
71
- NEW_ISSUE_LABELS
72
- end
73
-
74
73
  def new_issue_title(spec_run_time)
75
74
  "Job timeout risk: #{spec_run_time.file} ran much longer than expected"
76
75
  end
@@ -110,6 +109,10 @@ module GitlabQuality
110
109
  description: updated_description
111
110
  }
112
111
 
112
+ # We reopen closed issues to not lose any history
113
+ state_event = issue.state == 'closed' ? 'reopen' : nil
114
+ issue_attrs[:state_event] = state_event if state_event
115
+
113
116
  gitlab.edit_issue(iid: issue.iid, options: issue_attrs)
114
117
  puts " => Added a report in #{issue.web_url}!"
115
118
  end
@@ -149,14 +149,14 @@ module GitlabQuality
149
149
  labels |= new_labels.to_set
150
150
  ee_test?(test) ? labels << 'Enterprise Edition' : labels.delete('Enterprise Edition')
151
151
 
152
- if test.quarantine?
152
+ if test.respond_to?(:quarantine?) && test.quarantine?
153
153
  labels << 'quarantine'
154
154
  labels << "quarantine::#{test.quarantine_type}"
155
155
  else
156
156
  labels.delete_if { |label| label.include?('quarantine') }
157
157
  end
158
158
 
159
- labels << 'rspec-shared-examples' if test.calls_shared_examples?
159
+ labels << 'rspec-shared-examples' if test.respond_to?(:calls_shared_examples?) && test.calls_shared_examples?
160
160
 
161
161
  labels
162
162
  end
@@ -44,11 +44,11 @@ module GitlabQuality
44
44
 
45
45
  def health_problem_status_label_quick_action(reports_list)
46
46
  case reports_list.reports_count
47
- when 40..Float::INFINITY
47
+ when 6099..Float::INFINITY
48
48
  '/label ~"slowness::1"'
49
- when 28..39
49
+ when 2177..6098
50
50
  '/label ~"slowness::2"'
51
- when 12..27
51
+ when 521..2176
52
52
  '/label ~"slowness::3"'
53
53
  else
54
54
  '/label ~"slowness::4"'
@@ -11,7 +11,6 @@ module GitlabQuality
11
11
  attr_reader :project, :ref, :report_issue, :processed_commits
12
12
 
13
13
  TEST_PLATFORM_MAINTAINERS_SLACK_CHANNEL_ID = 'C0437FV9KBN' # test-platform-maintainers
14
- BATCH_LIMIT = 10
15
14
 
16
15
  def initialize(token:, project:, specs_file:, processor:, ref: 'master', dry_run: false)
17
16
  @specs_file = specs_file
@@ -29,7 +28,7 @@ module GitlabQuality
29
28
 
30
29
  contents['specs'].each do |spec|
31
30
  processor.create_commit(spec, self)
32
- break if processed_commits.keys.count >= BATCH_LIMIT
31
+ break if processed_commits.keys.count >= ENV.fetch('BATCH_LIMIT', 10)
33
32
  end
34
33
 
35
34
  processor.create_merge_requests(self)
@@ -32,10 +32,6 @@ module GitlabQuality
32
32
  raise NotImplementedError
33
33
  end
34
34
 
35
- def line_number
36
- raise NotImplementedError
37
- end
38
-
39
35
  def section
40
36
  raise NotImplementedError
41
37
  end
@@ -52,10 +48,53 @@ module GitlabQuality
52
48
  raise NotImplementedError
53
49
  end
54
50
 
51
+ def product_group
52
+ report['product_group'].to_s
53
+ end
54
+
55
+ def feature_category
56
+ report['feature_category']
57
+ end
58
+
55
59
  def failures?
56
60
  failures.any?
57
61
  end
58
62
 
63
+ def product_group?
64
+ product_group != ''
65
+ end
66
+
67
+ def failure_issue
68
+ report['failure_issue']
69
+ end
70
+
71
+ def failure_issue=(new_failure_issue)
72
+ report['failure_issue'] = new_failure_issue
73
+ end
74
+
75
+ def line_number
76
+ report['line_number']
77
+ end
78
+
79
+ def level
80
+ report['level']
81
+ end
82
+
83
+ def run_time
84
+ report['run_time'].to_f.round(2)
85
+ end
86
+
87
+ def screenshot?
88
+ !!screenshot
89
+ end
90
+
91
+ def quarantine?
92
+ # The value for 'quarantine' could be nil, a hash, a string,
93
+ # or true (if the test just has the :quarantine tag)
94
+ # But any non-nil or false value should means the test is in quarantine
95
+ !!quarantine
96
+ end
97
+
59
98
  def file
60
99
  @file ||= relative_file.start_with?('qa/') ? "qa/#{relative_file}" : relative_file
61
100
  end
@@ -98,6 +137,14 @@ module GitlabQuality
98
137
  private
99
138
 
100
139
  attr_reader :token, :project, :ref
140
+
141
+ def screenshot
142
+ report.fetch('screenshot', nil)
143
+ end
144
+
145
+ def quarantine
146
+ report.fetch('quarantine', nil)
147
+ end
101
148
  end
102
149
  end
103
150
  end
@@ -40,64 +40,13 @@ module GitlabQuality
40
40
  end
41
41
  end
42
42
 
43
- def quarantine
44
- !report['quarantine'].nil?
45
- end
46
-
47
- def quarantine?
48
- # The value for 'quarantine' could be nil, a hash, a string,
49
- # or true (if the test just has the :quarantine tag)
50
- # But any non-nil or false value should means the test is in quarantine
51
- !!quarantine
52
- end
53
-
54
- def line_number
55
- report['line_number']
56
- end
57
-
58
- def level
59
- report['level']
60
- end
61
-
62
- def run_time
63
- report['run_time'].to_f.round(2)
64
- end
65
-
66
- def screenshot
67
- report['screenshot']
68
- end
69
-
70
- def screenshot?
71
- !!screenshot
72
- end
73
-
74
43
  def max_duration_for_test
75
- ""
44
+ ''
76
45
  end
77
46
 
78
47
  def ci_job_url
79
48
  ENV.fetch('CI_JOB_URL', '')
80
49
  end
81
-
82
- def product_group
83
- report['product_group'].to_s
84
- end
85
-
86
- def product_group?
87
- product_group != ''
88
- end
89
-
90
- def feature_category
91
- report['feature_category']
92
- end
93
-
94
- def failure_issue
95
- report['failure_issue']
96
- end
97
-
98
- def failure_issue=(new_failure_issue)
99
- report['failure_issue'] = new_failure_issue
100
- end
101
50
  end
102
51
  end
103
52
  end
@@ -68,21 +68,6 @@ module GitlabQuality
68
68
  report['testcase'] = new_testcase
69
69
  end
70
70
 
71
- def failure_issue
72
- report['failure_issue']
73
- end
74
-
75
- def failure_issue=(new_failure_issue)
76
- report['failure_issue'] = new_failure_issue
77
- end
78
-
79
- def quarantine?
80
- # The value for 'quarantine' could be nil, a hash, a string,
81
- # or true (if the test just has the :quarantine tag)
82
- # But any non-nil or false value should means the test is in quarantine
83
- !!quarantine
84
- end
85
-
86
71
  def quarantine_type
87
72
  quarantine['type'] if quarantine?
88
73
  end
@@ -91,26 +76,10 @@ module GitlabQuality
91
76
  quarantine['issue'] if quarantine?
92
77
  end
93
78
 
94
- def screenshot?
95
- !!screenshot
96
- end
97
-
98
79
  def screenshot_image
99
80
  screenshot['image'] if screenshot?
100
81
  end
101
82
 
102
- def product_group
103
- report['product_group'].to_s
104
- end
105
-
106
- def product_group?
107
- product_group != ''
108
- end
109
-
110
- def feature_category
111
- report['feature_category']
112
- end
113
-
114
83
  def section
115
84
  report['section']
116
85
  end
@@ -119,22 +88,10 @@ module GitlabQuality
119
88
  report['category']
120
89
  end
121
90
 
122
- def run_time
123
- report['run_time'].to_f.round(2)
124
- end
125
-
126
91
  def example_id
127
92
  report['id']
128
93
  end
129
94
 
130
- def line_number
131
- report['line_number']
132
- end
133
-
134
- def level
135
- report['level']
136
- end
137
-
138
95
  def ci_job_id
139
96
  report['ci_job_url'].split('/').last
140
97
  end
@@ -180,14 +137,6 @@ module GitlabQuality
180
137
 
181
138
  private
182
139
 
183
- def quarantine
184
- report.fetch('quarantine', nil)
185
- end
186
-
187
- def screenshot
188
- report.fetch('screenshot', nil)
189
- end
190
-
191
140
  def format_message_lines(message_lines)
192
141
  message_lines.is_a?(Array) ? message_lines.join("\n") : message_lines
193
142
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "1.32.1"
5
+ VERSION = "1.34.0"
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.32.1
4
+ version: 1.34.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: 2024-07-25 00:00:00.000000000 Z
11
+ date: 2024-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control