Skip to content

Commit af829d4

Browse files
committed
Google Cloud Storage uploader
1 parent d823f51 commit af829d4

File tree

4 files changed

+119
-2
lines changed

4 files changed

+119
-2
lines changed

README.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,12 @@ end
201201
```
202202

203203

204-
Uploading screenshots to S3
204+
Uploading screenshots to AWS S3 or Google Cloud Storage
205205
--------------------------
206-
You can configure capybara-screenshot to automatically save your screenshots to an AWS S3 bucket.
206+
You can configure capybara-screenshot to automatically save your screenshots to either AWS S3
207+
or Google Cloud Storage bucket but noth both.
207208

209+
### AWS S3
208210
First, install the `aws-sdk-s3` gem or add it to your Gemfile
209211

210212
```ruby
@@ -243,6 +245,36 @@ Capybara::Screenshot.s3_configuration = {
243245
}
244246
```
245247

248+
### GCS
249+
250+
Google Cloud Storage configuration is very simiar to that of S3.
251+
Install the `google-cloud-storage` gem or add it to your Gemfile.
252+
253+
Next, configure capybara-screenshot with your GCS credentials either stored in a
254+
[JSON file](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
255+
or as a Hash, and the bucket to save to.
256+
Note that one may use [environment variables to set up credentials](https://googleapis.github.io/google-cloud-ruby/docs/google-cloud-storage/latest/file.AUTHENTICATION) as well.
257+
258+
```ruby
259+
Capybara::Screenshot.gcs_configuration = {
260+
credentials: 'path-to-credentials.json',
261+
bucket_name: 'my_screenshots',
262+
key_prefix: "some/folder/"
263+
}
264+
```
265+
266+
It is also possible to specify object metadata.
267+
If gzip content encoding is specified, uploaded files will be compressed for you to save on storage space.
268+
Configure the capybara-screenshot with these options in this way:
269+
270+
```ruby
271+
Capybara::Screenshot.gcs_object_configuration = {
272+
content_encoding: 'gzip',
273+
acl: 'public_read'
274+
}
275+
```
276+
277+
246278
Pruning old screenshots automatically
247279
--------------------------
248280
By default screenshots are saved indefinitely, if you want them to be automatically pruned on a new failure, then you can specify one of the following prune strategies as follows:

capybara-screenshot.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
3434
s.add_development_dependency 'spinach'
3535
s.add_development_dependency 'minitest'
3636
s.add_development_dependency 'aws-sdk-s3'
37+
s.add_development_dependency 'google-cloud-storage'
3738

3839
s.files = `git ls-files`.split("\n")
3940
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")

lib/capybara-screenshot.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class << self
1111
attr_accessor :prune_strategy
1212
attr_accessor :s3_configuration
1313
attr_accessor :s3_object_configuration
14+
attr_accessor :gcs_configuration
15+
attr_accessor :gcs_object_configuration
1416
end
1517

1618
self.autosave_on_failure = true
@@ -22,6 +24,8 @@ class << self
2224
self.prune_strategy = :keep_all
2325
self.s3_configuration = {}
2426
self.s3_object_configuration = {}
27+
self.gcs_configuration = {}
28+
self.gcs_object_configuration = {}
2529

2630
def self.append_screenshot_path=(value)
2731
$stderr.puts "WARNING: Capybara::Screenshot.append_screenshot_path is deprecated. " +
@@ -102,6 +106,11 @@ def self.new_saver(*args)
102106
saver = S3Saver.new_with_configuration(saver, s3_configuration, s3_object_configuration)
103107
end
104108

109+
unless gcs_configuration.empty?
110+
require 'capybara-screenshot/gcs_saver'
111+
saver = GcsSaver.new_with_configuration(saver, gcs_configuration, gcs_object_configuration)
112+
end
113+
105114
return saver
106115
end
107116

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
require 'zlib'
2+
require 'google/cloud/storage'
3+
4+
module Capybara
5+
module Screenshot
6+
class GcsSaver
7+
attr_accessor :html_path, :screenshot_path
8+
9+
def initialize(saver, bucket, object_configuration, key_prefix)
10+
@saver = saver
11+
@bucket = bucket
12+
@key_prefix = key_prefix
13+
@object_configuration = object_configuration
14+
end
15+
16+
def self.new_with_configuration(saver, configuration, object_configuration)
17+
conf = configuration.dup
18+
bucket_name = conf.delete(:bucket_name)
19+
key_prefix = conf.delete(:key_prefix)
20+
storage = Google::Cloud::Storage.new conf
21+
bucket = storage.bucket bucket_name, skip_lookup: true
22+
23+
new(saver, bucket, object_configuration, key_prefix)
24+
rescue KeyError
25+
raise "Invalid GCS Configuration #{configuration}. Please refer to the documentation for the necessary configurations."
26+
end
27+
28+
def save_and_upload_screenshot
29+
save_and do |type, local_file_path|
30+
if object_configuration.fetch(:content_encoding, '').to_sym.eql?(:gzip)
31+
compressed = StringIO.new ""
32+
gz = Zlib::GzipWriter.new(compressed, Zlib::BEST_COMPRESSION)
33+
gz.mtime = File.mtime(local_file_path)
34+
gz.orig_name = local_file_path
35+
gz.write IO.binread(local_file_path)
36+
gz.close
37+
data = StringIO.new compressed.string
38+
else
39+
data = local_file_path
40+
end
41+
gcs_upload_path = "#{@key_prefix}#{File.basename(local_file_path)}"
42+
f = bucket.create_file data, gcs_upload_path, object_configuration
43+
if f.acl.readers.include? 'allUsers'
44+
url = f.public_url
45+
else
46+
url = "https://storage.cloud.google.com/#{bucket.name}/#{gcs_upload_path}"
47+
end
48+
send("#{type}_path=", url)
49+
end
50+
end
51+
alias_method :save, :save_and_upload_screenshot
52+
53+
def method_missing(method, *args)
54+
# Need to use @saver instead of S3Saver#saver attr_reader method because
55+
# using the method goes into infinite loop. Maybe attr_reader implements
56+
# its methods via method_missing?
57+
@saver.send(method, *args)
58+
end
59+
60+
private
61+
attr_reader :saver,
62+
:gcs_client,
63+
:bucket,
64+
:object_configuration
65+
:key_prefix
66+
67+
def save_and
68+
saver.save
69+
70+
yield(:html, saver.html_path) if block_given? && saver.html_saved?
71+
yield(:screenshot, saver.screenshot_path) if block_given? && saver.screenshot_saved?
72+
end
73+
end
74+
end
75+
end

0 commit comments

Comments
 (0)