gitlab_quality-test_tooling 1.8.0 → 1.9.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 +1 -1
- data/README.md +8 -6
- data/exe/post-to-slack +25 -2
- data/lib/gitlab_quality/test_tooling/failed_jobs_table.rb +35 -0
- data/lib/gitlab_quality/test_tooling/gitlab_client/failed_jobs.rb +32 -0
- data/lib/gitlab_quality/test_tooling/report/relate_failure_issue.rb +2 -3
- data/lib/gitlab_quality/test_tooling/report/report_as_issue.rb +9 -0
- data/lib/gitlab_quality/test_tooling/report/slow_test_issue.rb +9 -1
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7c32e6b11eb72bf1f453827d3c8c0dd98a8d37788c22000566fac4fe9b0daab
|
4
|
+
data.tar.gz: 573ea110d2d1bea41f217f135f6dfe57a814ecc261142813e4dbbda17f813e0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7f5b809cd506c860edba93bc45c932183106da000b2eb14ae7149aa5d7a820502971fd5a26747664be1921334af3b1041a668fb128f8b4c739507ac63f850f2
|
7
|
+
data.tar.gz: 1a428ce49770515622c810bfaf2e918df2223b7ed23f38958d994de6bef4c591c5fd10efc7be071d1fdf6cde38eacc8598126b612fde62c300a01c0e9608c83a
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -130,11 +130,13 @@ Usage: exe/update-screenshot-paths [options]
|
|
130
130
|
|
131
131
|
```shell
|
132
132
|
Purpose: Create slow test issues from JSON RSpec report files
|
133
|
-
Usage: exe/slow-test-
|
133
|
+
Usage: exe/slow-test-issues [options]
|
134
134
|
-i, --input-files INPUT_FILES JSON RSpec report files JSON
|
135
135
|
-p, --project PROJECT Can be an integer or a group/project string
|
136
136
|
-t, --token TOKEN A valid access token with `api` scope and Maintainer permission in PROJECT
|
137
|
-
|
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)
|
138
140
|
-v, --version Show the version
|
139
141
|
-h, --help Show the usage
|
140
142
|
```
|
@@ -143,13 +145,13 @@ Usage: exe/slow-test-issue [options]
|
|
143
145
|
|
144
146
|
```shell
|
145
147
|
Purpose: Purpose: Create flaky test issues for any passed test coming from rspec-retry JSON report files
|
146
|
-
Usage: exe/flaky-test-
|
148
|
+
Usage: exe/flaky-test-issues [options]
|
147
149
|
-i, --input-files INPUT_FILES JSON rspec-retry report files
|
148
150
|
-p, --project PROJECT Can be an integer or a group/project string
|
149
151
|
-m MERGE_REQUEST_IID, An integer merge request IID
|
150
152
|
--merge_request_iid
|
151
153
|
-t, --token TOKEN A valid access token with `api` scope and Maintainer permission in PROJECT
|
152
|
-
--dry-run Perform a dry-run (don't create
|
154
|
+
--dry-run Perform a dry-run (don't create issues)
|
153
155
|
-v, --version Show the version
|
154
156
|
-h, --help Show the usage
|
155
157
|
```
|
@@ -160,11 +162,11 @@ Usage: exe/flaky-test-issue [options]
|
|
160
162
|
Purpose: Create slow test note on merge requests from JSON RSpec report files
|
161
163
|
Usage: exe/slow-test-merge-request-report-note [options]
|
162
164
|
-i, --input-files INPUT_FILES JSON RSpec report files JSON
|
163
|
-
|
165
|
+
-p, --project PROJECT Can be an integer or a group/project string
|
164
166
|
-m MERGE_REQUEST_IID, An integer merge request IID
|
165
167
|
--merge_request_iid
|
166
168
|
-t, --token TOKEN A valid access token with `api` scope and Maintainer permission in PROJECT
|
167
|
-
--dry-run Perform a dry-run (don't create
|
169
|
+
--dry-run Perform a dry-run (don't create note)
|
168
170
|
-v, --version Show the version
|
169
171
|
-h, --help Show the usage
|
170
172
|
```
|
data/exe/post-to-slack
CHANGED
@@ -8,6 +8,9 @@ require_relative "../lib/gitlab_quality/test_tooling"
|
|
8
8
|
|
9
9
|
params = {}
|
10
10
|
|
11
|
+
messages = []
|
12
|
+
gitlab_api_token = nil
|
13
|
+
|
11
14
|
options = OptionParser.new do |opts|
|
12
15
|
opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
13
16
|
|
@@ -15,16 +18,34 @@ options = OptionParser.new do |opts|
|
|
15
18
|
params[:slack_webhook_url] = slack_webhook_url
|
16
19
|
end
|
17
20
|
|
21
|
+
opts.on('-a', '--gitlab-api-token TOKEN', String, 'GitLab API token') do |token|
|
22
|
+
gitlab_api_token = token unless token.empty?
|
23
|
+
end
|
24
|
+
|
18
25
|
opts.on('-c', '--channel CHANNEL', String, 'Slack channel to post the message to') do |channel|
|
19
26
|
params[:channel] = channel
|
20
27
|
end
|
21
28
|
|
22
29
|
opts.on('-m', '--message MESSAGE', String, 'Post message to Slack') do |message|
|
23
|
-
|
30
|
+
messages << message
|
24
31
|
end
|
25
32
|
|
26
33
|
opts.on('-t', '--include-summary-table FILES', String, 'Add a test summary table based on RSpec report files (JUnit XML)') do |files|
|
27
|
-
|
34
|
+
messages << GitlabQuality::TestTooling::SummaryTable.create(input_files: files)
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on('-j', '--include-failed-jobs-table', 'Add a list of failed jobs in the pipeline') do
|
38
|
+
next puts("Failed jobs table requires api token to be set via --gitlab-api-token option, skipping failed jobs table") unless gitlab_api_token
|
39
|
+
|
40
|
+
project_id = ENV['CI_PROJECT_ID']&.to_i || (next puts("CI_PROJECT_ID not set, skipping failed jobs table"))
|
41
|
+
pipeline_id = ENV['CI_PIPELINE_ID']&.to_i || (next puts("CI_PIPELINE_ID not set, skipping failed jobs table"))
|
42
|
+
|
43
|
+
jobs = GitlabQuality::TestTooling::GitlabClient::FailedJobs.new(token: gitlab_api_token, project_id: project_id, pipeline_id: pipeline_id).fetch
|
44
|
+
next if jobs.empty?
|
45
|
+
|
46
|
+
messages << GitlabQuality::TestTooling::FailedJobsTable.create(jobs: jobs)
|
47
|
+
rescue StandardError => e
|
48
|
+
puts "Failed to fetch failed jobs. #{e.class}: #{e.message}"
|
28
49
|
end
|
29
50
|
|
30
51
|
opts.on('-u', '--username USERNAME', String, 'Username to use for the Slack message') do |username|
|
@@ -50,6 +71,8 @@ options = OptionParser.new do |opts|
|
|
50
71
|
opts.parse(ARGV)
|
51
72
|
end
|
52
73
|
|
74
|
+
params[:message] = messages.join("\n\n")
|
75
|
+
|
53
76
|
if params.any?
|
54
77
|
GitlabQuality::TestTooling::Slack::PostToSlack.new(**params).invoke!
|
55
78
|
else
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'table_print'
|
4
|
+
|
5
|
+
module GitlabQuality
|
6
|
+
module TestTooling
|
7
|
+
module FailedJobsTable
|
8
|
+
class << self
|
9
|
+
# Create table with formatted list of failed jobs
|
10
|
+
#
|
11
|
+
# @param [Array<Gitlab::ObjectifiedHash>] jobs
|
12
|
+
# @return [String]
|
13
|
+
def create(jobs:)
|
14
|
+
"```\n#{TablePrint::Printer.table_print(collect_results(jobs))}\n```\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Format list of failed jobs
|
20
|
+
#
|
21
|
+
# @param [Array<Gitlab::ObjectifiedHash>] jobs
|
22
|
+
# @return [Array]
|
23
|
+
def collect_results(jobs)
|
24
|
+
jobs.sort_by(&:stage).map do |job|
|
25
|
+
{
|
26
|
+
"Job" => job.name,
|
27
|
+
"Stage" => job.stage,
|
28
|
+
"Failure Reason" => job.failure_reason
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gitlab'
|
4
|
+
|
5
|
+
module GitlabQuality
|
6
|
+
module TestTooling
|
7
|
+
module GitlabClient
|
8
|
+
class FailedJobs
|
9
|
+
def initialize(token:, project_id:, pipeline_id:)
|
10
|
+
@token = token
|
11
|
+
@project_id = project_id
|
12
|
+
@pipeline_id = pipeline_id
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch
|
16
|
+
client.pipeline_jobs(project_id, pipeline_id, scope: 'failed')
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :token, :project_id, :pipeline_id
|
22
|
+
|
23
|
+
def client
|
24
|
+
@client ||= Gitlab.client(
|
25
|
+
endpoint: Runtime::Env.gitlab_api_base,
|
26
|
+
private_token: token
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -167,9 +167,7 @@ module GitlabQuality
|
|
167
167
|
def pipeline_issues_with_similar_stacktrace(test)
|
168
168
|
search_labels = (base_issue_labels + Set.new(%w[test failure::new])).to_a
|
169
169
|
not_labels = exclude_labels_for_search.to_a
|
170
|
-
|
171
|
-
not: { labels: not_labels },
|
172
|
-
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|
|
173
171
|
job_url_from_issue = failed_issue_job_url(issue)
|
174
172
|
|
175
173
|
next if pipeline != pipeline_env_from_job_url(job_url_from_issue)
|
@@ -196,6 +194,7 @@ module GitlabQuality
|
|
196
194
|
def failure_issues(test)
|
197
195
|
find_issues_for_test(
|
198
196
|
test,
|
197
|
+
state: 'opened',
|
199
198
|
labels: base_issue_labels + Set.new(%w[test]),
|
200
199
|
not_labels: exclude_labels_for_search
|
201
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 =
|
79
|
+
issues = slow_test_issues(test)
|
72
80
|
|
73
81
|
if issues.blank?
|
74
82
|
issues << create_issue(test)
|
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.
|
4
|
+
version: 1.9.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-
|
11
|
+
date: 2023-12-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: climate_control
|
@@ -383,6 +383,8 @@ files:
|
|
383
383
|
- exe/update-screenshot-paths
|
384
384
|
- lefthook.yml
|
385
385
|
- lib/gitlab_quality/test_tooling.rb
|
386
|
+
- lib/gitlab_quality/test_tooling/failed_jobs_table.rb
|
387
|
+
- lib/gitlab_quality/test_tooling/gitlab_client/failed_jobs.rb
|
386
388
|
- lib/gitlab_quality/test_tooling/gitlab_client/merge_request.rb
|
387
389
|
- lib/gitlab_quality/test_tooling/gitlab_client/merge_request_dry_client.rb
|
388
390
|
- lib/gitlab_quality/test_tooling/gitlab_issue_client.rb
|