gitlab_quality-test_tooling 0.2.2 → 0.4.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: b6aca93da1e251be67dab8c377c542ddfdba84392efb41949b62b42fabb283d3
4
- data.tar.gz: 32d0c338138afaeaf0f47a38cced840387ed07c55e63631847bc59a3bfb20842
3
+ metadata.gz: 4e917eea87f25727b389510a47d70ec930f02c201acf889efcb43b89b3d7060e
4
+ data.tar.gz: c7be66d7d4fdec18b8814c010e58a8a95474d9e6977e787c3b673d65892ea07c
5
5
  SHA512:
6
- metadata.gz: 3af4b645bb8c495ed38ce06964de0008e31fbd2a097f374339874aa9f7d9b1967cd6b7c3fae7ad46188120ece0103058864e9601a68e38812002529df6ac89c0
7
- data.tar.gz: 6c1670e30153abb2af66e098c6a89fc13140d71bf1b7aa82ed06793006c8c702bfd5d4345ced0737168f7efb6c288734828a1726a905e16d4d97f2785bc9692b
6
+ metadata.gz: 53b9854fb10540f4bff43a820f9fb4b13d6cd6f9e551390c0fba36a1a5a82db00bd701b84ffd4039b574c1d0504923232507428c2101bd61f893518ae6185fa0
7
+ data.tar.gz: 0d8847faab298bf0c9ed4a3174cc8bfa6d82c1392dd87cbe7ea8f5c88d48ace766d5018c14faeb4bb936236d027eed33e82b6744daaf527850726779da3fa433
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (0.2.2)
4
+ gitlab_quality-test_tooling (0.4.0)
5
5
  activesupport (~> 6.1)
6
6
  gitlab (~> 4.18.0)
7
7
  http (~> 5.0)
data/README.md CHANGED
@@ -31,9 +31,13 @@ The gem provides the following executables.
31
31
  ```shell
32
32
  Purpose: Generate test session report based on RSpec report files (JSON or JUnit XML)
33
33
  Usage: exe/generate-test-session [options]
34
- -i, --input-files FILES RSpec report files (JSON or JUnit XML)
34
+ -i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
35
35
  -p, --project PROJECT Can be an integer or a group/project string
36
- -t, --token ACCESS_TOKEN A valid access token with Reporter permission in PROJECT
36
+ -t, --token TOKEN A valid access token with `api` scope and Reporter permission in PROJECT
37
+ -c CI_PROJECT_TOKEN, A valid access token with `read_api` scope permission in current ENV["CI_PROJECT_ID"]
38
+ --ci-project-token
39
+ -f ISSUE_URL_FILE, Output the created test session issue URL
40
+ --issue-url-file
37
41
  --dry-run Perform a dry-run (don't create or update issues or test cases)
38
42
  -v, --version Show the version
39
43
  -h, --help Show the usage
@@ -63,7 +67,7 @@ Usage: exe/post-to-slack [options]
63
67
  $ exe/prepare-stage-reports -h
64
68
  Purpose: Prepare separate reports for each DevOps stage from the provided RSpec report files (JUnit XML)
65
69
  Usage: exe/prepare-stage-reports [options]
66
- -j, --junit-files FILES RSpec report files (JUnit XML)
70
+ -i, --input-files INPUT_FILES RSpec report files (JUnit XML)
67
71
  -v, --version Show the version
68
72
  -h, --help Show the usage
69
73
  ```
@@ -74,10 +78,11 @@ Usage: exe/prepare-stage-reports [options]
74
78
  $ exe/relate-failure-issue -h
75
79
  Purpose: Relate test failures to failure issues from RSpec report files (JSON or JUnit XML)
76
80
  Usage: exe/relate-failure-issue [options]
