Skip to content

Commit

Permalink
Google Cloud Storage uploader
Browse files Browse the repository at this point in the history
  • Loading branch information
mlt committed Oct 15, 2018
1 parent d823f51 commit a57e728
Showing 4 changed files with 113 additions and 2 deletions.
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -201,10 +201,12 @@ end
```


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

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

```ruby
@@ -243,6 +245,35 @@ Capybara::Screenshot.s3_configuration = {
}
```

### GCS

Google Cloud Storage configuration is very simiar to that of S3.
Install the `google-cloud-storage` gem or add it to your Gemfile.

Next, configure capybara-screenshot with your GCS credentials either stored in a
[JSON file](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
or as a Hash, and the bucket to save to.
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.

```ruby
Capybara::Screenshot.gcs_configuration = {
credentials: 'path-to-credentials.json',
bucket_name: 'my_screenshots',
key_prefix: "some/folder/"
}
```

It is also possible to specify object metadata.
If gzip content encoding is specified, uploaded files will be compressed for you to save on storage space.
Configure the capybara-screenshot with these options in this way:

```ruby
Capybara::Screenshot.gcs_object_configuration = {
content_encoding: 'gzip'
}
```


Pruning old screenshots automatically
--------------------------
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:
1 change: 1 addition & 0 deletions capybara-screenshot.gemspec
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'spinach'
s.add_development_dependency 'minitest'
s.add_development_dependency 'aws-sdk-s3'
s.add_development_dependency 'google-cloud-storage'

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
9 changes: 9 additions & 0 deletions lib/capybara-screenshot.rb
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@ class << self
attr_accessor :prune_strategy
attr_accessor :s3_configuration
attr_accessor :s3_object_configuration
attr_accessor :gcs_configuration
attr_accessor :gcs_object_configuration
end

self.autosave_on_failure = true
@@ -22,6 +24,8 @@ class << self
self.prune_strategy = :keep_all
self.s3_configuration = {}
self.s3_object_configuration = {}
self.gcs_configuration = {}
self.gcs_object_configuration = {}

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

unless gcs_configuration.empty?
require 'capybara-screenshot/gcs_saver'
saver = GcsSaver.new_with_configuration(saver, gcs_configuration, gcs_object_configuration)
end

return saver
end

70 changes: 70 additions & 0 deletions lib/capybara-screenshot/gcs_saver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
require 'zlib'
require 'google/cloud/storage'

module Capybara
module Screenshot
class GcsSaver
attr_accessor :html_path, :screenshot_path

def initialize(saver, bucket, object_configuration, key_prefix)
@saver = saver
@bucket = bucket
@key_prefix = key_prefix
@object_configuration = object_configuration
end

def self.new_with_configuration(saver, configuration, object_configuration)
conf = configuration.dup
bucket_name = conf.delete(:bucket_name)
key_prefix = conf.delete(:key_prefix)
storage = Google::Cloud::Storage.new conf
bucket = storage.bucket bucket_name, skip_lookup: true

new(saver, bucket, object_configuration, key_prefix)
rescue KeyError
raise "Invalid GCS Configuration #{configuration}. Please refer to the documentation for the necessary configurations."
end

def save_and_upload_screenshot
save_and do |type, local_file_path|
if object_configuration.fetch(:content_encoding, '').to_sym.eql?(:gzip)
compressed = StringIO.new ""
gz = Zlib::GzipWriter.new(compressed, Zlib::BEST_COMPRESSION)
gz.mtime = File.mtime(local_file_path)
gz.orig_name = local_file_path
gz.write IO.binread(local_file_path)
gz.close
data = StringIO.new compressed.string
else
data = local_file_path
end
gcs_upload_path = "#{@key_prefix}#{File.basename(local_file_path)}"
bucket.create_file data, gcs_upload_path, object_configuration
send("#{type}_path=", "https://storage.cloud.google.com/#{bucket.name}/#{gcs_upload_path}")
end
end
alias_method :save, :save_and_upload_screenshot

def method_missing(method, *args)
# Need to use @saver instead of S3Saver#saver attr_reader method because
# using the method goes into infinite loop. Maybe attr_reader implements
# its methods via method_missing?
@saver.send(method, *args)
end

private
attr_reader :saver,
:gcs_client,
:bucket,
:object_configuration
:key_prefix

def save_and
saver.save

yield(:html, saver.html_path) if block_given? && saver.html_saved?
yield(:screenshot, saver.screenshot_path) if block_given? && saver.screenshot_saved?
end
end
end
end

0 comments on commit a57e728

Please sign in to comment.