allure-report-publisher 0.0.3 → 0.1.1
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 -14
- 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/_provider.rb +174 -0
- 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/report_generator.rb +10 -13
- data/lib/allure_report_publisher/lib/uploaders/_uploader.rb +107 -51
- data/lib/allure_report_publisher/lib/uploaders/gcs.rb +104 -0
- data/lib/allure_report_publisher/lib/uploaders/{s3_uploader.rb → s3.rb} +45 -44
- data/lib/allure_report_publisher/version.rb +1 -1
- metadata +30 -10
- data/lib/allure_report_publisher/commands/base.rb +0 -17
- data/lib/allure_report_publisher/commands/upload_s3.rb +0 -43
- data/lib/allure_report_publisher/lib/providers/_base.rb +0 -111
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bb81eada76c7024e4a570187d02e2383677552daef81b14e1e1457ca2fbc6be
|
4
|
+
data.tar.gz: 27db25caad167473b073a6057f82981d648889d800c3fddb879c3c046d5dc951
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b3d2e2a7faa93ad323cb24ea892aeb3601c904e30c4fdadaf78732bd903945c7ba2e488440bb5a1d834e0ec62a1616c83aea48e697596edd02d271fcf8d0719
|
7
|
+
data.tar.gz: 400d890b0e1b315d1aab1a246482a31849a38c3a78b231310ffc285b5fd14d677ee3b3badfcf098f9f15d982091f7d85dac6642f5e6b0d0bd2f7e1b5f1509510
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
[](https://rubygems.org/gems/allure-report-publisher)
|
2
|
+
[](https://rubygems.org/gems/allure-report-publisher)
|
2
3
|
[](https://hub.docker.com/r/andrcuns/allure-report-publisher)
|
4
|
+
[](https://hub.docker.com/r/andrcuns/allure-report-publisher)
|
3
5
|

|
6
|
+
[](https://storage.googleapis.com/allure-test-reports/allure-report-publisher/refs/heads/main/index.html)
|
4
7
|
[](https://codeclimate.com/github/andrcuns/allure-report-publisher/maintainability)
|
5
8
|
[](https://codeclimate.com/github/andrcuns/allure-report-publisher/test_coverage)
|
6
9
|
|
@@ -28,35 +31,61 @@ docker pull andrcuns/allure-report-publisher:latest
|
|
28
31
|
|
29
32
|
allure-report-publisher will automatically detect if used in CI environment and add relevant executor info and history
|
30
33
|
|
31
|
-
### AWS S3
|
32
|
-
|
33
|
-
- `AWS authentication`: requires environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` or credentials file `~/.aws/credentials`
|
34
34
|
- `Allure report link`: requires `GITHUB_AUTH_TOKEN` or `GITLAB_AUTH_TOKEN` in order to update pull request description with link to latest report
|
35
35
|
|
36
36
|
```shell
|
37
|
-
$ (allure-report-publisher|docker run --rm andrcuns/allure-report-publisher:latest) upload
|
37
|
+
$ (allure-report-publisher|docker run --rm andrcuns/allure-report-publisher:latest) upload --help
|
38
38
|
Command:
|
39
|
-
allure-report-publisher upload
|
39
|
+
allure-report-publisher upload
|
40
40
|
|
41
41
|
Usage:
|
42
|
-
allure-report-publisher upload
|
42
|
+
allure-report-publisher upload TYPE
|
43
43
|
|
44
44
|
Description:
|
45
45
|
Generate and upload allure report
|
46
46
|
|
47
|
+
Arguments:
|
48
|
+
TYPE # REQUIRED Cloud storage type: (s3/gcs)
|
49
|
+
|
47
50
|
Options:
|
48
|
-
--
|
49
|
-
--
|
50
|
-
--
|
51
|
-
--
|
52
|
-
--
|
53
|
-
--
|
51
|
+
--results-glob=VALUE # Allure results files glob. Required: true
|
52
|
+
--bucket=VALUE # Bucket name. Required: true
|
53
|
+
--prefix=VALUE # Optional prefix for report path. Required: false
|
54
|
+
--update-pr=VALUE # Add report url to PR via comment or description update. Required: false: (comment/description)
|
55
|
+
--[no-]copy-latest # Keep copy of latest report at base prefix path, default: false
|
56
|
+
--[no-]color # Toggle color output, default: false
|
57
|
+
--help, -h # Print this help
|
54
58
|
|
55
59
|
Examples:
|
56
|
-
allure-report-publisher upload s3 --
|
57
|
-
allure-report-publisher upload
|
60
|
+
allure-report-publisher upload s3 --results-glob='path/to/allure-result/**/*' --bucket=my-bucket
|
61
|
+
allure-report-publisher upload gcs --results-glob='path/to/allure-result/**/*' --bucket=my-bucket --prefix=my-project/prs
|
58
62
|
```
|
59
63
|
|
64
|
+
### AWS S3
|
65
|
+
|
66
|
+
Requires environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` or credentials file `~/.aws/credentials`
|
67
|
+
|
68
|
+
### Google Cloud Storage
|
69
|
+
|
70
|
+
Requires on of the following environment variables.
|
71
|
+
|
72
|
+
credentials.json file location:
|
73
|
+
|
74
|
+
- `STORAGE_CREDENTIALS`
|
75
|
+
- `STORAGE_KEYFILE`
|
76
|
+
- `GOOGLE_CLOUD_CREDENTIALS`
|
77
|
+
- `GOOGLE_CLOUD_KEYFILE`
|
78
|
+
- `GCLOUD_KEYFILE`
|
79
|
+
|
80
|
+
credentials.json contents:
|
81
|
+
|
82
|
+
- `GOOGLE_CLOUD_CREDENTIALS_JSON`
|
83
|
+
- `STORAGE_CREDENTIALS_JSON`
|
84
|
+
- `STORAGE_KEYFILE_JSON`
|
85
|
+
- `GOOGLE_CLOUD_CREDENTIALS_JSON`
|
86
|
+
- `GOOGLE_CLOUD_KEYFILE_JSON`
|
87
|
+
- `GCLOUD_KEYFILE_JSON`
|
88
|
+
|
60
89
|
## Development
|
61
90
|
|
62
91
|
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. Required: false"
|
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("Adding reports urls")
|
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
|
@@ -99,7 +99,7 @@ module Publisher
|
|
99
99
|
# @param [String] error_message
|
100
100
|
# @return [void]
|
101
101
|
def spinner_error(error_message)
|
102
|
-
colored_message = colorize(error_message, error_color)
|
102
|
+
colored_message = colorize("failed\n#{error_message}", error_color)
|
103
103
|
return spinner.error(colored_message) if tty?
|
104
104
|
|
105
105
|
spinner.stop
|
@@ -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
|
@@ -4,7 +4,13 @@ module Publisher
|
|
4
4
|
module Providers
|
5
5
|
# Github implementation
|
6
6
|
#
|
7
|
-
class Github <
|
7
|
+
class Github < Provider
|
8
|
+
# Set octokit to autopaginate
|
9
|
+
#
|
10
|
+
Octokit.configure do |config|
|
11
|
+
config.auto_paginate = true
|
12
|
+
end
|
13
|
+
|
8
14
|
# Run id
|
9
15
|
#
|
10
16
|
# @return [String]
|
@@ -12,7 +18,12 @@ module Publisher
|
|
12
18
|
@run_id ||= ENV["GITHUB_RUN_ID"]
|
13
19
|
end
|
14
20
|
|
15
|
-
|
21
|
+
# Pull request run
|
22
|
+
#
|
23
|
+
# @return [Boolean]
|
24
|
+
def pr?
|
25
|
+
ENV["GITHUB_EVENT_NAME"] == "pull_request"
|
26
|
+
end
|
16
27
|
|
17
28
|
# Executor info
|
18
29
|
#
|
@@ -30,6 +41,8 @@ module Publisher
|
|
30
41
|
}
|
31
42
|
end
|
32
43
|
|
44
|
+
private
|
45
|
+
|
33
46
|
# Github api client
|
34
47
|
#
|
35
48
|
# @return [Octokit::Client]
|
@@ -41,11 +54,36 @@ module Publisher
|
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
44
|
-
#
|
57
|
+
# Update pull request description
|
45
58
|
#
|
46
|
-
# @return [
|
47
|
-
def
|
48
|
-
|
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)
|
49
87
|
end
|
50
88
|
|
51
89
|
# Pull request description
|
@@ -55,19 +93,11 @@ module Publisher
|
|
55
93
|
@pr_description ||= client.pull_request(repository, pr_id)[:body]
|
56
94
|
end
|
57
95
|
|
58
|
-
# Update pull request description
|
59
|
-
#
|
60
|
-
# @param [String] _desc
|
61
|
-
# @return [void]
|
62
|
-
def update_pr_description(desc)
|
63
|
-
client.update_pull_request(repository, pr_id, body: desc)
|
64
|
-
end
|
65
|
-
|
66
96
|
# Pull request id
|
67
97
|
#
|
68
98
|
# @return [Integer]
|
69
99
|
def pr_id
|
70
|
-
@pr_id ||=
|
100
|
+
@pr_id ||= github_event[:number]
|
71
101
|
end
|
72
102
|
|
73
103
|
# Server url
|
@@ -88,7 +118,7 @@ module Publisher
|
|
88
118
|
#
|
89
119
|
# @return [String]
|
90
120
|
def build_name
|
91
|
-
@build_name ||= ENV["GITHUB_JOB"]
|
121
|
+
@build_name ||= ENV[ALLURE_JOB_NAME] || ENV["GITHUB_JOB"]
|
92
122
|
end
|
93
123
|
|
94
124
|
# Github repository
|
@@ -97,6 +127,16 @@ module Publisher
|
|
97
127
|
def repository
|
98
128
|
@repository ||= ENV["GITHUB_REPOSITORY"]
|
99
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
|
100
140
|
end
|
101
141
|
end
|
102
142
|
end
|