allure-report-publisher 0.0.2 → 0.1.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 +22 -8
- 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 +2 -2
- data/lib/allure_report_publisher/lib/providers/_provider.rb +174 -0
- data/lib/allure_report_publisher/lib/providers/github.rb +142 -0
- data/lib/allure_report_publisher/lib/providers/gitlab.rb +132 -0
- data/lib/allure_report_publisher/lib/report_generator.rb +10 -13
- data/lib/allure_report_publisher/lib/uploaders/_uploader.rb +127 -41
- data/lib/allure_report_publisher/lib/uploaders/gcs.rb +104 -0
- data/lib/allure_report_publisher/lib/uploaders/s3.rb +107 -0
- data/lib/allure_report_publisher/version.rb +1 -1
- metadata +58 -9
- data/lib/allure_report_publisher/commands/base.rb +0 -13
- data/lib/allure_report_publisher/commands/upload_s3.rb +0 -43
- data/lib/allure_report_publisher/lib/ci/_base.rb +0 -63
- data/lib/allure_report_publisher/lib/ci/github_actions.rb +0 -50
- data/lib/allure_report_publisher/lib/uploaders/s3_uploader.rb +0 -94
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2212afd20c080df89b88eab18ae8fa96a6b8d00027af95b2b606e9b851b83dde
|
4
|
+
data.tar.gz: b6473ed381ddb267af1fcaee0ef6080a3c8063dac4d56ea5cbf0589457c7598e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e28a752bdaaf619bf293c6a4f995a17e7cdea913c6c1c89be07dcb14c575a2b78264bbb6fad03d2b1ec574c2d0c72fd04ce84431e7920e6ac7180b5f4006c54c
|
7
|
+
data.tar.gz: aa8f768c03494a14b6dcafc9ada76764b028f750f6ff104627bb669c431321074fbac76ae81ab84df6510988d7cf161a9863c796c6615e343193ae2708979419
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
[](https://rubygems.org/gems/allure-report-publisher)
|
2
2
|
[](https://hub.docker.com/r/andrcuns/allure-report-publisher)
|
3
3
|

|
4
|
+
[](http://allure-reports-andrcuns.s3.amazonaws.com/allure-report-publisher/refs/heads/main/index.html)
|
4
5
|
[](https://codeclimate.com/github/andrcuns/allure-report-publisher/maintainability)
|
5
6
|
[](https://codeclimate.com/github/andrcuns/allure-report-publisher/test_coverage)
|
6
7
|
|
@@ -28,31 +29,44 @@ docker pull andrcuns/allure-report-publisher:latest
|
|
28
29
|
|
29
30
|
allure-report-publisher will automatically detect if used in CI environment and add relevant executor info and history
|
30
31
|
|
31
|
-
|
32
|
+
- `Allure report link`: requires `GITHUB_AUTH_TOKEN` or `GITLAB_AUTH_TOKEN` in order to update pull request description with link to latest report
|
32
33
|
|
33
34
|
```shell
|
34
|
-
$ (allure-report-publisher|docker run --rm andrcuns/allure-report-publisher:latest) upload
|
35
|
+
$ (allure-report-publisher|docker run --rm andrcuns/allure-report-publisher:latest) upload --help
|
35
36
|
Command:
|
36
|
-
allure-report-publisher upload
|
37
|
+
allure-report-publisher upload
|
37
38
|
|
38
39
|
Usage:
|
39
|
-
allure-report-publisher upload
|
40
|
+
allure-report-publisher upload TYPE
|
40
41
|
|
41
42
|
Description:
|
42
43
|
Generate and upload allure report
|
43
44
|
|
45
|
+
Arguments:
|
46
|
+
TYPE # REQUIRED Cloud storage type: (s3/gcs)
|
47
|
+
|
44
48
|
Options:
|
45
|
-
--
|
46
|
-
--result-files-glob=VALUE # Allure results files glob. Required: true
|
49
|
+
--results-glob=VALUE # Allure results files glob. Required: true
|
47
50
|
--bucket=VALUE # Bucket name. Required: true
|
48
51
|
--prefix=VALUE # Optional prefix for report path. Required: false
|
52
|
+
--[no-]update-pr # Update pull request description with url to allure report, default: false
|
53
|
+
--[no-]copy-latest # Keep copy of latest report at base prefix path, default: false
|
54
|
+
--[no-]color # Toggle color output, default: false
|
49
55
|
--help, -h # Print this help
|
50
56
|
|
51
57
|
Examples:
|
52
|
-
allure-report-publisher upload s3 --
|
53
|
-
allure-report-publisher upload
|
58
|
+
allure-report-publisher upload s3 --results-glob='path/to/allure-result/**/*' --bucket=my-bucket
|
59
|
+
allure-report-publisher upload gcs --results-glob='path/to/allure-result/**/*' --bucket=my-bucket --prefix=my-project/prs
|
54
60
|
```
|
55
61
|
|
62
|
+
### AWS S3
|
63
|
+
|
64
|
+
- `AWS authentication`: requires environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` or credentials file `~/.aws/credentials`
|
65
|
+
|
66
|
+
### Google Cloud Storage
|
67
|
+
|
68
|
+
- `GCS authentication`: requires environment variable `GOOGLE_CLOUD_CREDENTIALS_JSON` with contents of credentials.json
|
69
|
+
|
56
70
|
## Development
|
57
71
|
|
58
72
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -14,11 +14,8 @@ module Publisher
|
|
14
14
|
extend Dry::CLI::Registry
|
15
15
|
|
16
16
|
register "version", Version, aliases: ["-v", "--version"]
|
17
|
-
|
18
|
-
register "upload" do |prefix|
|
19
|
-
prefix.register "s3", UploadS3
|
20
|
-
end
|
17
|
+
register "upload", Upload, aliases: ["u"]
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
|
-
Publisher::Commands.before("upload
|
21
|
+
Publisher::Commands.before("upload") { Publisher::Helpers.validate_allure_cli_present }
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Publisher
|
2
|
+
module Commands
|
3
|
+
# Upload allure report
|
4
|
+
#
|
5
|
+
class Upload < Dry::CLI::Command
|
6
|
+
include Helpers
|
7
|
+
|
8
|
+
desc "Generate and upload allure report"
|
9
|
+
|
10
|
+
argument :type,
|
11
|
+
type: :string,
|
12
|
+
required: true,
|
13
|
+
values: %w[s3 gcs],
|
14
|
+
desc: "Cloud storage type"
|
15
|
+
|
16
|
+
option :results_glob,
|
17
|
+
desc: "Allure results files glob. Required: true"
|
18
|
+
option :bucket,
|
19
|
+
desc: "Bucket name. Required: true"
|
20
|
+
option :prefix,
|
21
|
+
desc: "Optional prefix for report path. Required: false"
|
22
|
+
option :update_pr,
|
23
|
+
type: :string,
|
24
|
+
values: %w[comment description],
|
25
|
+
desc: "Add report url to PR via comment or description update"
|
26
|
+
option :copy_latest,
|
27
|
+
type: :boolean,
|
28
|
+
default: false,
|
29
|
+
desc: "Keep copy of latest report at base prefix path"
|
30
|
+
option :color,
|
31
|
+
type: :boolean,
|
32
|
+
default: false,
|
33
|
+
desc: "Toggle color output"
|
34
|
+
|
35
|
+
example [
|
36
|
+
"s3 --results-glob='path/to/allure-result/**/*' --bucket=my-bucket",
|
37
|
+
"gcs --results-glob='path/to/allure-result/**/*' --bucket=my-bucket --prefix=my-project/prs"
|
38
|
+
]
|
39
|
+
|
40
|
+
def call(**args)
|
41
|
+
validate_args(args)
|
42
|
+
validate_result_files(args[:results_glob])
|
43
|
+
Helpers.pastel(force_color: args[:color] || nil)
|
44
|
+
|
45
|
+
uploader = uploaders(args[:type]).new(**args.slice(:results_glob, :bucket, :prefix, :copy_latest, :update_pr))
|
46
|
+
|
47
|
+
log("Generating allure report")
|
48
|
+
Spinner.spin("generating") { uploader.generate_report }
|
49
|
+
|
50
|
+
log("Uploading allure report to #{args[:type]}")
|
51
|
+
Spinner.spin("uploading") { uploader.upload }
|
52
|
+
uploader.report_urls.each { |k, v| log("#{k}: #{v}", :green) }
|
53
|
+
return unless args[:update_pr] && uploader.pr?
|
54
|
+
|
55
|
+
log("Updating pull request description")
|
56
|
+
Spinner.spin("updating", exit_on_error: false) { uploader.add_url_to_pr }
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Uploader class
|
62
|
+
#
|
63
|
+
# @param [String] uploader
|
64
|
+
# @return [Publisher::Uploaders::Uploader]
|
65
|
+
def uploaders(uploader)
|
66
|
+
{
|
67
|
+
"s3" => Uploaders::S3,
|
68
|
+
"gcs" => Uploaders::GCS
|
69
|
+
}[uploader]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Validate required args
|
73
|
+
#
|
74
|
+
# @param [Hash] args
|
75
|
+
# @return [void]
|
76
|
+
def validate_args(args)
|
77
|
+
error("Missing argument --results-glob!") unless args[:results_glob]
|
78
|
+
error("Missing argument --bucket!") unless args[:bucket]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Check if allure results present
|
82
|
+
#
|
83
|
+
# @param [String] results_glob
|
84
|
+
# @return [void]
|
85
|
+
def validate_result_files(results_glob)
|
86
|
+
Dir.glob(results_glob).empty? && error("Glob '#{results_glob}' did not match any files!")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -10,7 +10,7 @@ module Publisher
|
|
10
10
|
# @param [Boolean] force_color
|
11
11
|
# @return [Pastel]
|
12
12
|
def self.pastel(force_color: nil)
|
13
|
-
@pastel ||= Pastel.new(enabled: force_color)
|
13
|
+
@pastel ||= Pastel.new(enabled: force_color, eachline: "\n")
|
14
14
|
end
|
15
15
|
|
16
16
|
# Check allure cli is installed and executable
|
@@ -48,7 +48,7 @@ module Publisher
|
|
48
48
|
# @param [String] message
|
49
49
|
# @return [void]
|
50
50
|
def error(message)
|
51
|
-
|
51
|
+
warn colorize(message, :red)
|
52
52
|
exit(1)
|
53
53
|
end
|
54
54
|
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Publisher
|
2
|
+
# Namespace for providers executing tests
|
3
|
+
#
|
4
|
+
module Providers
|
5
|
+
# Detect CI provider
|
6
|
+
#
|
7
|
+
# @return [Publisher::Providers::Base]
|
8
|
+
def self.provider
|
9
|
+
return Github if ENV["GITHUB_WORKFLOW"]
|
10
|
+
return Gitlab if ENV["GITLAB_CI"]
|
11
|
+
end
|
12
|
+
|
13
|
+
# Base class for CI executor info
|
14
|
+
#
|
15
|
+
class Provider
|
16
|
+
DESCRIPTION_PATTERN = /<!-- allure -->[\s\S]+<!-- allurestop -->/.freeze
|
17
|
+
ALLURE_JOB_NAME = "ALLURE_JOB_NAME".freeze
|
18
|
+
|
19
|
+
def initialize(report_url:, update_pr:)
|
20
|
+
@report_url = report_url
|
21
|
+
@update_pr = update_pr
|
22
|
+
end
|
23
|
+
|
24
|
+
# :nocov:
|
25
|
+
|
26
|
+
# Get ci run ID without creating instance of ci provider
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
def self.run_id
|
30
|
+
raise("Not implemented!")
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get executor info
|
34
|
+
#
|
35
|
+
# @return [Hash]
|
36
|
+
def executor_info
|
37
|
+
raise("Not implemented!")
|
38
|
+
end
|
39
|
+
# :nocov:
|
40
|
+
|
41
|
+
# Add report url to pull request description
|
42
|
+
#
|
43
|
+
# @return [void]
|
44
|
+
def add_report_url
|
45
|
+
raise("Not a pull request, skipped!") unless pr?
|
46
|
+
return add_comment if comment?
|
47
|
+
|
48
|
+
update_pr_description
|
49
|
+
end
|
50
|
+
|
51
|
+
# :nocov:
|
52
|
+
|
53
|
+
# Pull request run
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
56
|
+
def pr?
|
57
|
+
raise("Not implemented!")
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
attr_reader :report_url, :update_pr
|
63
|
+
|
64
|
+
# Current pull request description
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
def pr_description
|
68
|
+
raise("Not implemented!")
|
69
|
+
end
|
70
|
+
|
71
|
+
# Update pull request description
|
72
|
+
#
|
73
|
+
# @return [void]
|
74
|
+
def update_pr_description
|
75
|
+
raise("Not implemented!")
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add comment with report url
|
79
|
+
#
|
80
|
+
# @return [void]
|
81
|
+
def add_comment
|
82
|
+
raise("Not implemented!")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Commit SHA url
|
86
|
+
#
|
87
|
+
# @return [String]
|
88
|
+
def sha_url
|
89
|
+
raise("Not implemented!")
|
90
|
+
end
|
91
|
+
# :nocov:
|
92
|
+
|
93
|
+
# Add report url as comment
|
94
|
+
#
|
95
|
+
# @return [Boolean]
|
96
|
+
def comment?
|
97
|
+
update_pr == "comment"
|
98
|
+
end
|
99
|
+
|
100
|
+
# CI run id
|
101
|
+
#
|
102
|
+
# @return [String]
|
103
|
+
def run_id
|
104
|
+
self.class.run_id
|
105
|
+
end
|
106
|
+
|
107
|
+
# Check if PR already has report urls
|
108
|
+
#
|
109
|
+
# @return [Boolean]
|
110
|
+
def reported?
|
111
|
+
@reported ||= pr_description.match?(DESCRIPTION_PATTERN)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Full PR description
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
def updated_pr_description
|
118
|
+
reported? ? existing_pr_description : initial_pr_descripion
|
119
|
+
end
|
120
|
+
|
121
|
+
# Updated PR description
|
122
|
+
#
|
123
|
+
# @return [String]
|
124
|
+
def existing_pr_description
|
125
|
+
pr_description.gsub(DESCRIPTION_PATTERN, pr_body).strip
|
126
|
+
end
|
127
|
+
|
128
|
+
# Initial PR description
|
129
|
+
#
|
130
|
+
# @return [String]
|
131
|
+
def initial_pr_descripion
|
132
|
+
"#{pr_description}\n\n#{pr_body}".strip
|
133
|
+
end
|
134
|
+
|
135
|
+
# Heading for report urls
|
136
|
+
#
|
137
|
+
# @return [String]
|
138
|
+
def heading
|
139
|
+
@heading ||= <<~HEADING.strip
|
140
|
+
# Allure report
|
141
|
+
`allure-report-publisher` generated allure report for #{sha_url}!
|
142
|
+
HEADING
|
143
|
+
end
|
144
|
+
|
145
|
+
# Allure report url pr description
|
146
|
+
#
|
147
|
+
# @return [String]
|
148
|
+
def pr_body
|
149
|
+
@pr_body ||= <<~DESC
|
150
|
+
<!-- allure -->
|
151
|
+
---
|
152
|
+
#{heading}
|
153
|
+
|
154
|
+
#{job_entry}
|
155
|
+
<!-- allurestop -->
|
156
|
+
DESC
|
157
|
+
end
|
158
|
+
|
159
|
+
# Allure report url comment body
|
160
|
+
#
|
161
|
+
# @return [String]
|
162
|
+
def comment_body
|
163
|
+
@comment_body ||= pr_body.gsub("---\n", "")
|
164
|
+
end
|
165
|
+
|
166
|
+
# Single job report URL entry
|
167
|
+
#
|
168
|
+
# @return [String]
|
169
|
+
def job_entry
|
170
|
+
@job_entry ||= "**#{build_name}**: 📝 [allure report](#{report_url})"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require "octokit"
|
2
|
+
|
3
|
+
module Publisher
|
4
|
+
module Providers
|
5
|
+
# Github implementation
|
6
|
+
#
|
7
|
+
class Github < Provider
|
8
|
+
# Set octokit to autopaginate
|
9
|
+
#
|
10
|
+
Octokit.configure do |config|
|
11
|
+
config.auto_paginate = true
|
12
|
+
end
|
13
|
+
|
14
|
+
# Run id
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
def self.run_id
|
18
|
+
@run_id ||= ENV["GITHUB_RUN_ID"]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Pull request run
|
22
|
+
#
|
23
|
+
# @return [Boolean]
|
24
|
+
def pr?
|
25
|
+
ENV["GITHUB_EVENT_NAME"] == "pull_request"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Executor info
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
def executor_info
|
32
|
+
{
|
33
|
+
name: "Github",
|
34
|
+
type: "github",
|
35
|
+
reportName: "AllureReport",
|
36
|
+
url: server_url,
|
37
|
+
reportUrl: report_url,
|
38
|
+
buildUrl: build_url,
|
39
|
+
buildOrder: run_id,
|
40
|
+
buildName: build_name
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Github api client
|
47
|
+
#
|
48
|
+
# @return [Octokit::Client]
|
49
|
+
def client
|
50
|
+
@client ||= begin
|
51
|
+
raise("Missing GITHUB_AUTH_TOKEN environment variable!") unless ENV["GITHUB_AUTH_TOKEN"]
|
52
|
+
|
53
|
+
Octokit::Client.new(access_token: ENV["GITHUB_AUTH_TOKEN"], api_endpoint: ENV["GITHUB_API_URL"])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Update pull request description
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
def update_pr_description
|
61
|
+
client.update_pull_request(repository, pr_id, body: updated_pr_description)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Add comment with report url
|
65
|
+
#
|
66
|
+
# @return [void]
|
67
|
+
def add_comment
|
68
|
+
return client.add_comment(repository, pr_id, comment_body) unless comment
|
69
|
+
|
70
|
+
client.update_comment(repository, comment[:id], comment_body)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Existing comment with allure urls
|
74
|
+
#
|
75
|
+
# @return [Sawyer::Resource]
|
76
|
+
def comment
|
77
|
+
@comment ||= client.issue_comments(repository, pr_id).detect do |comment|
|
78
|
+
comment[:body].match?(DESCRIPTION_PATTERN)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Github event
|
83
|
+
#
|
84
|
+
# @return [Hash]
|
85
|
+
def github_event
|
86
|
+
@github_event ||= JSON.parse(File.read(ENV["GITHUB_EVENT_PATH"]), symbolize_names: true)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Pull request description
|
90
|
+
#
|
91
|
+
# @return [String]
|
92
|
+
def pr_description
|
93
|
+
@pr_description ||= client.pull_request(repository, pr_id)[:body]
|
94
|
+
end
|
95
|
+
|
96
|
+
# Pull request id
|
97
|
+
#
|
98
|
+
# @return [Integer]
|
99
|
+
def pr_id
|
100
|
+
@pr_id ||= github_event[:number]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Server url
|
104
|
+
#
|
105
|
+
# @return [String]
|
106
|
+
def server_url
|
107
|
+
@server_url ||= ENV["GITHUB_SERVER_URL"]
|
108
|
+
end
|
109
|
+
|
110
|
+
# Build url
|
111
|
+
#
|
112
|
+
# @return [String]
|
113
|
+
def build_url
|
114
|
+
@build_url ||= "#{server_url}/#{repository}/actions/runs/#{run_id}"
|
115
|
+
end
|
116
|
+
|
117
|
+
# Job name
|
118
|
+
#
|
119
|
+
# @return [String]
|
120
|
+
def build_name
|
121
|
+
@build_name ||= ENV[ALLURE_JOB_NAME] || ENV["GITHUB_JOB"]
|
122
|
+
end
|
123
|
+
|
124
|
+
# Github repository
|
125
|
+
#
|
126
|
+
# @return [String]
|
127
|
+
def repository
|
128
|
+
@repository ||= ENV["GITHUB_REPOSITORY"]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Commit sha url
|
132
|
+
#
|
133
|
+
# @return [String]
|
134
|
+
def sha_url
|
135
|
+
sha = github_event.dig(:pull_request, :head, :sha)
|
136
|
+
short_sha = sha[0..7]
|
137
|
+
|
138
|
+
"[#{short_sha}](#{server_url}/#{repository}/pull/#{pr_id}/commits/#{sha})"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|