allure-report-publisher 1.0.0 → 1.1.0

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: cbc236368c7b0893b5de931e7ecd37836c72bc540a5909efcf319fd74348541a
4
- data.tar.gz: bf74a63cf06f76bc27d52cdf16fce99006a82076c12fce25de89375a27a932c0
3
+ metadata.gz: fc21e0f3488c76bf88a227a59a470d1959f5aadb813fc86986f7a7a175793efc
4
+ data.tar.gz: 641b2e9a9e6587a3246bdcdbf4e34cc3b952f56c46773e495473db9749e68e80
5
5
  SHA512:
6
- metadata.gz: 51104eb7d7073e3495804534aaa0f415cec9f9300dd1c0fa8e1338b065acae290f91fd758c61e0af45f34165f1710923bd6a6e0f2b6d1a9c4d295d409fa89909
7
- data.tar.gz: 5aec20910db4609549224a161a09502a390be539a77873b2d1de556b73d307b23d93d0d0f6c8404897569c7fc84e4a7c366bb33cfb6dc40406c530f1874cd2c6
6
+ metadata.gz: 2ef72a1f8869b175110a7377418bc3a4b369bbb44329965b2b76184c905dc38293b845cf0d661dbe1ff6eb66c2b87804d6fdc74b06eefa58d30826b863c6f0f9
7
+ data.tar.gz: d15121ee77d77a467a7e9f6a28b447218711aacc3aa63586f2a0cac424e1abdd129ac2aa7aaba654ddce25f8cf4aec0049d39d4b6cf8be8348515cac6f1854de
data/README.md CHANGED
@@ -53,6 +53,7 @@ Options:
53
53
  --[no-]copy-latest # Keep copy of latest report at base prefix path, default: false
54
54
  --[no-]color # Force color output
55
55
  --[no-]ignore-missing-results # Ignore missing allure results, default: false
56
+ --[no-]debug # Print additional debug output, default: false
56
57
  --help, -h # Print this help
57
58
 
58
59
  Examples:
@@ -55,6 +55,10 @@ module Publisher
55
55
  type: :boolean,
56
56
  default: false,
57
57
  desc: "Ignore missing allure results"
58
+ option :debug,
59
+ type: :boolean,
60
+ default: false,
61
+ desc: "Print additional debug output"
58
62
 
