gitlab_quality-test_tooling 1.8.0 → 1.9.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: 4ee3407afd5274be75c1bb63c7f7aeeb0d2353cf62f0fb75c1393bd2103c8c1e
4
- data.tar.gz: a4965dd9d979a58c4202c6f25315d60e08d597d51322db491a077a0ae797cf34
3
+ metadata.gz: d7c32e6b11eb72bf1f453827d3c8c0dd98a8d37788c22000566fac4fe9b0daab
4
+ data.tar.gz: 573ea110d2d1bea41f217f135f6dfe57a814ecc261142813e4dbbda17f813e0e
5
5
  SHA512:
6
- metadata.gz: 1619807ec2456f02c9d4a1c09dfb0aeba598de7d51fe7a0377c1e5a9f3f9fc82cf607fa34387bb5ee1691ad28b5637e75c18c38ce068269c3bba76e3c902df22
7
- data.tar.gz: '0940057d402dfb8fbcd3a6d2d09f7ff698e26d140ebdda659fcc5347445574fa7f398b2bd91e8a39c872b0f8a9f368fa1f734e59e10262790ed2d507fb97e514'
6
+ metadata.gz: b7f5b809cd506c860edba93bc45c932183106da000b2eb14ae7149aa5d7a820502971fd5a26747664be1921334af3b1041a668fb128f8b4c739507ac63f850f2
7
+ data.tar.gz: 1a428ce49770515622c810bfaf2e918df2223b7ed23f38958d994de6bef4c591c5fd10efc7be071d1fdf6cde38eacc8598126b612fde62c300a01c0e9608c83a
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (1.8.0)
4
+ gitlab_quality-test_tooling (1.9.0)
5
5
  activesupport (>= 6.1, < 7.2)
6
6
  amatch (~> 0.4.1)
7
7
  gitlab (~> 4.19)
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-issue [options]
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
- --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)
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-issue [options]
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 note)
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
- --project PROJECT Can be an integer or a group/project string
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 issues)
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
- params[:message] = message
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
- params[:message] += "\n\n#{GitlabQuality::TestTooling::SummaryTable.create(input_files: files)}"
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
- gitlab.find_issues(options: { labels: search_labels,
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 = 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)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "1.8.0"
5
+ VERSION = "1.9.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.8.0
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-30 00:00:00.000000000 Z
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