allure-report-publisher 0.0.3 → 0.1.1

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: 818cdc599b432cb8484e95662881253a9f0df4265eb742f3f56f459ecbe57dfd
4
- data.tar.gz: a261391b7851b0305883c6cd15a9789854051b30d39184728235641f881fe3fa
3
+ metadata.gz: 9bb81eada76c7024e4a570187d02e2383677552daef81b14e1e1457ca2fbc6be
4
+ data.tar.gz: 27db25caad167473b073a6057f82981d648889d800c3fddb879c3c046d5dc951
5
5
  SHA512:
6
- metadata.gz: 9e8ea6e47d729b8e484c660a5add949546662deb3d339caf6d95b4e45c5970db7137375cf3dd67764f5dcb7e9b78859eb52f8dfc3da0e5dedbcb7d346a5f5e26
7
- data.tar.gz: dec6eec389f65663b7b6f7531796e0e7c0a39a2137e5f94c0dd881e87284ca31b6a268462a7dca99909250b91b911f250e378319dcb3b97930078eaa22b858c9
6
+ metadata.gz: 5b3d2e2a7faa93ad323cb24ea892aeb3601c904e30c4fdadaf78732bd903945c7ba2e488440bb5a1d834e0ec62a1616c83aea48e697596edd02d271fcf8d0719
7
+ data.tar.gz: 400d890b0e1b315d1aab1a246482a31849a38c3a78b231310ffc285b5fd14d677ee3b3badfcf098f9f15d982091f7d85dac6642f5e6b0d0bd2f7e1b5f1509510
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  [![Gem Version](https://img.shields.io/gem/v/allure-report-publisher?color=red)](https://rubygems.org/gems/allure-report-publisher)
2
+ [![Gem Pulls](https://img.shields.io/gem/dt/allure-report-publisher)](https://rubygems.org/gems/allure-report-publisher)
2
3
  [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/andrcuns/allure-report-publisher?color=blue&label=docker&sort=semver)](https://hub.docker.com/r/andrcuns/allure-report-publisher)
4
+ [![Docker Pulls](https://img.shields.io/docker/pulls/andrcuns/allure-report-publisher)](https://hub.docker.com/r/andrcuns/allure-report-publisher)
3
5
  ![Workflow status](https://github.com/andrcuns/allure-report-publisher/workflows/Test/badge.svg)
6
+ [![Test Report](https://img.shields.io/badge/report-allure-blue.svg)](https://storage.googleapis.com/allure-test-reports/allure-report-publisher/refs/heads/main/index.html)
4
7
  [![Maintainability](https://api.codeclimate.com/v1/badges/210eaa4f74588fb08313/maintainability)](https://codeclimate.com/github/andrcuns/allure-report-publisher/maintainability)
5
8
  [![Test Coverage](https://api.codeclimate.com/v1/badges/210eaa4f74588fb08313/test_coverage)](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 s3 --help
37
+ $ (allure-report-publisher|docker run --rm andrcuns/allure-report-publisher:latest) upload --help
38
38
  Command:
39
- allure-report-publisher upload s3
39
+ allure-report-publisher upload
40
40
 
41
41
  Usage:
42
- allure-report-publisher upload s3
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
- --[no-]color # Toggle color output
49
- --[no-]update-pr # Update pull request description with url to allure report, default: false
50
- --result-files-glob=VALUE # Allure results files glob. Required: true
51
- --bucket=VALUE # Bucket name. Required: true
52
- --prefix=VALUE # Optional prefix for report path. Required: false
53
- --help, -h # Print this help
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 --result-files-glob='path/to/allure-result/**/*' --bucket=my-bucket
57
- allure-report-publisher upload s3 --result-files-glob='path/to/allure-result/**/*' --bucket=my-bucket --project=my-project/prs
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 s3") { Publisher::Helpers.validate_allure_cli_present }
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 < Base
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
- private
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
- # Pull request run
57
+ # Update pull request description
45
58
  #
46
- # @return [Boolean]
47
- def pr?
48
- ENV["GITHUB_EVENT_NAME"] == "pull_request"
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 ||= JSON.parse(File.read(ENV["GITHUB_EVENT_PATH"]))["number"]
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