59
63
  example [
60
64
  "s3 --results-glob='path/to/allure-results' --bucket=my-bucket",
@@ -68,16 +72,13 @@ module Publisher
68
72
  validate_args
69
73
  validate_result_files
70
74
 
71
- log("Generating allure report")
72
- Spinner.spin("generating") { uploader.generate_report }
73
-
74
- log("Uploading allure report to #{args[:type]}")
75
- Spinner.spin("uploading") { uploader.upload }
76
- uploader.report_urls.each { |k, v| log("#{k}: #{v}", :green) }
75
+ generate_report
76
+ upload_report
77
77
  return unless args[:update_pr] && uploader.pr?
78
78
 
79
- log("Adding reports urls")
80
- Spinner.spin("updating", exit_on_error: false) { uploader.add_result_summary }
79
+ add_report_urls
80
+ rescue StandardError => e
81
+ handle_error(e)
81
82
  end
82
83
 
83
84
  private
@@ -133,6 +134,40 @@ module Publisher
133
134
  log("Glob '#{results_glob}' did not match any files!", ignore ? :yellow : :red)
134
135
  exit(ignore ? 0 : 1)
135
136
  end
137
+
138
+ # Generate allure report
139
+ #
140
+ # @return [void]
141
+ def generate_report
142
+ log("Generating allure report")
143
+ Spinner.spin("generating", debug: args[:debug]) { uploader.generate_report }
144
+ end
145
+
146
+ # Upload report to cloud storage
147
+ #
148
+ # @return [void]
149
+ def upload_report
150
+ log("Uploading allure report to #{args[:type]}")
151
+ Spinner.spin("uploading", debug: args[:debug]) { uploader.upload }
152
+ uploader.report_urls.each { |k, v| log("#{k}: #{v}", :green) }
153
+ end
154
+
155
+ # Add report results to pr/mr
156
+ #
157
+ # @return [void]
158
+ def add_report_urls
159
+ log("Adding reports urls")
160
+ Spinner.spin("updating", exit_on_error: false, debug: args[:debug]) { uploader.add_result_summary }
161
+ end
162
+
163
+ # Handle error during upload command
164
+ #
165
+ # @param [StandardError] error
166
+ # @return [void]
167
+ def handle_error(error)
168
+ exit(1) if error.is_a?(Spinner::Failure)
169
+ error(error)
170
+ end
136
171
  end
137
172
  end
138
173
  end
@@ -0,0 +1,120 @@
1
+ require "tempfile"
2
+
3
+ module Publisher
4
+ module Helpers
5
+ # Helper class for gsutil cli utility
6
+ #
7
+ class Gsutil
8
+ class UnsupportedConfig < StandardError; end
9
+ class Uninitialised < StandardError; end
10
+
11
+ include Helpers
12
+
13
+ def self.init
14
+ new.init!
15
+ end
16
+
17
+ private_class_method :new
18
+
19
+ # Initialize gsutil
20
+ #
21
+ # @return [Gsutil]
22
+ def init!
23
+ log_debug("Setting up gsutil")
24
+ @valid = execute_shell("which gsutil") && true
25
+
26
+ log_debug("Checking google credentials")
27
+ check_credentials
28
+ log_debug("Credentials valid, gsutil initialized")
29
+ self
30
+ rescue StandardError => e
31
+ case e
32
+ when UnsupportedConfig
33
+ log_debug("credentials not compatible with gsutil! Falling back to google sdk client for batch uploads")
34
+ when ShellCommandFailure
35
+ log_debug("gsutil command not found, falling back to gcs client")
36
+ else
37
+ log_debug("gsutil init failed: error: #{e}\nbacktrace: #{e.backtrace&.join("\n")}")
38
+ end
39
+
40
+ @valid = false
41
+ self
42
+ end
43
+
44
+ # Check if gsutil is valid
45
+ #
46
+ # @return [Boolean]
47
+ def valid?
48
+ @valid
49
+ end
50
+
51
+ # Perform batch copy operation
52
+ #
53
+ # @param [String] source_dir
54
+ # @param [String] destination_dir
55
+ # @param [String] bucket
56
+ # @param [String] cache_control
57
+ # @return [void]
58
+ def batch_copy(source_dir:, destination_dir:, bucket:, cache_control: 3600)
59
+ raise(Uninitialised, "gsutil has not been properly set up!") unless valid?
60
+
61
+ log_debug("Uploading '#{source_dir}' using gsutil to bucket '#{bucket}' with destination '#{destination_dir}'")
62
+ with_credentials do |key_file|
63
+ execute_shell([
64
+ base_cmd(key_file),
65
+ "-h 'Cache-Control:private, max-age=#{cache_control}'",
66
+ "rsync -r #{source_dir} gs://#{bucket}/#{destination_dir}"
67
+ ].join(" "))
68
+ end
69
+ log_debug("Finished upload successfully")
70
+ end
71
+
72
+ private
73
+
74
+ # Execute block with gcs credentials
75
+ #
76
+ # @return [void]
77
+ def with_credentials
78
+ if json_key[:file]
79
+ yield(json_key[:key])
80
+ else
81
+ Tempfile.create("auth") do |f|
82
+ f.write(json_key[:key])
83
+ f.close
84
+
85
+ yield(f.path)
86
+ end
87
+ end
88
+ end
89
+
90
+ # Google auth default credentials
91
+ #
92
+ # @return [String, Hash]
93
+ def gcs_credentials
94
+ @gcs_credentials ||= Google::Cloud::Storage.default_credentials
95
+ end
96
+
97
+ # Google auth json key
98
+ #
99
+ # @return [Hash]
100
+ def json_key
101
+ @json_key ||= if gcs_credentials.is_a?(Hash)
102
+ { file: false, key: gcs_credentials.to_json }
103
+ elsif gcs_credentials.is_a?(String) && File.exist?(gcs_credentials)
104
+ { file: true, key: gcs_credentials.tap { |f| JSON.parse(File.read(f)) } }
105
+ else
106
+ raise(UnsupportedConfig, "only google key json credentials are supported for gsutil")
107
+ end
108
+ end
109
+ alias check_credentials json_key
110
+
111
+ # Base command
112
+ #
113
+ # @param [String] key_file
114
+ # @return [String]
115
+ def base_cmd(key_file)
116
+ "gsutil -o 'Credentials:gs_service_key_file=#{key_file}' -m"
117
+ end
118
+ end
119
+ end
120
+ end
@@ -1,28 +1,66 @@
1
1
  require "pastel"
2
2
  require "open3"
3
+ require "logger"
4
+ require "stringio"
3
5
 
4
6
  module Publisher
5
7
  # Helpers
6
8
  #
7
9
  module Helpers
8
- # Global instance of pastel
9
- #
10
- # @param [Boolean] force_color
11
- # @return [Pastel]
12
- def self.pastel(force_color: nil)
13
- @pastel ||= Pastel.new(enabled: force_color, eachline: "\n")
14
- end
10
+ class ShellCommandFailure < StandardError; end
15
11
 
16
- # Check allure cli is installed and executable
17
- #
18
- # @return [void]
19
- def self.validate_allure_cli_present
20
- _out, status = Open3.capture2("which allure")
21
- return if status.success?
12
+ class << self
13
+ # Global instance of pastel
14
+ #
15
+ # @param [Boolean] force_color
16
+ # @return [Pastel]
17
+ def pastel(force_color: nil)
18
+ @pastel ||= Pastel.new(enabled: force_color, eachline: "\n")
19
+ end
20
+
21
+ # Check allure cli is installed and executable
22
+ #
23
+ # @return [void]
24
+ def allure_cli?
25
+ execute_shell("which allure")
26
+ rescue StandardError
27
+ Helpers.error(
28
+ "Allure cli is missing! See https://docs.qameta.io/allure/#_installing_a_commandline on how to install it!"
29
+ )
30
+ end
31
+
32
+ # Check if gsutil is installed and executable
33
+ #
34
+ # @return [Boolean]
35
+ def gsutil?
36
+ execute_shell("which gsutil") && true
37
+ rescue StandardError
38
+ false
39
+ end
40
+
41
+ # Debug logging session output
42
+ #
43
+ # @return [StringIO]
44
+ def debug_io
45
+ @debug_io ||= StringIO.new
46
+ end
47
+
48
+ # Clear debug log output
49
+ #
50
+ # @return [void]
51
+ def reset_debug_io!
52
+ @debug_io = nil
53
+ end
22
54
 
23
- Helpers.error(
24
- "Allure cli is missing! See https://docs.qameta.io/allure/#_installing_a_commandline on how to install it!"
25
- )
55
+ # Logger instance
56
+ #
57
+ # @return [Logger]
58
+ def logger
59
+ Logger.new(debug_io).tap do |logger|
60
+ logger.datetime_format = "%Y-%m-%d %H:%M:%S"
61
+ logger.formatter = proc { |_severity, time, _progname, msg| "[#{time}] #{msg}\n" }
62
+ end
63
+ end
26
64
  end
27
65
 
28
66
  # Colorize string
@@ -43,6 +81,14 @@ module Publisher
43
81
  puts colorize(message, color)
44
82
  end
45
83
 
84
+ # Save debug message to be displayed later
85
+ #
86
+ # @param [String] message
87
+ # @return [void]
88
+ def log_debug(message)
89
+ Helpers.logger.info(message)
90
+ end
91
+
46
92
  # Print error message and exit
47
93
  #
48
94
  # @param [String] message
@@ -64,13 +110,25 @@ module Publisher
64
110
  #
65
111
  # @param [String] command
66
112
  # @return [String] output
67
- def execute_shell(command)
113
+ def execute_shell(command, mask: nil)
114
+ loggable_command = mask ? command.gsub(mask, "***") : command
115
+ log_debug("Executing command '#{loggable_command}'")
68
116
  out, err, status = Open3.capture3(command)
69
- raise("Out:\n#{out}\n\nErr:\n#{err}") unless status.success?
70
117
 
71
- out
118
+ cmd_output = []
119
+ cmd_output << "Out: #{out}" unless out.empty?
120
+ cmd_output << "Err: #{err}" unless err.empty?
121
+ output = cmd_output.join("\n")
122
+
123
+ unless status.success?
124
+ err_msg = "Command '#{loggable_command}' failed!\n#{output}"
125
+ err_msg = mask ? err_msg.gsub(mask, "***") : err_msg
126
+ raise(ShellCommandFailure, err_msg)
127
+ end
128
+
129
+ mask ? output.gsub(mask, "***") : output
72
130
  end
73
131
 
74
- module_function :colorize, :log, :error, :path, :execute_shell
132
+ module_function :colorize, :log, :log_debug, :error, :path, :execute_shell
75
133
  end
76
134
  end
@@ -9,9 +9,12 @@ module Publisher
9
9
  class Spinner
10
10
  include Helpers
11
11
 
12
- def initialize(spinner_message, exit_on_error: true)
12
+ class Failure < StandardError; end
13
+
14
+ def initialize(spinner_message, exit_on_error: true, debug: false)
13
15
  @spinner_message = spinner_message
14
16
  @exit_on_error = exit_on_error
17
+ @debug = debug
15
18
  end
16
19
 
17
20
  # Run code block inside spinner
@@ -21,8 +24,8 @@ module Publisher
21
24
  # @param [Boolean] exit_on_error
22
25
  # @param [Proc] &block
23
26
  # @return [void]
24
- def self.spin(spinner_message, done_message: "done", exit_on_error: true, &block)
25
- new(spinner_message, exit_on_error: exit_on_error).spin(done_message, &block)
27
+ def self.spin(spinner_message, done_message: "done", exit_on_error: true, debug: false, &block)
28
+ new(spinner_message, exit_on_error: exit_on_error, debug: debug).spin(done_message, &block)
26
29
  end
27
30
 
28
31
  # Run code block inside spinner
@@ -34,14 +37,32 @@ module Publisher
34
37
  yield
35
38
  spinner_success(done_message)
36
39
  rescue StandardError => e
37
- spinner_error(e.message)
38
- exit(1) if exit_on_error
40
+ spinner_error(e)
41
+ raise(Failure, e.message) if exit_on_error
42
+ ensure
43
+ print_debug
44
+ Helpers.reset_debug_io!
39
45
  end
40
46
  end
41
47
 
42
48
  private
43
49
 
44
- attr_reader :spinner_message, :exit_on_error
50
+ attr_reader :spinner_message,
51
+ :exit_on_error,
52
+ :debug
53
+
54
+ # Print debug contents
55
+ #
56
+ # @return [void]
57
+ def print_debug
58
+ return if !debug || Helpers.debug_io.string.empty?
59
+
60
+ puts <<~OUT.strip
61
+ == DEBUG LOG OUTPUT ==
62
+ #{Helpers.debug_io.string.strip}
63
+ == DEBUG LOG OUTPUT ==
64
+ OUT
65
+ end
45
66
 
46
67
  # Error message color
47
68
  #
@@ -96,10 +117,12 @@ module Publisher
96
117
 
97
118
  # Return spinner error
98
119
  #
99
- # @param [String] error_message
120
+ # @param [StandardError] error
100
121
  # @return [void]
101
- def spinner_error(error_message)
102
- colored_message = colorize("failed\n#{error_message}", error_color)
122
+ def spinner_error(error)
123
+ message = ["failed", error.message]
124
+ message << error.backtrace if debug
125
+ colored_message = colorize(message.compact.join("\n"), error_color)
103
126
  return spinner.error(colored_message) if tty?
104
127
 
105
128
  spinner.stop
@@ -70,7 +70,7 @@ module Publisher
70
70
  # Short summary table
71
71
  #
72
72
  # @return [Array<String>]
73
- def short_summary # rubocop:disable Metrics/MethodLength
73
+ def short_summary
74
74
  return @short_summary if defined?(@short_summary)
75
75
 
76
76
  sum = summary_data.values.each_with_object({
@@ -5,6 +5,8 @@ module Publisher
5
5
  # Github implementation
6
6
  #
7
7
  class Github < Provider
8
+ include Helpers
9
+
8
10
  # Set octokit to autopaginate
9
11
  #
10
12
  Octokit.configure do |config|
@@ -60,6 +62,7 @@ module Publisher
60
62
  def update_pr_description
61
63
  return File.write(step_summary_file, url_section_builder.comment_body) if actions?
62
64
 
65
+ log_debug("Updating pr description for pr !#{pr_id}")
63
66
  client.update_pull_request(repository, pr_id, body: url_section_builder.updated_pr_description(pr_description))
64
67
  end
65
68
 
@@ -67,8 +70,12 @@ module Publisher
67
70
  #
68
71
  # @return [void]
69
72
  def add_comment
70
- return client.add_comment(repository, pr_id, url_section_builder.comment_body) unless comment
73
+ unless comment
74
+ log_debug("Creating comment with summary for pr ! #{pr_id}")
75
+ return client.add_comment(repository, pr_id, url_section_builder.comment_body)
76
+ end
71
77
 
78
+ log_debug("Updating summary in comment with id #{comment[:id]} in pr !#{pr_id}")
72
79
  client.update_comment(repository, comment[:id], url_section_builder.comment_body(comment[:body]))
73
80
  end
74
81
 
@@ -5,6 +5,8 @@ module Publisher
5
5
  # Gitlab implementation
6
6
  #
7
7
  class Gitlab < Provider
8
+ include Helpers
9
+
8
10
  # Get ci run ID without creating instance of ci provider
9
11
  #
10
12
  # @return [String]
@@ -48,6 +50,7 @@ module Publisher
48
50
  #
49
51
  # @return [void]
50
52
  def update_pr_description
53
+ log_debug("Updating mr description for mr !#{mr_iid}")
51
54
  client.update_merge_request(
52
55
  project,
53
56
  mr_iid,
@@ -59,8 +62,12 @@ module Publisher
59
62
  #
60
63
  # @return [void]
61
64
  def add_comment
62
- return client.create_merge_request_comment(project, mr_iid, url_section_builder.comment_body) unless comment
65
+ unless comment
66
+ log_debug("Creating comment with summary for mr ! #{mr_iid}")
67
+ return client.create_merge_request_comment(project, mr_iid, url_section_builder.comment_body)
68
+ end
63
69
 
70
+ log_debug("Updating summary in comment with id #{comment.id} in mr !#{mr_iid}")
64
71
  client.edit_merge_request_note(project, mr_iid, comment.id, url_section_builder.comment_body(comment.body))
65
72
  end
66
73
 
@@ -18,6 +18,8 @@ module Publisher
18
18
  #
19
19
  # @return [void]
20
20
  def generate
21
+ create_common_path
22
+
21
23
  generate_report
22
24
  end
23
25
 
@@ -25,14 +27,17 @@ module Publisher
25
27
  #
26
28
  # @return [String]
27
29
  def common_info_path
28
- @common_info_path ||= Dir.mktmpdir("allure-results")
30
+ @common_info_path ||= Dir.mktmpdir("allure-results").tap do |path|
31
+ log_debug("Created tmp folder for common data: '#{path}'")
32
+ end
29
33
  end
34
+ alias create_common_path common_info_path
30
35
 
31
36
  # Allure report directory
32
37
  #
33
38
  # @return [String]
34
39
  def report_path
35
- @report_path ||= Dir.mktmpdir("allure-report")
40
+ @report_path ||= File.join(Dir.tmpdir, "allure-report-#{Time.now.to_i}")
36
41
  end
37
42
 
38
43
  private
@@ -55,10 +60,12 @@ module Publisher
55
60
  #
56
61
  # @return [void]
57
62
  def generate_report
58
- out, _err, status = Open3.capture3(
59
- "allure generate --clean --output #{report_path} #{common_info_path} #{result_paths}"
60
- )
61
- raise(AllureError, out) unless status.success?
63
+ log_debug("Generating allure report from following paths: #{result_paths}")
64
+ cmd = "allure generate --clean --output #{report_path} #{common_info_path} #{result_paths}"
65
+ out = execute_shell(cmd)
66
+ log_debug("Generated allure report. #{out}")
67
+ rescue StandardError => e
68
+ raise(AllureError, e.message)
62
69
  end
63
70
  end
64
71
  end
@@ -1,4 +1,5 @@
1
1
  require "forwardable"
2
+ require "json"
2
3
 
3
4
  module Publisher
4
5
  module Uploaders
@@ -73,6 +74,7 @@ module Publisher
73
74
  def add_result_summary
74
75
  return unless update_pr && ci_provider
75
76
 
77
+ log_debug("Adding test result summary")
76
78
  ci_provider.add_result_summary
77
79
  end
78
80
 
@@ -214,7 +216,8 @@ module Publisher
214
216
  def add_history
215
217
  create_history_dir
216
218
  download_history
217
- rescue HistoryNotFoundError
219
+ rescue HistoryNotFoundError => e
220
+ log_debug(e.message)
218
221
  nil
219
222
  end
220
223
 
@@ -224,7 +227,11 @@ module Publisher
224
227
  def add_executor_info
225
228
  return unless ci_provider
226
229
 
227
- File.write("#{common_info_path}/#{EXECUTOR_JSON}", ci_provider.executor_info.to_json)
230
+ json_path = "#{common_info_path}/#{EXECUTOR_JSON}"
231
+ json = ci_provider.executor_info.to_json
232
+ log_debug("Saving ci executor info")
233
+ File.write(json_path, json)
234
+ log_debug("Saved '#{EXECUTOR_JSON}' as '#{json_path}'\n#{JSON.pretty_generate(ci_provider.executor_info)}")
228
235
  end
229
236
 
230
237
  # Run upload commands
@@ -240,7 +247,8 @@ module Publisher
240
247
  #
241
248
  # @return [void]
242
249
  def create_history_dir
243
- FileUtils.mkdir_p(path(common_info_path, "history"))
250
+ path = FileUtils.mkdir_p(path(common_info_path, "history"))
251
+ log_debug("Created tmp folder for history data: '#{path.first}'")
244
252
  end
245
253
  end
246
254
  end
@@ -14,6 +14,13 @@ module Publisher
14
14
  @client ||= Google::Cloud::Storage.new
15
15
  end
16
16
 
17
+ # Gsutil class
18
+ #
19
+ # @return [Helpers::Gsutil]
20
+ def gsutil
21
+ @gsutil ||= Helpers::Gsutil.init
22
+ end
23
+
17
24
  # GCS bucket
18
25
  #
19
26
  # @return [Google::Cloud::Storage::Bucket]
@@ -39,11 +46,14 @@ module Publisher
39
46
  #
40
47
  # @return [void]
41
48
  def download_history
49
+ log_debug("Downloading previous run history")
42
50
  HISTORY.each do |file_name|
43
51
  file = bucket.file(key(prefix, "history", file_name))
44
52
  raise(HistoryNotFoundError, "Allure history from previous runs not found!") unless file
45
53
 
46
- file.download(path(common_info_path, "history", file_name))
54
+ file_path = path(common_info_path, "history", file_name)
55
+ file.download(file_path)
56
+ log_debug("Downloaded '#{file_name}' as '#{file_path}'")
47
57
  end
48
58
  end
49
59
 
@@ -51,6 +61,7 @@ module Publisher
51
61
  #
52
62
  # @return [void]
53
63
  def upload_history
64
+ log_debug("Uploading report history")
54
65
  upload_to_gcs(report_files.select { |file| file.fnmatch?("*/history/*") }, prefix)
55
66
  end
56
67
 
@@ -58,6 +69,9 @@ module Publisher
58
69
  #
59
70
  # @return [void]
60
71
  def upload_report
72
+ log_debug("Uploading report files")
73
+ return batch_upload_to_gcs(report_path, full_prefix) if gsutil.valid?
74
+
61
75
  upload_to_gcs(report_files, full_prefix)
62
76
  end
63
77
 
@@ -65,6 +79,9 @@ module Publisher
65
79
  #
66
80
  # @return [void]
67
81
  def upload_latest_copy
82
+ log_debug("Uploading report copy as latest report")
83
+ return batch_upload_to_gcs(report_path, prefix, cache_control: 60) if gsutil.valid?
84
+
68
85
  upload_to_gcs(report_files, prefix, cache_control: 60)
69
86
  end
70
87
 
@@ -73,8 +90,9 @@ module Publisher
73
90
  # @param [Array<Pathname>] files
74
91
  # @param [String] key_prefix
75
92
  # @param [Hash] params
76
- # @return [Array<Hash>]
93
+ # @return [void]
77
94
  def upload_to_gcs(files, key_prefix, cache_control: 3600)
95
+ threads = 8
78
96
  args = files.map do |file|
79
97
  {
80
98
  file: file.to_s,
@@ -83,9 +101,25 @@ module Publisher
83
101
  }
84
102
  end
85
103
 
86
- Parallel.each(args, in_threads: 8) do |obj|
104
+ log_debug("Uploading '#{args.size}' files in '#{threads}' threads to bucker '#{bucket_name}'")
105
+ Parallel.each(args, in_threads: threads) do |obj|
87
106
  bucket.create_file(*obj.slice(:file, :path).values, **obj.slice(:cache_control))
88
107
  end
108
+ log_debug("Finished upload successfully")
109
+ end
110
+
111
+ # Batch upload whole directory
112
+ #
113
+ # @param [String] source_dir
114
+ # @param [String] destination_dir
115
+ # @return [void]
116
+ def batch_upload_to_gcs(source_dir, destination_dir, cache_control: 3600)
117
+ gsutil.batch_copy(
118
+ source_dir: source_dir,
119
+ destination_dir: destination_dir,
120
+ bucket: bucket_name,
121
+ cache_control: cache_control
122
+ )
89
123
  end
90
124
 
91
125
  # Fabricate key for s3 object
@@ -47,12 +47,15 @@ module Publisher
47
47
  #
48
48
  # @return [void]
49
49
  def download_history
50
- HISTORY.each do |file|
50
+ log_debug("Downloading previous run history")
51
+ HISTORY.each do |file_name|
52
+ file_path = path(common_info_path, "history", file_name)
51
53
  client.get_object(
52
- response_target: path(common_info_path, "history", file),
53
- key: key(prefix, "history", file),
54
+ response_target: file_path,
55
+ key: key(prefix, "history", file_name),
54
56
  bucket: bucket_name
55
57
  )
58
+ log_debug("Downloaded '#{file_name}' as '#{file_path}'")
56
59
  end
57
60
  rescue Aws::S3::Errors::NoSuchKey
58
61
  raise(HistoryNotFoundError, "Allure history from previous runs not found!")
@@ -62,6 +65,7 @@ module Publisher
62
65
  #
63
66
  # @return [void]
64
67
  def upload_history
68
+ log_debug("Uploading report history")
65
69
  upload_to_s3(report_files.select { |file| file.fnmatch?("*/history/*") }, prefix)
66
70
  end
67
71
 
@@ -69,6 +73,7 @@ module Publisher
69
73
  #
70
74
  # @return [void]
71
75
  def upload_report
76
+ log_debug("Uploading report files")
72
77
  upload_to_s3(report_files, full_prefix)
73
78
  end
74
79
 
@@ -76,6 +81,7 @@ module Publisher
76
81
  #
77
82
  # @return [void]
78
83
  def upload_latest_copy
84
+ log_debug("Uploading report copy as latest report")
79
85
  upload_to_s3(report_files, prefix, cache_control: 60)
80
86
  end
81
87
 
@@ -85,6 +91,7 @@ module Publisher
85
91
  # @param [String] key_prefix
86
92
  # @return [Array<Hash>]
87
93
  def upload_to_s3(files, key_prefix, cache_control: 3600)
94
+ threads = 8
88
95
  args = files.map do |file|
89
96
  {
90
97
  body: File.new(file),
@@ -95,7 +102,9 @@ module Publisher
95
102
  }
96
103
  end
97
104
 
98
- Parallel.each(args, in_threads: 8) { |obj| client.put_object(obj) }
105
+ log_debug("Uploading '#{args.size}' files in '#{threads}' threads")
106
+ Parallel.each(args, in_threads: threads) { |obj| client.put_object(obj) }
107
+ log_debug("Finished upload successfully")
99
108
  end
100
109
 
101
110
  # Fabricate key for s3 object
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Publisher
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -18,4 +18,4 @@ module Publisher
18
18
  end
19
19
  end
20
20
 
21
- Publisher::Commands.before("upload") { Publisher::Helpers.validate_allure_cli_present }
21
+ Publisher::Commands.before("upload") { Publisher::Helpers.allure_cli? }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: allure-report-publisher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrejs Cunskis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-25 00:00:00.000000000 Z
11
+ date: 2022-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-s3
@@ -202,6 +202,20 @@ dependencies:
202
202
  - - "~>"
203
203
  - !ruby/object:Gem::Version
204
204
  version: 0.9.3
205
+ - !ruby/object:Gem::Dependency
206
+ name: activesupport
207
+ requirement: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - "~>"
210
+ - !ruby/object:Gem::Version
211
+ version: '7.0'
212
+ type: :development
213
+ prerelease: false
214
+ version_requirements: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - "~>"
217
+ - !ruby/object:Gem::Version
218
+ version: '7.0'
205
219
  - !ruby/object:Gem::Dependency
206
220
  name: allure-rspec
207
221
  requirement: !ruby/object:Gem::Requirement
@@ -231,19 +245,19 @@ dependencies:
231
245
  - !ruby/object:Gem::Version
232
246
  version: 1.2.0
233
247
  - !ruby/object:Gem::Dependency
234
- name: pry-byebug
248
+ name: debug
235
249
  requirement: !ruby/object:Gem::Requirement
236
250
  requirements:
237
- - - "~>"
251
+ - - ">="
238
252
  - !ruby/object:Gem::Version
239
- version: '3.9'
253
+ version: 1.0.0
240
254
  type: :development
241
255
  prerelease: false
242
256
  version_requirements: !ruby/object:Gem::Requirement
243
257
  requirements:
244
- - - "~>"
258
+ - - ">="
245
259
  - !ruby/object:Gem::Version
246
- version: '3.9'
260
+ version: 1.0.0
247
261
  - !ruby/object:Gem::Dependency
248
262
  name: rake
249
263
  requirement: !ruby/object:Gem::Requirement
@@ -362,14 +376,14 @@ dependencies:
362
376
  requirements:
363
377
  - - "~>"
364
378
  - !ruby/object:Gem::Version
365
- version: 0.46.0
379
+ version: 0.47.0
366
380
  type: :development
367
381
  prerelease: false
368
382
  version_requirements: !ruby/object:Gem::Requirement
369
383
  requirements:
370
384
  - - "~>"
371
385
  - !ruby/object:Gem::Version
372
- version: 0.46.0
386
+ version: 0.47.0
373
387
  description: Upload allure reports to different file storage providers
374
388
  email:
375
389
  - andrejs.cunskis@gmail.com
@@ -383,6 +397,7 @@ files:
383
397
  - lib/allure_report_publisher.rb
384
398
  - lib/allure_report_publisher/commands/upload.rb
385
399
  - lib/allure_report_publisher/commands/version.rb
400
+ - lib/allure_report_publisher/lib/helpers/gsutil.rb
386
401
  - lib/allure_report_publisher/lib/helpers/helpers.rb
387
402
  - lib/allure_report_publisher/lib/helpers/spinner.rb
388
403
  - lib/allure_report_publisher/lib/helpers/summary.rb