renv 0.0.1 → 1.0.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
  SHA1:
3
- metadata.gz: e26c29836717d549fdf77aeb14b7532b0dc36f8c
4
- data.tar.gz: 0e2ec7d01003e5582aec6d90d2c1cce9ff508e19
3
+ metadata.gz: 2ce592555a68c352b441bafb892b77a01ff64d93
4
+ data.tar.gz: 424d50fc6061eea8ea4367930c74b503abb07fea
5
5
  SHA512:
6
- metadata.gz: 7b68c0ecca614b4c6e088a78e17d9f3e3343ad00d7b52711cfa83143b97c15eb53161cb2dc6ab16d2fb67215d77f55daf42fe5844acfc5b90079ef134bdf6c7e
7
- data.tar.gz: 9aa845d58d33b6700b4b1180e9d1e8e1b139a31a7b308d4afc1e186d1e989eb3bb6b0cf3c7514b2ea596c9edbb6c20be7160f3e34e58f324fd70b6eb163f4f92
6
+ metadata.gz: e4cf5e5ac2314ef0ebfeb797dc43e2d0c6853e30e63339751efd503751b4caeb93481f6226e5b95fa55dca7a3525bd5ff89452084854eb94b0d178ff9594e5d6
7
+ data.tar.gz: d49b2c4950e42f474dc63fa581d9431ab2ac7f0367cc51a30ae82bd64e57d586be30952afdb36f416aef16885935e6e84fc9f18342715905fc587335b54c637f
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+ script:
5
+ - bundle exec rspec
@@ -0,0 +1,18 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ # Note: The cmd option is now required due to the increasing number of ways
5
+ # rspec may be run, below are examples of the most common uses.
6
+ # * bundler: 'bundle exec rspec'
7
+ # * bundler binstubs: 'bin/rspec'
8
+ # * spring: 'bin/rsspec' (This will use spring if running and you have
9
+ # installed the spring binstubs per the docs)
10
+ # * zeus: 'zeus rspec' (requires the server to be started separetly)
11
+ # * 'just' rspec: 'rspec'
12
+ guard :rspec, cmd: 'bundle exec rspec' do
13
+ watch(%r{^spec/.+_spec\.rb$})
14
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
15
+ watch('spec/spec_helper.rb') { "spec" }
16
+ end
17
+
18
+ # vi: ft=ruby
data/README.md CHANGED
@@ -7,6 +7,8 @@ The name stands for "Remote ENVironment" (thanks, captain obvious).
7
7
  It can be used to provide a replacement to Heroku's superb `config:get` /
8
8
  `config:set` in Capistrano-land.
9
9
 