77
- -i, --input-files FILES RSpec report files (JSON or JUnit XML)
78
- --max-diff-ratio DIFF_RATO Max stacktrace diff ratio for QA failure issues detection
81
+ -i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
82
+ --max-diff-ratio MAX_DIFF_RATO
83
+ Max stacktrace diff ratio for QA failure issues detection
79
84
  -p, --project PROJECT Can be an integer or a group/project string
80
- -t, --token ACCESS_TOKEN A valid access token with Reporter permission in PROJECT
85
+ -t, --token TOKEN A valid access token with `api` scope and Reporter permission in PROJECT
81
86
  --system-log-files SYSTEM_LOG_FILES
82
87
  Include errors from system logs in failure issues
83
88
  --dry-run Perform a dry-run (don't create or update issues)
@@ -91,13 +96,16 @@ Usage: exe/relate-failure-issue [options]
91
96
  $ exe/report-results -h
92
97
  Purpose: Report test results from RSpec report files (JSON or JUnit XML) in GitLab test cases and result issues
93
98
  Usage: exe/report-results [options]
94
- -i, --input-files FILES RSpec report files (JSON or JUnit XML)
99
+ -i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
95
100
  --test-case-project TEST_CASE_PROJECT
96
101
  Can be an integer or a group/project string
102
+ -t TEST_CASE_PROJECT_TOKEN, A valid access token with `api` scope and Reporter permission in TEST_CASE_PROJECT
103
+ --test-case-project-token
97
104
  --results-issue-project RESULTS_ISSUE_PROJECT
98
105
  Can be an integer or a group/project string
99
- -t, --token ACCESS_TOKEN A valid access token
100
- --dry-run Perform a dry-run (don't create or update issues or test cases)
106
+ -r RESULTS_ISSUE_PROJECT_TOKEN, A valid access token with `api` scope and Reporter permission in RESULTS_ISSUE_PROJECT
107
+ --results-issue-project-token
108
+ --dry-run Perform a dry-run (don't create/update issues or test cases)
101
109
  -v, --version Show the version
102
110
  -h, --help Show the usage
103
111
  ```
@@ -108,7 +116,7 @@ Usage: exe/report-results [options]
108
116
  $ exe/update-screenshot-paths -h
109
117
  Purpose: Update the path to screenshots to container's host from RSpec report files (JSON or JUnit XML)
110
118
  Usage: exe/update-screenshot-paths [options]
111
- -i, --input-files FILES RSpec report files (JSON or JUnit XML)
119
+ -i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
112
120
  -v, --version Show the version
113
121
  -h, --help Show the usage
114
122
  ```
@@ -11,7 +11,7 @@ params = {}
11
11
  options = OptionParser.new do |opts|
12
12
  opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
13
13
 
14
- opts.on('-i', '--input-files FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
14
+ opts.on('-i', '--input-files INPUT_FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
15
15
  params[:input_files] = input_files
16
16
  end
17
17
 
@@ -19,8 +19,16 @@ options = OptionParser.new do |opts|
19
19
  params[:project] = project
20
20
  end
21
21
 
22
- opts.on('-t', '--token ACCESS_TOKEN', String, 'A valid access token with Reporter permission in PROJECT') do |token|
23
- params[:token] = GitlabQuality::TestTooling::Runtime::TokenFinder.find_token!(token)
22
+ opts.on('-t', '--token TOKEN', String, 'A valid access token with `api` scope and Reporter permission in PROJECT') do |token|
23
+ params[:token] = token
24
+ end
25
+
26
+ opts.on('-c', '--ci-project-token CI_PROJECT_TOKEN', String, 'A valid access token with `read_api` scope permission in current ENV["CI_PROJECT_ID"]') do |ci_project_token|
27
+ params[:ci_project_token] = ci_project_token
28
+ end
29
+
30
+ opts.on('-f', '--issue-url-file ISSUE_URL_FILE', 'Output the created test session issue URL') do |issue_url_file|
31
+ params[:issue_url_file] = issue_url_file
24
32
  end
25
33
 
26
34
  opts.on('--dry-run', "Perform a dry-run (don't create or update issues or test cases)") do
@@ -42,8 +50,12 @@ options = OptionParser.new do |opts|
42
50
  opts.parse(ARGV)
43
51
  end
44
52
 
53
+ issue_url_file = params.delete(:issue_url_file)
54
+
45
55
  if params.any?
46
- GitlabQuality::TestTooling::Report::GenerateTestSession.new(**params).invoke!
56
+ issue_url = GitlabQuality::TestTooling::Report::GenerateTestSession.new(**params).invoke!
57
+
58
+ File.write(issue_url_file, issue_url) if issue_url_file && issue_url
47
59
  else
48
60
  puts options
49
61
  exit 1
@@ -11,8 +11,8 @@ params = {}
11
11
  options = OptionParser.new do |opts|
12
12
  opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
13
13
 
14
- opts.on('-j', '--junit-files FILES', String, 'RSpec report files (JUnit XML)') do |junit_files|
15
- params[:junit_files] = junit_files
14
+ opts.on('-i', '--input-files INPUT_FILES', String, 'RSpec report files (JUnit XML)') do |input_files|
15
+ params[:input_files] = input_files
16
16
  end
17
17
 
18
18
  opts.on_tail('-v', '--version', 'Show the version') do
@@ -11,20 +11,20 @@ params = {}
11
11
  options = OptionParser.new do |opts|
12
12
  opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
13
13
 
14
- opts.on('-i', '--input-files FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
14
+ opts.on('-i', '--input-files INPUT_FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
15
15
  params[:input_files] = input_files
16
16
  end
17
17
 
18
- opts.on('--max-diff-ratio DIFF_RATO', Float, 'Max stacktrace diff ratio for QA failure issues detection') do |value|
19
- params[:max_diff_ratio] = value
18
+ opts.on('--max-diff-ratio MAX_DIFF_RATO', Float, 'Max stacktrace diff ratio for QA failure issues detection') do |max_diff_ratio|
19
+ params[:max_diff_ratio] = max_diff_ratio
20
20
  end
21
21
 
22
22
  opts.on('-p', '--project PROJECT', String, 'Can be an integer or a group/project string') do |project|
23
23
  params[:project] = project
24
24
  end
25
25
 
26
- opts.on('-t', '--token ACCESS_TOKEN', String, 'A valid access token with Reporter permission in PROJECT') do |token|
27
- params[:token] = GitlabQuality::TestTooling::Runtime::TokenFinder.find_token!(token)
26
+ opts.on('-t', '--token TOKEN', String, 'A valid access token with `api` scope and Reporter permission in PROJECT') do |token|
27
+ params[:token] = token
28
28
  end
29
29
 
30
30
  opts.on('--system-log-files SYSTEM_LOG_FILES', String,
data/exe/report-results CHANGED
@@ -11,7 +11,7 @@ params = {}
11
11
  options = OptionParser.new do |opts|
12
12
  opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
13
13
 
14
- opts.on('-i', '--input-files FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
14
+ opts.on('-i', '--input-files INPUT_FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
15
15
  params[:input_files] = input_files
16
16
  end
17
17
 
@@ -20,16 +20,22 @@ options = OptionParser.new do |opts|
20
20
  params[:test_case_project] = test_case_project
21
21
  end
22
22
 
23
+ opts.on('-t', '--test-case-project-token TEST_CASE_PROJECT_TOKEN', String,
24
+ 'A valid access token with `api` scope and Reporter permission in TEST_CASE_PROJECT') do |test_case_project_token|
25
+ params[:test_case_project_token] = test_case_project_token
26
+ end
27
+
23
28
  opts.on('--results-issue-project RESULTS_ISSUE_PROJECT', String,
24
29
  'Can be an integer or a group/project string') do |results_issue_project|
25
30
  params[:results_issue_project] = results_issue_project
26
31
  end
27
32
 
28
- opts.on('-t', '--token ACCESS_TOKEN', String, 'A valid access token') do |token|
29
- params[:token] = GitlabQuality::TestTooling::Runtime::TokenFinder.find_token!(token)
33
+ opts.on('-r', '--results-issue-project-token RESULTS_ISSUE_PROJECT_TOKEN', String,
34
+ 'A valid access token with `api` scope and Reporter permission in RESULTS_ISSUE_PROJECT') do |results_issue_project_token|
35
+ params[:results_issue_project_token] = results_issue_project_token
30
36
  end
31
37
 
32
- opts.on('--dry-run', "Perform a dry-run (don't create or update issues or test cases)") do
38
+ opts.on('--dry-run', "Perform a dry-run (don't create/update issues or test cases)") do
33
39
  params[:dry_run] = true
34
40
  end
35
41
 
@@ -11,8 +11,8 @@ params = {}
11
11
  options = OptionParser.new do |opts|
12
12
  opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
13
13
 
14
- opts.on('-i', '--input-files FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
15
- params[:junit_files] = input_files
14
+ opts.on('-i', '--input-files INPUT_FILES', String, 'RSpec report files (JSON or JUnit XML)') do |input_files|
15
+ params[:input_files] = input_files
16
16
  end
17
17
 
18
18
  opts.on_tail('-v', '--version', 'Show the version') do
@@ -7,13 +7,16 @@ module GitlabQuality
7
7
  module TestTooling
8
8
  module Report
9
9
  class GenerateTestSession < ReportAsIssue
10
- def initialize(**kwargs)
10
+ def initialize(ci_project_token:, **kwargs)
11
11
  super
12
+ @ci_project_token = ci_project_token
12
13
  @issue_type = 'issue'
13
14
  end
14
15
 
15
16
  private
16
17
 
18
+ attr_reader :ci_project_token
19
+
17
20
  # rubocop:disable Metrics/AbcSize
18
21
  def run!
19
22
  puts "Generating test results in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
@@ -37,7 +40,7 @@ module GitlabQuality
37
40
  note: "/relate #{Runtime::Env.qa_issue_url}")
38
41
  end
39
42
 
40
- File.write('REPORT_ISSUE_URL', issue.web_url)
43
+ issue&.web_url # Issue isn't created in dry-run mode
41
44
  end
42
45
  # rubocop:enable Metrics/AbcSize
43
46
 
@@ -78,12 +81,12 @@ module GitlabQuality
78
81
  def generate_failed_jobs_listing
79
82
  failed_jobs = []
80
83
 
81
- client = Gitlab.client(
84
+ ci_project_client = Gitlab.client(
82
85
  endpoint: Runtime::Env.ci_api_v4_url,
83
- private_token: Runtime::Env.gitlab_ci_api_token)
86
+ private_token: ci_project_token)
84
87
 
85
88
  gitlab.handle_gitlab_client_exceptions do
86
- failed_jobs = client.pipeline_jobs(
89
+ failed_jobs = ci_project_client.pipeline_jobs(
87
90
  Runtime::Env.ci_project_id,
88
91
  Runtime::Env.ci_pipeline_id,
89
92
  scope: 'failed')
@@ -8,8 +8,8 @@ module GitlabQuality
8
8
  class PrepareStageReports
9
9
  EXTRACT_STAGE_FROM_TEST_FILE_REGEX = %r{(?:api|browser_ui)/(?:[0-9]+_)?(?<stage>[_\w]+)/}i
10
10
 
11
- def initialize(junit_files:)
12
- @junit_files = junit_files
11
+ def initialize(input_files:)
12
+ @input_files = input_files
13
13
  end
14
14
 
15
15
  def invoke!
@@ -24,13 +24,13 @@ module GitlabQuality
24
24
 
25
25
  private
26
26
 
27
- attr_reader :junit_files
27
+ attr_reader :input_files
28
28
 
29
29
  # Collect the test cases from the original reports and group them by Stage
30
30
  def collate_test_cases
31
- Dir.glob(junit_files)
32
- .each_with_object(Hash.new { |h, k| h[k] = [] }) do |junit_file, test_cases|
33
- report = Nokogiri::XML(File.open(junit_file))
31
+ Dir.glob(input_files)
32
+ .each_with_object(Hash.new { |h, k| h[k] = [] }) do |input_file, test_cases|
33
+ report = Nokogiri::XML(File.open(input_file))
34
34
  report.xpath('//testcase').each do |test_case|
35
35
  # The test file paths could start with any of
36
36
  # /qa/specs/features/api/<stage>
@@ -12,12 +12,12 @@ module GitlabQuality
12
12
  :results_issue_project, :gitlab
13
13
 
14
14
  def initialize(
15
- token:, input_files:, test_case_project: nil, results_issue_project: nil, dry_run: false,
15
+ test_case_project_token:, results_issue_project_token:, input_files:, test_case_project: nil, results_issue_project: nil, dry_run: false,
16
16
  **kwargs)
17
17
  @testcase_project_reporter = GitlabQuality::TestTooling::Report::ResultsInTestCases.new(
18
- token: token, input_files: input_files, project: test_case_project, dry_run: dry_run, **kwargs)
18
+ token: test_case_project_token, input_files: input_files, project: test_case_project, dry_run: dry_run, **kwargs)
19
19
  @results_issue_project_reporter = GitlabQuality::TestTooling::Report::ResultsInIssues.new(
20
- token: token, input_files: input_files, project: results_issue_project, dry_run: dry_run, **kwargs)
20
+ token: results_issue_project_token, input_files: input_files, project: results_issue_project, dry_run: dry_run, **kwargs)
21
21
  @test_case_project = test_case_project
22
22
  @results_issue_project = results_issue_project
23
23
  @files = Array(input_files)
@@ -8,28 +8,28 @@ module GitlabQuality
8
8
  module TestTooling
9
9
  module Report
10
10
  class UpdateScreenshotPath
11
- def initialize(junit_files:)
12
- @junit_files = junit_files
11
+ def initialize(input_files:)
12
+ @input_files = input_files
13
13
  end
14
14
 
15
15
  REGEX = %r{(?<gitlab_qa_run>gitlab-qa-run-.*?(?=/))/(?<gitlab_ce_ee_qa>gitlab-(?:ee|ce)-qa-.*?(?=/))}
16
16
  CONTAINER_PATH = File.join('/home', 'gitlab', 'qa', 'tmp').freeze
17
17
 
18
18
  def invoke!
19
- Dir.glob(junit_files).each do |junit_file|
20
- match_data = junit_file.match(REGEX)
19
+ Dir.glob(input_files).each do |input_file|
20
+ match_data = input_file.match(REGEX)
21
21
  next unless match_data
22
22
 
23
23
  host_relative_path = "#{match_data[:gitlab_qa_run]}/#{match_data[:gitlab_ce_ee_qa]}"
24
24
 
25
- rewrite_schreenshot_paths_in_junit_file(junit_file, host_relative_path)
26
- rewrite_schreenshot_paths_in_json_file(junit_file.gsub('.xml', '.json'), host_relative_path)
25
+ rewrite_schreenshot_paths_in_junit_file(input_file, host_relative_path)
26
+ rewrite_schreenshot_paths_in_json_file(input_file.gsub('.xml', '.json'), host_relative_path)
27
27
  end
28
28
  end
29
29
 
30
30
  private
31
31
 
32
- attr_reader :junit_files
32
+ attr_reader :input_files
33
33
 
34
34
  def rewrite_schreenshot_paths_in_junit_file(junit_file, host_relative_path)
35
35
  File.write(
@@ -11,9 +11,7 @@ module GitlabQuality
11
11
  using Rainbow
12
12
 
13
13
  ENV_VARIABLES = {
14
- 'GITLAB_API_BASE' => :api_base,
15
14
  'GITLAB_QA_ISSUE_URL' => :qa_issue_url,
16
- 'GITLAB_CI_API_TOKEN' => :gitlab_ci_api_token,
17
15
  'CI_COMMIT_REF_NAME' => :ci_commit_ref_name,
18
16
  'CI_JOB_NAME' => :ci_job_name,
19
17
  'CI_JOB_URL' => :ci_job_url,
@@ -21,7 +19,6 @@ module GitlabQuality
21
19
  'CI_PROJECT_NAME' => :ci_project_name,
22
20
  'CI_PIPELINE_ID' => :ci_pipeline_id,
23
21
  'CI_PIPELINE_URL' => :ci_pipeline_url,
24
- 'CI_API_V4_URL' => :ci_api_v4_url,
25
22
  'SLACK_QA_CHANNEL' => :slack_qa_channel,
26
23
  'DEPLOY_VERSION' => :deploy_version
27
24
  }.freeze
@@ -44,8 +41,12 @@ module GitlabQuality
44
41
  env_var_value_if_defined('QA_DEFAULT_BRANCH') || 'main'
45
42
  end
46
43
 
44
+ def ci_api_v4_url
45
+ env_var_value_if_defined('CI_API_V4_URL') || 'https://gitlab.com/api/v4'
46
+ end
47
+
47
48
  def gitlab_api_base
48
- env_var_value_if_defined('GITLAB_API_BASE') || 'https://gitlab.com/api/v4'
49
+ env_var_value_if_defined('GITLAB_API_BASE') || ci_api_v4_url
49
50
  end
50
51
 
51
52
  def pipeline_from_project_name
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "0.2.2"
5
+ VERSION = "0.4.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: 0.2.2
4
+ version: 0.4.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-05-10 00:00:00.000000000 Z
11
+ date: 2023-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control
@@ -357,7 +357,6 @@ files:
357
357
  - lib/gitlab_quality/test_tooling/report/update_screenshot_path.rb
358
358
  - lib/gitlab_quality/test_tooling/runtime/env.rb
359
359
  - lib/gitlab_quality/test_tooling/runtime/logger.rb
360
- - lib/gitlab_quality/test_tooling/runtime/token_finder.rb
361
360
  - lib/gitlab_quality/test_tooling/slack/post_to_slack.rb
362
361
  - lib/gitlab_quality/test_tooling/summary_table.rb
363
362
  - lib/gitlab_quality/test_tooling/support/http_request.rb
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GitlabQuality
4
- module TestTooling
5
- module Runtime
6
- class TokenFinder
7
- def self.find_token!(token, suffix: nil)
8
- new(token, suffix).find_token!
9
- end
10
-
11
- attr_reader :token, :suffix
12
-
13
- def initialize(token, suffix)
14
- @token = token
15
- @suffix = suffix
16
- end
17
-
18
- def find_token!
19
- find_token_from_attrs || find_token_from_env || find_token_from_file
20
- end
21
-
22
- def find_token_from_attrs
23
- token
24
- end
25
-
26
- def find_token_from_env
27
- Env.gitlab_ci_api_token
28
- end
29
-
30
- def find_token_from_file
31
- @token_from_file ||= File.read(token_file_path).strip
32
- rescue Errno::ENOENT
33
- fail "Please provide a valid access token with the `-t/--token` option, the `GITLAB_CI_API_TOKEN` environment variable, or in the `#{token_file_path}` file!"
34
- end
35
-
36
- private
37
-
38
- def token_file_path
39
- @token_file_path ||= File.expand_path("../api_token#{"_#{suffix}" if suffix}", __dir__)
40
- end
41
- end
42
- end
43
- end
44
- end