gitlab_quality-test_tooling 0.2.2 → 0.3.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 +16 -10
- data/exe/generate-test-session +7 -3
- data/exe/prepare-stage-reports +2 -2
- data/exe/relate-failure-issue +5 -5
- data/exe/report-results +10 -4
- data/exe/update-screenshot-paths +2 -2
- data/lib/gitlab_quality/test_tooling/report/generate_test_session.rb +8 -5
- data/lib/gitlab_quality/test_tooling/report/prepare_stage_reports.rb +6 -6
- data/lib/gitlab_quality/test_tooling/report/report_results.rb +3 -3
- data/lib/gitlab_quality/test_tooling/report/update_screenshot_path.rb +7 -7
- data/lib/gitlab_quality/test_tooling/runtime/env.rb +5 -4
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +2 -3
- data/lib/gitlab_quality/test_tooling/runtime/token_finder.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d279ff4333f75a706c86e3eced4a8b95c7612be05b740479ea032b8c7f49a62
|
4
|
+
data.tar.gz: 92783c9acf4188c3dc781c097f3d25073fc70abab6c503a4c8802a06fda1cfb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b0a7ab6ab95bb9356ddc3a5276a1b81083fe2056d102fc284d56e9b64890dcac5e76548f85dad95823bb0d1f8ceb1dc0ef0e4cb3e30ef7aad0ca11764a27b44
|
7
|
+
data.tar.gz: c6b06b7040e97db27912113cab68d0161d51d311efe7ae7f5fb81b5f6ef55d7aec0a9d8df310f40f109b5a94d099e0e2be2e617a8119066f967e9efeaeb84a81
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -31,9 +31,11 @@ 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
|
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
|
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
|
37
39
|
--dry-run Perform a dry-run (don't create or update issues or test cases)
|
38
40
|
-v, --version Show the version
|
39
41
|
-h, --help Show the usage
|
@@ -63,7 +65,7 @@ Usage: exe/post-to-slack [options]
|
|
63
65
|
$ exe/prepare-stage-reports -h
|
64
66
|
Purpose: Prepare separate reports for each DevOps stage from the provided RSpec report files (JUnit XML)
|
65
67
|
Usage: exe/prepare-stage-reports [options]
|
66
|
-
-
|
68
|
+
-i, --input-files INPUT_FILES RSpec report files (JUnit XML)
|
67
69
|
-v, --version Show the version
|
68
70
|
-h, --help Show the usage
|
69
71
|
```
|
@@ -74,10 +76,11 @@ Usage: exe/prepare-stage-reports [options]
|
|
74
76
|
$ exe/relate-failure-issue -h
|
75
77
|
Purpose: Relate test failures to failure issues from RSpec report files (JSON or JUnit XML)
|
76
78
|
Usage: exe/relate-failure-issue [options]
|
77
|
-
-i, --input-files
|
78
|
-
--max-diff-ratio
|
79
|
+
-i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
|
80
|
+
--max-diff-ratio MAX_DIFF_RATO
|
81
|
+
Max stacktrace diff ratio for QA failure issues detection
|
79
82
|
-p, --project PROJECT Can be an integer or a group/project string
|
80
|
-
-t, --token
|
83
|
+
-t, --token TOKEN A valid access token with `api` scope and Reporter permission in PROJECT
|
81
84
|
--system-log-files SYSTEM_LOG_FILES
|
82
85
|
Include errors from system logs in failure issues
|
83
86
|
--dry-run Perform a dry-run (don't create or update issues)
|
@@ -91,13 +94,16 @@ Usage: exe/relate-failure-issue [options]
|
|
91
94
|
$ exe/report-results -h
|
92
95
|
Purpose: Report test results from RSpec report files (JSON or JUnit XML) in GitLab test cases and result issues
|
93
96
|
Usage: exe/report-results [options]
|
94
|
-
-i, --input-files
|
97
|
+
-i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
|
95
98
|
--test-case-project TEST_CASE_PROJECT
|
96
99
|
Can be an integer or a group/project string
|
100
|
+
-t TEST_CASE_PROJECT_TOKEN, A valid access token with `api` scope and Reporter permission in TEST_CASE_PROJECT
|
101
|
+
--test-case-project-token
|
97
102
|
--results-issue-project RESULTS_ISSUE_PROJECT
|
98
103
|
Can be an integer or a group/project string
|
99
|
-
-
|
100
|
-
--
|
104
|
+
-r RESULTS_ISSUE_PROJECT_TOKEN, A valid access token with `api` scope and Reporter permission in RESULTS_ISSUE_PROJECT
|
105
|
+
--results-issue-project-token
|
106
|
+
--dry-run Perform a dry-run (don't create/update issues or test cases)
|
101
107
|
-v, --version Show the version
|
102
108
|
-h, --help Show the usage
|
103
109
|
```
|
@@ -108,7 +114,7 @@ Usage: exe/report-results [options]
|
|
108
114
|
$ exe/update-screenshot-paths -h
|
109
115
|
Purpose: Update the path to screenshots to container's host from RSpec report files (JSON or JUnit XML)
|
110
116
|
Usage: exe/update-screenshot-paths [options]
|
111
|
-
-i, --input-files
|
117
|
+
-i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
|
112
118
|
-v, --version Show the version
|
113
119
|
-h, --help Show the usage
|
114
120
|
```
|
data/exe/generate-test-session
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
|
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,12 @@ options = OptionParser.new do |opts|
|
|
19
19
|
params[:project] = project
|
20
20
|
end
|
21
21
|
|
22
|
-
opts.on('-t', '--token
|
23
|
-
params[: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
|
24
28
|
end
|
25
29
|
|
26
30
|
opts.on('--dry-run', "Perform a dry-run (don't create or update issues or test cases)") do
|
data/exe/prepare-stage-reports
CHANGED
@@ -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('-
|
15
|
-
params[:
|
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
|
data/exe/relate-failure-issue
CHANGED
@@ -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
|
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
|
19
|
-
params[:max_diff_ratio] =
|
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
|
27
|
-
params[: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
|
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('-
|
29
|
-
|
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
|
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
|
|
data/exe/update-screenshot-paths
CHANGED
@@ -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
|
15
|
-
params[:
|
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
|
-
|
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
|
-
|
84
|
+
ci_project_client = Gitlab.client(
|
82
85
|
endpoint: Runtime::Env.ci_api_v4_url,
|
83
|
-
private_token:
|
86
|
+
private_token: ci_project_token)
|
84
87
|
|
85
88
|
gitlab.handle_gitlab_client_exceptions do
|
86
|
-
failed_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(
|
12
|
-
@
|
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 :
|
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(
|
32
|
-
.each_with_object(Hash.new { |h, k| h[k] = [] }) do |
|
33
|
-
report = Nokogiri::XML(File.open(
|
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
|
-
|
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:
|
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:
|
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(
|
12
|
-
@
|
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(
|
20
|
-
match_data =
|
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(
|
26
|
-
rewrite_schreenshot_paths_in_json_file(
|
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 :
|
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') ||
|
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
|
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.
|
4
|
+
version: 0.3.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-
|
11
|
+
date: 2023-05-11 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
|