10
+ ![Version](https://badge.fury.io/rb/renv.svg)
11
+ ![Build status](https://travis-ci.org/HouseTrip/renv.svg?branch=master)
10
12
 
11
13
  ## Installation
12
14
 
@@ -37,16 +37,21 @@ module Renv
37
37
  private
38
38
 
39
39
  def _engine
40
+ connection = Connection.new(
41
+ app: options[:app],
42
+ bucket: options[:bucket]
43
+ )
40
44
  Engine.new(
41
- app: options[:app],
42
- name: options[:name],
43
- bucket: options[:bucket])
45
+ name: options[:name],
46
+ connection: connection)
44
47
  end
45
48
 
49
+ # Transforms an array of KEY=VALUE pairs into a { KEY => VALUE } hash.
50
+ # The key is the part at the left of the first equals sign.
46
51
  def _parse_pairs(pairs)
47
52
  Hash.new.tap do |h|
48
53
  pairs.each do |p|
49
- if p !~ /^([^=]+)=(.*)$/
54
+ if p !~ /^([^=]+)=(.*)$/ # left/right of the first equals sign
50
55
  $stderr.puts "Not a valid key-value: '#{p}'"
51
56
  exit 1
52
57
  end
@@ -0,0 +1,53 @@
1
+ require 'fog'
2
+ require 'delegate'
3
+ require 'renv'
4
+
5
+ module Renv
6
+ class Connection < SimpleDelegator
7
+
8
+ def initialize(app: nil, bucket: bucket)
9
+ @_app = app
10
+ @_bucket = bucket
11
+
12
+ connection = Fog::Storage.new(
13
+ provider: 'AWS',
14
+ aws_access_key_id: ENV.fetch("RENV_AWS_KEY_#{_app}"),
15
+ aws_secret_access_key: ENV.fetch("RENV_AWS_SECRET_#{_app}"),
16
+ region: ENV.fetch("RENV_AWS_REGION_#{_app}", 'eu-west-1')
17
+ )
18
+
19
+ if connection.nil?
20
+ $stderr.puts "Failed to connect to AWS, please check your key and secret."
21
+ exit 1
22
+ end
23
+
24
+ bucket = connection.directories.get(_bucket).tap do |b|
25
+ if b.nil?
26
+ $stderr.puts "Bucket '#{_bucket}' does not seem to exist"
27
+ exit 1
28
+ end
29
+ end
30
+
31
+ super bucket
32
+
33
+ rescue Excon::Errors::Forbidden
34
+ $stderr.puts "Credentials rejected by AWS, please check your settings."
35
+ exit 1
36
+ end
37
+
38
+
39
+ def app_name ; _app ; end
40
+
41
+ private
42
+
43
+ def _app
44
+ @_app ||= ENV.fetch('RENV_APP')
45
+ end
46
+
47
+ def _bucket
48
+ @_bucket ||= ENV.fetch("RENV_BUCKET_#{_app}")
49
+ end
50
+
51
+ end
52
+ end
53
+
@@ -5,7 +5,7 @@ module Renv
5
5
  class Data
6
6
  extend Forwardable
7
7
 
8
- def initialize(payload)
8
+ def initialize(payload = '')
9
9
  @data = _parse(payload)
10
10
  end
11
11
 
@@ -22,7 +22,8 @@ module Renv
22
22
  end
23
23
 
24
24
  def load(payload)
25
- @data = _parse(payload).merge(@data)
25
+ @data = @data.merge(_parse(payload))
26
+ self
26
27
  end
27
28
 
28
29
  private
@@ -1,19 +1,22 @@
1
1
  require 'renv'
2
2
  require 'fog'
3
3
  require 'renv/data'
4
+ require 'renv/connection'
4
5
 
5
6
  module Renv
6
7
  class Engine
7
- def initialize(app: nil, name: nil, bucket: nil)
8
- @_app = app
9
- @_name = name
10
- @_bucket = bucket
8
+ def initialize(connection:, name: nil, data: nil)
9
+ @_name = name
10
+ @_connection = connection
11
+ @_data = data || Data.new
12
+ @_loaded = false
11
13
  end
12
14
 
13
15
  def get(key)
14
16
  _data[key]
15
17
  end
16
18
 
19
+ # Sets one or more key-value pairs
17
20
  def set(hash)
18
21
  hash.each_pair do |key, value|
19
22
  _data[key] = value
@@ -21,6 +24,7 @@ module Renv
21
24
  _save
22
25
  end
23
26
 
27
+ # Deletes one or more keys-value pairs
24
28
  def del(keys)
25
29
  keys.each { |key| _data.delete(key) }
26
30
  _save
@@ -38,16 +42,16 @@ module Renv
38
42
  private
39
43
 
40
44
  def _data
41
- @_data ||= begin
42
- s3file = _directory.files.get(_path_current)
43
- payload = s3file ? s3file.body : ''
44
- Data.new(payload)
45
- end
45
+ return @_data if @_loaded
46
+ s3file = @_connection.files.get(_path_current)
47
+ payload = s3file ? s3file.body : ''
48
+ @_loaded = true
49
+ @_data.load(payload)
46
50
  end
47
51
 
48
52
  def _save
49
53
  [_path_new, _path_current].each do |path|
50
- _directory.files.create(key: path, body: _data.dump, public: false)
54
+ @_connection.files.create(key: path, body: _data.dump, public: false)
51
55
  end
52
56
  end
53
57
 
@@ -55,38 +59,17 @@ module Renv
55
59
  @_path_current ||= "#{_name}/current"
56
60
  end
57
61
 
62
+ # "Backup" path, which is a timestamp in ISO format (2014-08-07T11:24:25)
58
63
  def _path_new
59
64
  @_path_new ||= "#{_name}/#{Time.now.strftime('%FT%T')}"
60
65
  end
61
66
 
62
- def _directory
63
- @_directory ||= _connection.directories.get(_bucket).tap do |dir|
64
- if dir.nil?
65
- $stderr.puts "Bucket '#{_bucket}' does not seem to exist"
66
- exit 1
67
- end
68
- end
69
- end
70
-
71
- def _connection
72
- @_connection ||= Fog::Storage.new(
73
- provider: 'AWS',
74
- aws_access_key_id: ENV.fetch("RENV_AWS_KEY_#{_app}"),
75
- aws_secret_access_key: ENV.fetch("RENV_AWS_SECRET_#{_app}"),
76
- region: ENV.fetch("RENV_AWS_REGION_#{_app}", 'eu-west-1')
77
- )
78
- end
79
-
80
- def _bucket
81
- @_bucket ||= ENV.fetch("RENV_BUCKET_#{_app}")
82
- end
83
-
84
67
  def _name
85
- @_name ||= _app
68
+ @_name ||= @_connection.app_name
86
69
  end
87
70
 
88
71
  def _app
89
- @_app ||= ENV.fetch('RENV_APP')
72
+ @_connection.app
90
73
  end
91
74
 
92
75
  end
@@ -1,3 +1,3 @@
1
1
  module Renv
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.add_development_dependency 'bundler', '~> 1.6'
21
21
  spec.add_development_dependency 'rake'
22
22
  spec.add_development_dependency 'pry'
23
+ spec.add_development_dependency 'guard-rspec'
24
+ spec.add_development_dependency 'timecop'
23
25
 
24
26
  spec.add_runtime_dependency 'fog'
25
27
  spec.add_runtime_dependency 'thor'
@@ -0,0 +1,91 @@
1
+ require 'renv/data'
2
+
3
+ describe Renv::Data do
4
+ let(:payload) { '' }
5
+ subject { described_class.new(payload) }
6
+
7
+ context 'with a simple payload' do
8
+ let(:payload) { "FOO=bar\nBAR=baz" }
9
+
10
+ describe '#[]' do
11
+ it 'returns nil for unknown keys' do
12
+ expect(subject['DO_YOU_EVEN']).to be_nil
13
+ end
14
+
15
+ it 'returns key values' do
16
+ expect(subject['FOO']).to eq('bar')
17
+ end
18
+ end
19
+
20
+ describe '#[]=' do
21
+ it 'aborts on bad keys' do
22
+ expect { subject['hello, world!'] = 'foo' }.to raise_error(SystemExit)
23
+ end
24
+
25
+ it 'sets key values' do
26
+ subject['DO_YOU'] = 'even'
27
+ expect(subject['DO_YOU']).to eq('even')
28
+ end
29
+ end
30
+
31
+ describe '#dump' do
32
+ it 'serializes the hash' do
33
+ subject['BAZ'] = 'qux'
34
+ expect(subject.dump).to eq("FOO=bar\nBAR=baz\nBAZ=qux\n")
35
+ end
36
+ end
37
+
38
+ describe '#load' do
39
+ it 'adds extra keys' do
40
+ subject.load('QUX=even')
41
+ expect(subject['QUX']).to eq('even')
42
+ end
43
+
44
+ it 'does not remove existing keys' do
45
+ subject.load('QUX=even')
46
+ expect(subject['FOO']).to eq('bar')
47
+ end
48
+
49
+ it 'replaces same keys' do
50
+ subject.load('FOO=qux')
51
+ expect(subject['FOO']).to eq('qux')
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#initialize' do
57
+ it 'does not require a payload' do
58
+ expect { described_class.new }.not_to raise_error
59
+ end
60
+
61
+ it 'accepts comments' do
62
+ payload.replace "# comment1\nFOO=bar\n# comment 2"
63
+ expect(subject['FOO']).to eq('bar')
64
+ end
65
+
66
+ it 'accepts blank lines' do
67
+ payload.replace "\n\nFOO=bar\n\n\n# comment 2\n\n"
68
+ expect(subject['FOO']).to eq('bar')
69
+ end
70
+
71
+ it 'accepts multiple equal signs' do
72
+ payload.replace "FOO=bar=baz"
73
+ expect(subject['FOO']).to eq('bar=baz')
74
+ end
75
+
76
+ it 'accepts spaces in values' do
77
+ payload.replace "FOO=bar baz"
78
+ expect(subject['FOO']).to eq('bar baz')
79
+ end
80
+
81
+ it 'rejects misformatted pairs' do
82
+ payload.replace "FOO: bar baz"
83
+ expect { subject }.to raise_error(SystemExit)
84
+ end
85
+
86
+ it 'only loads the last of identical keys' do
87
+ payload.replace "FOO=bar\nFOO=qux"
88
+ expect(subject['FOO']).to eq('qux')
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,141 @@
1
+ require 'renv/engine'
2
+ require 'timecop'
3
+ require 'fog'
4
+
5
+ describe Renv::Engine do
6
+ let(:tempdir) { Pathname.new('tmp').join("%08x" % rand(1<<31)) }
7
+ let(:name) { 'staging' }
8
+ let(:app_name) { 'testapp' }
9
+ let(:data) { Renv::Data.new }
10
+
11
+ let(:connection) do
12
+ c = Fog::Storage.new(provider: 'Local', local_root: tempdir.to_s)
13
+ c.directories.create(key: 'testbucket')
14
+ end
15
+
16
+ let(:options) {{ name: name, connection: connection, data: data }}
17
+
18
+ let(:default_data) { "KEY1=value1\nKEY2=value2" }
19
+
20
+ subject { described_class.new(**options) }
21
+
22
+ def data_for(entry, value = nil)
23
+ path = tempdir.join("testbucket/#{name}/#{entry}")
24
+ if value
25
+ path.parent.mkpath
26
+ path.write(value)
27
+ elsif path.exist?
28
+ path.read
29
+ else
30
+ nil
31
+ end
32
+ end
33
+
34
+ around do |example|
35
+ tempdir.mkpath
36
+ example.run
37
+ tempdir.rmtree
38
+ end
39
+
40
+ before do
41
+ allow(connection).to receive(:app_name).and_return(app_name)
42
+ # TODO: proper separation would use the injected Data dependency
43
+ # and do the following instead of parsing files:
44
+ # allow(data).to receive(:dump).and_return('dump')
45
+ end
46
+
47
+ before do
48
+ data_for(:current, default_data) if default_data
49
+ end
50
+
51
+ shared_examples 'writer' do
52
+ it 'creates a backup' do
53
+ timestamp = '2014-07-30T01:23:45'
54
+ Timecop.freeze(timestamp) { perform }
55
+ expect(data_for(timestamp)).not_to be_nil
56
+ end
57
+ end
58
+
59
+ shared_examples 'preserving existing keypairs' do
60
+ it 'leaves existing keypairs intact' do
61
+ data_for(:current, "#{default_data}\nPRESERVED=value\n")
62
+ perform
63
+ expect(data_for(:current)).to match(/^PRESERVED=value$/)
64
+ end
65
+ end
66
+
67
+ shared_examples 'initial conditions' do
68
+ let(:default_data) { nil }
69
+
70
+ it 'has no initial data' do
71
+ expect(data_for(:current)).to be_nil
72
+ end
73
+
74
+ it 'works with an empty bucket' do
75
+ expect { perform }.not_to raise_error
76
+ end
77
+ end
78
+
79
+ describe 'set' do
80
+ let(:perform) { subject.set('FOO' => 'bar', 'BAZ' => 'qux') }
81
+ it 'writes keys to file' do
82
+ perform
83
+ expect(data_for(:current)).to match(/^FOO=bar$/)
84
+ expect(data_for(:current)).to match(/^BAZ=qux$/)
85
+ end
86
+
87
+ it_behaves_like 'writer'
88
+ it_behaves_like 'preserving existing keypairs'
89
+ it_behaves_like 'initial conditions'
90
+ end
91
+
92
+ describe 'del' do
93
+ let(:perform) { subject.del(['KEY1']) }
94
+
95
+ it 'deletes key from store' do
96
+ perform
97
+ expect(data_for(:current)).not_to match(/^KEY1=/)
98
+ end
99
+
100
+ it_behaves_like 'writer'
101
+ it_behaves_like 'preserving existing keypairs'
102
+ it_behaves_like 'initial conditions'
103
+ end
104
+
105
+ describe 'load' do
106
+ let(:perform) { subject.load("FOO=bar\nBAZ=qux") }
107
+
108
+ it 'deletes key from store' do
109
+ perform
110
+ expect(data_for(:current)).to match(/^FOO=bar$/)
111
+ expect(data_for(:current)).to match(/^BAZ=qux$/)
112
+ end
113
+
114
+ it_behaves_like 'writer'
115
+ it_behaves_like 'preserving existing keypairs'
116
+ it_behaves_like 'initial conditions'
117
+ end
118
+
119
+ describe 'get' do
120
+ let(:perform) { subject.get('KEY1') }
121
+
122
+ it 'returns the value' do
123
+ expect(perform).to eq('value1')
124
+ end
125
+
126
+ it_behaves_like 'preserving existing keypairs'
127
+ it_behaves_like 'initial conditions'
128
+ end
129
+
130
+ describe 'dump' do
131
+ let(:perform) { subject.dump }
132
+
133
+ it 'returns the value' do
134
+ expect(perform).to match(/^KEY1=value1$/)
135
+ expect(perform).to match(/^KEY2=value2$/)
136
+ end
137
+
138
+ it_behaves_like 'preserving existing keypairs'
139
+ it_behaves_like 'initial conditions'
140
+ end
141
+ end
@@ -0,0 +1,78 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, make a
10
+ # separate helper file that requires this one and then use it only in the specs
11
+ # that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+ RSpec.configure do |config|
18
+ # The settings below are suggested to provide a good initial experience
19
+ # with RSpec, but feel free to customize to your heart's content.
20
+ =begin
21
+ # These two settings work together to allow you to limit a spec run
22
+ # to individual examples or groups you care about by tagging them with
23
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
24
+ # get run.
25
+ config.filter_run :focus
26
+ config.run_all_when_everything_filtered = true
27
+
28
+ # Many RSpec users commonly either run the entire suite or an individual
29
+ # file, and it's useful to allow more verbose output when running an
30
+ # individual spec file.
31
+ if config.files_to_run.one?
32
+ # Use the documentation formatter for detailed output,
33
+ # unless a formatter has already been configured
34
+ # (e.g. via a command-line flag).
35
+ config.default_formatter = 'doc'
36
+ end
37
+
38
+ # Print the 10 slowest examples and example groups at the
39
+ # end of the spec run, to help surface which specs are running
40
+ # particularly slow.
41
+ config.profile_examples = 10
42
+
43
+ # Run specs in random order to surface order dependencies. If you find an
44
+ # order dependency and want to debug it, you can fix the order by providing
45
+ # the seed, which is printed after each run.
46
+ # --seed 1234
47
+ config.order = :random
48
+
49
+ # Seed global randomization in this process using the `--seed` CLI option.
50
+ # Setting this allows you to use `--seed` to deterministically reproduce
51
+ # test failures related to randomization by passing the same `--seed` value
52
+ # as the one that triggered the failure.
53
+ Kernel.srand config.seed
54
+
55
+ # rspec-expectations config goes here. You can use an alternate
56
+ # assertion/expectation library such as wrong or the stdlib/minitest
57
+ # assertions if you prefer.
58
+ config.expect_with :rspec do |expectations|
59
+ # Enable only the newer, non-monkey-patching expect syntax.
60
+ # For more details, see:
61
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
62
+ expectations.syntax = :expect
63
+ end
64
+
65
+ # rspec-mocks config goes here. You can use an alternate test double
66
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
67
+ config.mock_with :rspec do |mocks|
68
+ # Enable only the newer, non-monkey-patching expect syntax.
69
+ # For more details, see:
70
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
71
+ mocks.syntax = :expect
72
+
73
+ # Prevents you from mocking or stubbing a method that does not exist on
74
+ # a real object. This is generally recommended.
75
+ mocks.verify_partial_doubles = true
76
+ end
77
+ =end
78
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: renv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Letessier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-24 00:00:00.000000000 Z
11
+ date: 2014-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: timecop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: fog
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -89,17 +117,24 @@ extensions: []
89
117
  extra_rdoc_files: []
90
118
  files:
91
119
  - ".gitignore"
120
+ - ".rspec"
121
+ - ".travis.yml"
92
122
  - Gemfile
123
+ - Guardfile
93
124
  - LICENSE.txt
94
125
  - README.md
95
126
  - Rakefile
96
127
  - bin/renv
97
128
  - lib/renv.rb
98
129
  - lib/renv/cli.rb
130
+ - lib/renv/connection.rb
99
131
  - lib/renv/data.rb
100
132
  - lib/renv/engine.rb
101
133
  - lib/renv/version.rb
102
134
  - renv.gemspec
135
+ - spec/renv/data_spec.rb
136
+ - spec/renv/engine_spec.rb
137
+ - spec/spec_helper.rb
103
138
  homepage: ''
104
139
  licenses:
105
140
  - MIT
@@ -124,4 +159,7 @@ rubygems_version: 2.2.2
124
159
  signing_key:
125
160
  specification_version: 4
126
161
  summary: Manages out-of-repository .env file
127
- test_files: []
162
+ test_files:
163
+ - spec/renv/data_spec.rb
164
+ - spec/renv/engine_spec.rb
165
+ - spec/spec_helper.rb