allure-report-publisher 0.0.4 → 0.2.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/README.md +43 -15
- data/lib/allure_report_publisher.rb +2 -5
- data/lib/allure_report_publisher/commands/upload.rb +90 -0
- data/lib/allure_report_publisher/lib/helpers/helpers.rb +1 -1
- data/lib/allure_report_publisher/lib/helpers/spinner.rb +1 -1
- data/lib/allure_report_publisher/lib/providers/{_base.rb → _provider.rb} +48 -38
- data/lib/allure_report_publisher/lib/providers/github.rb +56 -16
- data/lib/allure_report_publisher/lib/providers/gitlab.rb +42 -13
- data/lib/allure_report_publisher/lib/providers/url_section_builder.rb +97 -0
- data/lib/allure_report_publisher/lib/report_generator.rb +10 -13
- data/lib/allure_report_publisher/lib/uploaders/_uploader.rb +84 -63
- data/lib/allure_report_publisher/lib/uploaders/gcs.rb +104 -0
- data/lib/allure_report_publisher/lib/uploaders/{s3_uploader.rb → s3.rb} +15 -25
- data/lib/allure_report_publisher/version.rb +1 -1
- metadata +31 -10
- data/lib/allure_report_publisher/commands/base.rb +0 -21
- data/lib/allure_report_publisher/commands/upload_s3.rb +0 -41
@@ -4,7 +4,7 @@ module Publisher
|
|
4
4
|
module Providers
|
5
5
|
# Gitlab implementation
|
6
6
|
#
|
7
|
-
class Gitlab <
|
7
|
+
class Gitlab < Provider
|
8
8
|
# Get ci run ID without creating instance of ci provider
|
9
9
|
#
|
10
10
|
# @return [String]
|
@@ -12,6 +12,13 @@ module Publisher
|
|
12
12
|
@run_id ||= ENV["CI_PIPELINE_ID"]
|
13
13
|
end
|
14
14
|
|
15
|
+
# Pull request run
|
16
|
+
#
|
17
|
+
# @return [Boolean]
|
18
|
+
def pr?
|
19
|
+
ENV["CI_PIPELINE_SOURCE"] == "merge_request_event"
|
20
|
+
end
|
21
|
+
|
15
22
|
# Get executor info
|
16
23
|
#
|
17
24
|
# @return [Hash]
|
@@ -28,6 +35,8 @@ module Publisher
|
|
28
35
|
}
|
29
36
|
end
|
30
37
|
|
38
|
+
private
|
39
|
+
|
31
40
|
# Current pull request description
|
32
41
|
#
|
33
42
|
# @return [String]
|
@@ -37,10 +46,27 @@ module Publisher
|
|
37
46
|
|
38
47
|
# Update pull request description
|
39
48
|
#
|
40
|
-
# @param [String] desc
|
41
49
|
# @return [void]
|
42
|
-
def update_pr_description
|
43
|
-
client.update_merge_request(project, mr_iid, description:
|
50
|
+
def update_pr_description
|
51
|
+
client.update_merge_request(project, mr_iid, description: report_urls.updated_pr_description(pr_description))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add comment with report url
|
55
|
+
#
|
56
|
+
# @return [void]
|
57
|
+
def add_comment
|
58
|
+
return client.create_merge_request_comment(project, mr_iid, report_urls.comment_body) unless comment
|
59
|
+
|
60
|
+
client.edit_merge_request_note(project, mr_iid, comment.id, report_urls.comment_body(comment.body))
|
61
|
+
end
|
62
|
+
|
63
|
+
# Existing comment with allure urls
|
64
|
+
#
|
65
|
+
# @return [Gitlab::ObjectifiedHash]
|
66
|
+
def comment
|
67
|
+
client.merge_request_comments(project, mr_iid).auto_paginate.detect do |comment|
|
68
|
+
UrlSectionBuilder.match?(comment.body)
|
69
|
+
end
|
44
70
|
end
|
45
71
|
|
46
72
|
# Get gitlab client
|
@@ -57,13 +83,6 @@ module Publisher
|
|
57
83
|
end
|
58
84
|
end
|
59
85
|
|
60
|
-
# Pull request run
|
61
|
-
#
|
62
|
-
# @return [Boolean]
|
63
|
-
def pr?
|
64
|
-
ENV["CI_PIPELINE_SOURCE"] == "merge_request_event"
|
65
|
-
end
|
66
|
-
|
67
86
|
# Merge request iid
|
68
87
|
#
|
69
88
|
# @return [Integer]
|
@@ -89,15 +108,25 @@ module Publisher
|
|
89
108
|
#
|
90
109
|
# @return [String]
|
91
110
|
def build_name
|
92
|
-
@build_name ||= ENV["CI_JOB_NAME"]
|
111
|
+
@build_name ||= ENV[ALLURE_JOB_NAME] || ENV["CI_JOB_NAME"]
|
93
112
|
end
|
94
113
|
|
95
|
-
#
|
114
|
+
# Gitlab repository
|
96
115
|
#
|
97
116
|
# @return [String]
|
98
117
|
def project
|
99
118
|
@project ||= ENV["CI_PROJECT_PATH"]
|
100
119
|
end
|
120
|
+
|
121
|
+
# Commit sha url
|
122
|
+
#
|
123
|
+
# @return [String]
|
124
|
+
def sha_url
|
125
|
+
sha = ENV["CI_MERGE_REQUEST_SOURCE_BRANCH_SHA"] || ENV["CI_COMMIT_SHA"]
|
126
|
+
short_sha = sha[0..7]
|
127
|
+
|
128
|
+
"[#{short_sha}](#{server_url}/#{project}/-/merge_requests/#{mr_iid}/diffs?commit_id=#{sha})"
|
129
|
+
end
|
101
130
|
end
|
102
131
|
end
|
103
132
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Publisher
|
2
|
+
module Providers
|
3
|
+
# Urls section builder
|
4
|
+
#
|
5
|
+
class UrlSectionBuilder
|
6
|
+
DESCRIPTION_PATTERN = /<!-- allure -->[\s\S]+<!-- allurestop -->/.freeze
|
7
|
+
JOBS_PATTERN = /<!-- jobs -->\n([\s\S]+)\n<!-- jobs -->/.freeze
|
8
|
+
|
9
|
+
def initialize(report_url:, build_name:, sha_url:)
|
10
|
+
@report_url = report_url
|
11
|
+
@build_name = build_name
|
12
|
+
@sha_url = sha_url
|
13
|
+
end
|
14
|
+
|
15
|
+
# Matches url section pattern
|
16
|
+
#
|
17
|
+
# @param [String] urls_block
|
18
|
+
# @return [Boolean]
|
19
|
+
def self.match?(urls_block)
|
20
|
+
urls_block.match?(DESCRIPTION_PATTERN)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get urls for PR update
|
24
|
+
#
|
25
|
+
# @param [String] pr
|
26
|
+
# @return [String]
|
27
|
+
def updated_pr_description(pr_description)
|
28
|
+
return "#{pr_description}\n\n#{body}" unless pr_description.match?(DESCRIPTION_PATTERN)
|
29
|
+
|
30
|
+
job_entries = jobs_section(pr_description)
|
31
|
+
pr_description.gsub(DESCRIPTION_PATTERN, body(job_entries))
|
32
|
+
end
|
33
|
+
|
34
|
+
# Allure report url comment
|
35
|
+
#
|
36
|
+
# @return [String]
|
37
|
+
def comment_body(pr_comment = nil)
|
38
|
+
return body.gsub("---\n", "") unless pr_comment
|
39
|
+
|
40
|
+
job_entries = jobs_section(pr_comment)
|
41
|
+
body(job_entries).gsub("---\n", "")
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :report_url, :build_name, :sha_url
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Allure report url pr description
|
49
|
+
#
|
50
|
+
# @return [String]
|
51
|
+
def body(job_entries = "**#{build_name}**: 📝 [allure report](#{report_url})")
|
52
|
+
@body ||= <<~BODY.strip
|
53
|
+
<!-- allure -->
|
54
|
+
---
|
55
|
+
#{heading}
|
56
|
+
|
57
|
+
<!-- jobs -->
|
58
|
+
#{job_entries}
|
59
|
+
<!-- jobs -->
|
60
|
+
<!-- allurestop -->
|
61
|
+
BODY
|
62
|
+
end
|
63
|
+
|
64
|
+
# Url section heading
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
def heading
|
68
|
+
@heading ||= "# Allure report\n`allure-report-publisher` generated allure report for #{sha_url}!"
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return updated jobs section
|
72
|
+
#
|
73
|
+
# @param [String] urls
|
74
|
+
# @return [String]
|
75
|
+
def jobs_section(urls_block)
|
76
|
+
jobs = urls_block.match(JOBS_PATTERN)[1]
|
77
|
+
return jobs.gsub(job_entry_pattern, job_entry) if jobs.match?(job_entry_pattern)
|
78
|
+
|
79
|
+
"#{jobs}\n#{job_entry}"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Single job report URL entry
|
83
|
+
#
|
84
|
+
# @return [String]
|
85
|
+
def job_entry
|
86
|
+
@job_entry ||= "**#{build_name}**: 📝 [allure report](#{report_url})"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Job entry pattern
|
90
|
+
#
|
91
|
+
# @return [RegExp]
|
92
|
+
def job_entry_pattern
|
93
|
+
@job_entry_pattern ||= /^\*\*#{build_name}\*\*:.*\[allure report\]\(.*\)$/
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -10,35 +10,32 @@ module Publisher
|
|
10
10
|
class ReportGenerator
|
11
11
|
include Helpers
|
12
12
|
|
13
|
-
def initialize(results_glob,
|
13
|
+
def initialize(results_glob, results_path, report_path)
|
14
14
|
@results_glob = results_glob
|
15
|
-
@
|
16
|
-
@
|
15
|
+
@results_path = results_path
|
16
|
+
@report_path = report_path
|
17
17
|
end
|
18
18
|
|
19
19
|
# Generate allure report
|
20
20
|
#
|
21
21
|
# @return [void]
|
22
22
|
def generate
|
23
|
-
|
24
|
-
|
25
|
-
aggregate_results
|
26
|
-
generate_report
|
27
|
-
end
|
23
|
+
aggregate_results
|
24
|
+
generate_report
|
28
25
|
end
|
29
26
|
|
30
27
|
private
|
31
28
|
|
32
|
-
attr_reader :results_glob, :
|
29
|
+
attr_reader :results_glob, :results_path, :report_path
|
33
30
|
|
34
31
|
# Copy all results files to results directory
|
35
32
|
#
|
36
33
|
# @return [void]
|
37
34
|
def aggregate_results
|
38
35
|
results = Dir.glob(results_glob)
|
39
|
-
|
36
|
+
raise(NoAllureResultsError, "Missing allure results") if results.empty?
|
40
37
|
|
41
|
-
FileUtils.cp(results,
|
38
|
+
FileUtils.cp(results, results_path)
|
42
39
|
end
|
43
40
|
|
44
41
|
# Generate allure report
|
@@ -46,9 +43,9 @@ module Publisher
|
|
46
43
|
# @return [void]
|
47
44
|
def generate_report
|
48
45
|
out, _err, status = Open3.capture3(
|
49
|
-
"allure generate --clean --output #{
|
46
|
+
"allure generate --clean --output #{report_path} #{results_path}"
|
50
47
|
)
|
51
|
-
|
48
|
+
raise(AllureError, out) unless status.success?
|
52
49
|
end
|
53
50
|
end
|
54
51
|
end
|
@@ -1,10 +1,13 @@
|
|
1
1
|
module Publisher
|
2
2
|
module Uploaders
|
3
|
+
class HistoryNotFoundError < StandardError; end
|
4
|
+
|
3
5
|
# Uploader implementation
|
4
6
|
#
|
5
7
|
class Uploader
|
6
8
|
include Helpers
|
7
9
|
|
10
|
+
EXECUTOR_JSON = "executor.json".freeze
|
8
11
|
HISTORY = [
|
9
12
|
"categories-trend.json",
|
10
13
|
"duration-trend.json",
|
@@ -13,38 +16,76 @@ module Publisher
|
|
13
16
|
"retry-trend.json"
|
14
17
|
].freeze
|
15
18
|
|
16
|
-
def initialize(results_glob:, bucket:, update_pr:
|
19
|
+
def initialize(results_glob:, bucket:, update_pr: nil, prefix: nil, copy_latest: false)
|
17
20
|
@results_glob = results_glob
|
18
|
-
@
|
21
|
+
@bucket_name = bucket
|
19
22
|
@prefix = prefix
|
20
23
|
@update_pr = update_pr
|
21
|
-
@copy_latest = Providers.provider && copy_latest # copy latest for ci only
|
24
|
+
@copy_latest = !!(Providers.provider && copy_latest) # copy latest for ci only
|
22
25
|
end
|
23
26
|
|
24
|
-
# :nocov:
|
25
|
-
|
26
27
|
# Execute allure report generation and upload
|
27
28
|
#
|
28
29
|
# @return [void]
|
29
30
|
def execute
|
30
|
-
|
31
|
-
|
32
|
-
generate
|
31
|
+
generate_report
|
33
32
|
upload
|
34
33
|
add_url_to_pr
|
35
|
-
rescue StandardError => e
|
36
|
-
error(e.message)
|
37
34
|
end
|
38
35
|
|
39
|
-
|
36
|
+
# Generate allure report
|
37
|
+
#
|
38
|
+
# @return [void]
|
39
|
+
def generate_report
|
40
|
+
add_history
|
41
|
+
add_executor_info
|
40
42
|
|
41
|
-
|
43
|
+
ReportGenerator.new(results_glob, results_path, report_path).generate
|
44
|
+
end
|
42
45
|
|
43
|
-
#
|
44
|
-
#
|
46
|
+
# Upload report to storage provider
|
47
|
+
#
|
48
|
+
# @return [void]
|
49
|
+
def upload
|
50
|
+
run_uploads
|
51
|
+
end
|
52
|
+
|
53
|
+
# Add allure report url to pull request description
|
45
54
|
#
|
46
55
|
# @return [void]
|
47
|
-
def
|
56
|
+
def add_url_to_pr
|
57
|
+
return unless update_pr && ci_provider
|
58
|
+
|
59
|
+
ci_provider.add_report_url
|
60
|
+
end
|
61
|
+
|
62
|
+
# Uploaded report urls
|
63
|
+
#
|
64
|
+
# @return [Hash<String, String>] uploaded report urls
|
65
|
+
def report_urls
|
66
|
+
urls = { "Report url" => report_url }
|
67
|
+
urls["Latest report url"] = latest_report_url if copy_latest
|
68
|
+
|
69
|
+
urls
|
70
|
+
end
|
71
|
+
|
72
|
+
# Executed in PR pipeline
|
73
|
+
#
|
74
|
+
# @return [Boolean]
|
75
|
+
def pr?
|
76
|
+
ci_provider&.pr?
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
attr_reader :results_glob, :bucket_name, :prefix, :update_pr, :copy_latest
|
82
|
+
|
83
|
+
# :nocov:
|
84
|
+
|
85
|
+
# Cloud provider client
|
86
|
+
#
|
87
|
+
# @return [Object]
|
88
|
+
def client
|
48
89
|
raise("Not Implemented!")
|
49
90
|
end
|
50
91
|
|
@@ -55,6 +96,20 @@ module Publisher
|
|
55
96
|
raise("Not Implemented!")
|
56
97
|
end
|
57
98
|
|
99
|
+
# Latest report url
|
100
|
+
#
|
101
|
+
# @return [String]
|
102
|
+
def latest_report_url
|
103
|
+
raise("Not Implemented!")
|
104
|
+
end
|
105
|
+
|
106
|
+
# Download allure history
|
107
|
+
#
|
108
|
+
# @return [void]
|
109
|
+
def download_history
|
110
|
+
raise("Not implemented!")
|
111
|
+
end
|
112
|
+
|
58
113
|
# Upload history to s3
|
59
114
|
#
|
60
115
|
# @return [void]
|
@@ -81,11 +136,10 @@ module Publisher
|
|
81
136
|
#
|
82
137
|
# @return [void]
|
83
138
|
def add_history
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
139
|
+
create_history_dir
|
140
|
+
download_history
|
141
|
+
rescue HistoryNotFoundError
|
142
|
+
nil
|
89
143
|
end
|
90
144
|
|
91
145
|
# Add CI executor info
|
@@ -94,53 +148,20 @@ module Publisher
|
|
94
148
|
def add_executor_info
|
95
149
|
return unless ci_provider
|
96
150
|
|
97
|
-
|
98
|
-
|
99
|
-
ci_provider.write_executor_info
|
151
|
+
File.open("#{results_path}/#{EXECUTOR_JSON}", "w") do |file|
|
152
|
+
file.write(ci_provider.executor_info.to_json)
|
100
153
|
end
|
101
154
|
end
|
102
155
|
|
103
|
-
# Generate allure report
|
104
|
-
#
|
105
|
-
# @return [void]
|
106
|
-
def generate
|
107
|
-
add_history
|
108
|
-
add_executor_info
|
109
|
-
|
110
|
-
ReportGenerator.new(results_glob, results_dir, report_dir).generate
|
111
|
-
end
|
112
|
-
|
113
|
-
# Upload report to storage provider
|
114
|
-
#
|
115
|
-
# @return [void]
|
116
|
-
def upload
|
117
|
-
log("Uploading report")
|
118
|
-
Helpers::Spinner.spin("uploading report") { run_uploads }
|
119
|
-
log("Run report: #{report_url}", :green)
|
120
|
-
log("Latest report: #{latest_report_url}", :green) if copy_latest
|
121
|
-
end
|
122
|
-
|
123
156
|
# Run upload commands
|
124
157
|
#
|
125
158
|
# @return [void]
|
126
159
|
def run_uploads
|
127
|
-
upload_history unless
|
160
|
+
upload_history unless !run_id || copy_latest
|
128
161
|
upload_report
|
129
162
|
upload_latest_copy if copy_latest
|
130
163
|
end
|
131
164
|
|
132
|
-
# Add allure report url to pull request description
|
133
|
-
#
|
134
|
-
# @return [void]
|
135
|
-
def add_url_to_pr
|
136
|
-
return unless update_pr && ci_provider
|
137
|
-
|
138
|
-
log("Adding allure report link to pr description")
|
139
|
-
Helpers::Spinner.spin("adding link", exit_on_error: false) do
|
140
|
-
ci_provider.add_report_url
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
165
|
# Get run id
|
145
166
|
#
|
146
167
|
# @return [String]
|
@@ -154,14 +175,14 @@ module Publisher
|
|
154
175
|
def ci_provider
|
155
176
|
return @ci_provider if defined?(@ci_provider)
|
156
177
|
|
157
|
-
@ci_provider = Providers.provider&.new(
|
178
|
+
@ci_provider = Providers.provider&.new(report_url: report_url, update_pr: update_pr)
|
158
179
|
end
|
159
180
|
|
160
181
|
# Fetch allure report history
|
161
182
|
#
|
162
183
|
# @return [void]
|
163
184
|
def create_history_dir
|
164
|
-
FileUtils.mkdir_p(path(
|
185
|
+
FileUtils.mkdir_p(path(results_path, "history"))
|
165
186
|
end
|
166
187
|
|
167
188
|
# Report path prefix
|
@@ -178,15 +199,15 @@ module Publisher
|
|
178
199
|
# Aggregated results directory
|
179
200
|
#
|
180
201
|
# @return [String]
|
181
|
-
def
|
182
|
-
@
|
202
|
+
def results_path
|
203
|
+
@results_path ||= Dir.mktmpdir("allure-results")
|
183
204
|
end
|
184
205
|
|
185
206
|
# Allure report directory
|
186
207
|
#
|
187
208
|
# @return [String]
|
188
|
-
def
|
189
|
-
@
|
209
|
+
def report_path
|
210
|
+
@report_path ||= Dir.mktmpdir("allure-report")
|
190
211
|
end
|
191
212
|
|
192
213
|
# Report files
|
@@ -194,7 +215,7 @@ module Publisher
|
|
194
215
|
# @return [Array<Pathname>]
|
195
216
|
def report_files
|
196
217
|
@report_files ||= Pathname
|
197
|
-
.glob("#{
|
218
|
+
.glob("#{report_path}/**/*")
|
198
219
|
.reject(&:directory?)
|
199
220
|
end
|
200
221
|
end
|