chamber 2.13.0 → 3.0.0rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +101 -26
  5. data/lib/chamber.rb +77 -16
  6. data/lib/chamber/adapters/cloud/circle_ci.rb +16 -13
  7. data/lib/chamber/adapters/cloud/heroku.rb +40 -13
  8. data/lib/chamber/binary/circle_ci.rb +28 -14
  9. data/lib/chamber/binary/heroku.rb +34 -14
  10. data/lib/chamber/binary/runner.rb +40 -29
  11. data/lib/chamber/binary/travis.rb +10 -4
  12. data/lib/chamber/commands/base.rb +10 -16
  13. data/lib/chamber/commands/cloud/base.rb +3 -3
  14. data/lib/chamber/commands/cloud/pull.rb +2 -2
  15. data/lib/chamber/commands/cloud/push.rb +7 -7
  16. data/lib/chamber/commands/comparable.rb +2 -2
  17. data/lib/chamber/commands/compare.rb +6 -9
  18. data/lib/chamber/commands/initialize.rb +26 -22
  19. data/lib/chamber/commands/securable.rb +12 -9
  20. data/lib/chamber/commands/secure.rb +2 -2
  21. data/lib/chamber/commands/show.rb +8 -8
  22. data/lib/chamber/commands/sign.rb +2 -2
  23. data/lib/chamber/commands/verify.rb +2 -2
  24. data/lib/chamber/configuration.rb +6 -3
  25. data/lib/chamber/context_resolver.rb +7 -7
  26. data/lib/chamber/encryption_methods/ssl.rb +12 -12
  27. data/lib/chamber/file.rb +20 -15
  28. data/lib/chamber/file_set.rb +18 -8
  29. data/lib/chamber/files/signature.rb +16 -14
  30. data/lib/chamber/filters/decryption_filter.rb +19 -15
  31. data/lib/chamber/filters/encryption_filter.rb +14 -11
  32. data/lib/chamber/filters/environment_filter.rb +21 -20
  33. data/lib/chamber/filters/failed_decryption_filter.rb +9 -6
  34. data/lib/chamber/filters/insecure_filter.rb +4 -5
  35. data/lib/chamber/filters/namespace_filter.rb +13 -9
  36. data/lib/chamber/filters/secure_filter.rb +9 -7
  37. data/lib/chamber/filters/translate_secure_keys_filter.rb +9 -7
  38. data/lib/chamber/instance.rb +48 -31
  39. data/lib/chamber/key_pair.rb +7 -7
  40. data/lib/chamber/keys/base.rb +13 -13
  41. data/lib/chamber/keys/decryption.rb +3 -3
  42. data/lib/chamber/keys/encryption.rb +3 -3
  43. data/lib/chamber/namespace_set.rb +2 -4
  44. data/lib/chamber/refinements/array.rb +20 -0
  45. data/lib/chamber/refinements/deep_dup.rb +58 -0
  46. data/lib/chamber/refinements/enumerable.rb +36 -0
  47. data/lib/chamber/refinements/hash.rb +51 -0
  48. data/lib/chamber/settings.rb +81 -66
  49. data/lib/chamber/types/secured.rb +21 -23
  50. data/lib/chamber/version.rb +1 -1
  51. data/templates/settings.yml +2 -0
  52. metadata +44 -51
  53. metadata.gz.sig +0 -0
  54. data/lib/chamber/core_ext/hash.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e231bd41a0611bd30e8c2cbb2d8cc1178ecc1f570649be797468612fc63e922
4
- data.tar.gz: 19fb0f2721ec1fe8a24ea7244f42f58d2f82e9ca216414b126ec1d72665481ba
3
+ metadata.gz: 3119f8787d3c63913a0ab69a0114cbf6d43a154ad1703aef610a2b02720b0cbc
4
+ data.tar.gz: ed25f8e4a9f93045c94aba4776fa6a0296f9db9f1312e4a1dadeb35343eba140
5
5
  SHA512:
6
- metadata.gz: 45b656980d6e7ecf49f1ae008639506ec0462192a4ec7b58e577c8607db07333f5f2cf646314a86daa5c61c41b5abac6aac50a72ea34b2f69e8282a8e8766310
7
- data.tar.gz: 1ed02191209f650c8f3db3110fc7f7b743b466881a74089115bd00ba4001bd19e0aee8e8c373c5e8622339bf2cb4cc931b52067428da025d519da9f12aaf8c38
6
+ metadata.gz: acc3d5daf9e6570ccf16e76b8433e8d0912cdd85f4858f6634ee37531aa6a1c53b47621afeb21c0b9524eea6f8af3a02b52872f843b28a3f94d3e20bfa582880
7
+ data.tar.gz: 39a117062b19f734066f11c405730e499cc0325e6b2e3fd208aa68a930645e28f6b88f4f98e43133e8b70457d82ac3860f426b1385611b0d4b924003f79f0490
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -1,5 +1,33 @@
1
- # Chamber
2
- [![Gem Version](https://img.shields.io/gem/v/chamber.svg)](https://rubygems.org/gems/chamber) ![Rubygems Rank Overall](https://img.shields.io/gem/rt/chamber.svg) ![Rubygems Rank Daily](https://img.shields.io/gem/rd/chamber.svg) ![Rubygems Downloads](https://img.shields.io/gem/dv/chamber/stable.svg) [![Build Status](https://img.shields.io/travis/thekompanee/chamber/master.svg)](http://travis-ci.org/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber.svg)](https://codeclimate.com/github/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber/coverage.svg)](https://codeclimate.com/github/thekompanee/chamber)
1
+ Chamber
2
+ ================================================================================
3
+
4
+ <div align="center">
5
+ <a href="https://rubygems.org/gems/chamber" alt="RubyGems Version">
6
+ <img src="https://img.shields.io/gem/v/chamber.svg?style=flat-square&label=current-version" alt="RubyGems Version" />
7
+ </a>
8
+
9
+ <a href="https://rubygems.org/gems/chamber" alt="RubyGems Rank Overall">
10
+ <img src="https://img.shields.io/gem/rt/chamber.svg?style=flat-square&label=total-rank" alt="RubyGems Rank Overall" />
11
+ </a>
12
+
13
+ <a href="https://rubygems.org/gems/chamber" alt="RubyGems Rank Daily">
14
+ <img src="https://img.shields.io/gem/rd/chamber.svg?style=flat-square&label=daily-rank" alt="RubyGems Rank Daily" />
15
+ </a>
16
+
17
+ <a href="https://rubygems.org/gems/chamber" alt="RubyGems Downloads">
18
+ <img src="https://img.shields.io/gem/dt/chamber.svg?style=flat-square&label=total-downloads" alt="RubyGems Downloads" />
19
+ </a>
20
+
21
+ <a href="https://github.com/thekompanee/chamber/actions?query=workflow%3ABuild" alt="Build Status">
22
+ <img src="https://img.shields.io/github/workflow/status/thekompanee/chamber/Build?label=CI&style=flat-square&logo=github" alt="Build Status" />
23
+ </a>
24
+
25
+ <a href="#" alt="Maintainability">
26
+ <img src="https://img.shields.io/codeclimate/maintainability/thekompanee/chamber?style=flat-square&label=grade" alt="Maintainability" />
27
+ </a>
28
+ </div>
29
+
30
+ <br>
3
31
 
4
32
  Chamber is the auto-encrypting, extremely organizable, Heroku-loving,
5
33
  CLI-having, non-extra-repo-needing, non-Rails-specific-ing, CI-serving
@@ -9,17 +37,73 @@ We looked at all of the options out there and thought something was still
9
37
  missing, so we wrote Chamber. We made it with lots of ❤ and we hope you like it
10
38
  as much as we do.
11
39
 
12
- ## What Sets Chamber Apart?
40
+ What Sets Chamber Apart
41
+ --------------------------------------------------------------------------------
13
42
 
14
43
  For an idea of how Chamber compares to other popular libraries, check out our
15
44
  [Gem Comparison][comparison].
16
45
 
17
- ## Basic Usage
46
+ Basic Usage
47
+ --------------------------------------------------------------------------------
48
+
49
+ Before starting this guide, make sure you [install chamber][installation].
50
+
51
+ Once your app is initialized, you should have a `settings.yml` file somewhere.
52
+ A lot of times it's the root of your project and sometimes it's in a framework
53
+ specific location.
54
+
55
+ Inside of here you can define any settings you'd like like so:
56
+
57
+ ```yaml
58
+ # settings.yml
59
+
60
+ smtp_username: 'my_username'
61
+ smtp_password: 'my_password'
62
+ ```
63
+
64
+ From there you can access your settings by using the special `Chamber.env`
65
+ constant.
66
+
67
+ ```ruby
68
+ Chamber.env.smtp_password
69
+ # => 'my_password'
70
+ ```
71
+
72
+ If you want to encrypt a setting, prefix the setting name with `_secure_` like
73
+ so:
74
+
75
+ ```ruby
76
+ # settings.yml
77
+
78
+ smtp_username: 'my_username'
79
+ _secure_smtp_password: 'my_password'
80
+ ```
81
+
82
+ And then run `chamber secure`. Your settings file will have an encrypted value:
83
+
84
+ ```ruby
85
+ # settings.yml
86
+
87
+ smtp_username: 'my_username'
88
+ _secure_smtp_password: JL5hAVux4tERpv49QPWxy9H0VC2Rnk7V8/e8+1XOwPcXcoH/a7Lh253UY/v9m8nI/Onb+ZG9nZ082J4M/BmLa+f7jwMEwufIqbUhUah9eKIW8xcxlppBYpl7JVGf2HJF5TfCN44gMQNgGNzboCQXKqRyeGFm4u772Sg9V2gEx/q7qJ6F4jg7v/cltCFLmJfXA2SHA5Dai4p9L4IvMVVJGm34k5j7KOegNqpVWs2RY99cagjPuzc9VM2XSUsXgqcUJdmH8YtPW8Kqkyg0oYlRh6VQWABlWXwTZz74QjTTjqtqfoELIoFTMBDh+cCvuUTAE5m06LhlqauVrB4UnBsd5g==
89
+ ```
90
+
91
+ which you still access the same way because Chamber handles the decryption for
92
+ you:
93
+
94
+ ```ruby
95
+ Chamber.env.smtp_password
96
+ # => 'my_password'
97
+ ```
98
+
99
+ Full Reference
100
+ --------------------------------------------------------------------------------
18
101
 
19
- You can view our Basic Usage Guide [here][basic-usage]. Otherwise, for the full
102
+ There's so much to Chamber, we couldn't put it all in the README. For the full
20
103
  Chamber guide, visit the [wiki][wiki].
21
104
 
22
- ## Credits
105
+ Credits
106
+ --------------------------------------------------------------------------------
23
107
 
24
108
  Chamber was written by [Jeff Felchner][jeff-profile] and
25
109
  [Mark McEahern][mark-profile]
@@ -30,27 +114,18 @@ Chamber is maintained and funded by [The Kompanee, Ltd.][kompanee-site]
30
114
 
31
115
  The names and logos for The Kompanee are trademarks of The Kompanee, Ltd.
32
116
 
33
- ## License
117
+ License
118
+ --------------------------------------------------------------------------------
34
119
 
35
- Chamber is Copyright © 2014-2019 Jeff Felchner and Mark McEahern. It is free
120
+ Chamber is Copyright © 2014-2021 Jeff Felchner and Mark McEahern. It is free
36
121
  software, and may be redistributed under the terms specified in the
37
122
  [LICENSE][license] file.
38
123
 
39
- [accessing]: https://github.com/thekompanee/chamber/wiki/Accessing-Settings
40
- [basic-usage]: https://github.com/thekompanee/chamber/wiki/Basic-Usage
41
- [cli]: https://github.com/thekompanee/chamber/wiki/CLI-Overview
42
- [commit-hook]: https://github.com/thekompanee/chamber/wiki/Git-Commit-Hooks
43
- [comparison]: https://github.com/thekompanee/chamber/wiki/Gem-Comparison
44
- [encryption]: https://github.com/thekompanee/chamber/wiki/Encryption-Basics
45
- [env-vars]: https://github.com/thekompanee/chamber/wiki/Environment-Variables
46
- [heroku]: https://github.com/thekompanee/chamber/wiki/Heroku
47
- [inch]: https://inch-ci.org/github/thekompanee/chamber
48
- [jeff-profile]: https://github.com/jfelchner
49
- [kompanee-logo]: https://kompanee-public-assets.s3.amazonaws.com/readmes/kompanee-horizontal-black.png
50
- [kompanee-site]: http://www.thekompanee.com
51
- [license]: https://github.com/thekompanee/chamber/blob/master/LICENSE.txt
52
- [mark-profile]: https://github.com/m5rk
53
- [namespace-keys]: https://github.com/thekompanee/chamber/wiki/Namespaced-Key-Pairs
54
- [plain-ruby]: https://github.com/thekompanee/chamber/wiki/Installation#in-a-ruby-project-or-ruby-gem
55
- [travis]: https://github.com/thekompanee/chamber/wiki/TravisCI
56
- [wiki]: https://github.com/thekompanee/chamber/wiki
124
+ [comparison]: https://github.com/thekompanee/chamber/wiki/Gem-Comparison
125
+ [jeff-profile]: https://github.com/jfelchner
126
+ [kompanee-logo]: https://kompanee-public-assets.s3.amazonaws.com/readmes/kompanee-horizontal-black.png
127
+ [kompanee-site]: http://www.thekompanee.com
128
+ [license]: https://github.com/thekompanee/chamber/blob/master/LICENSE.txt
129
+ [mark-profile]: https://github.com/m5rk
130
+ [wiki]: https://github.com/thekompanee/chamber/wiki
131
+ [installation]: https://github.com/thekompanee/chamber/wiki/Installation
@@ -7,12 +7,8 @@ require 'chamber/rails'
7
7
  module Chamber
8
8
  attr_writer :instance
9
9
 
10
- def load(options = {})
11
- self.instance = Instance.new(options)
12
- end
13
-
14
- def to_s(options = {})
15
- instance.to_s(options)
10
+ def load(**args)
11
+ self.instance = Instance.new(**args)
16
12
  end
17
13
 
18
14
  def env
@@ -20,24 +16,89 @@ module Chamber
20
16
  end
21
17
 
22
18
  def instance
23
- @instance ||= Instance.new({})
19
+ @instance ||= Instance.new
24
20
  end
25
21
 
26
- def method_missing(name, *args)
27
- return instance.public_send(name, *args) if instance.respond_to?(name)
22
+ def [](key)
23
+ instance.[](key)
24
+ end
28
25
 
29
- super
26
+ def dig!(*args)
27
+ instance.dig!(*args)
30
28
  end
31
29
 
32
- def respond_to_missing?(name, include_private = false)
33
- instance.respond_to?(name, include_private)
30
+ def dig(*args)
31
+ instance.dig(*args)
34
32
  end
35
33
 
36
- module_function :load,
37
- :to_s,
34
+ def configuration
35
+ instance.configuration
36
+ end
37
+
38
+ def decrypt(value, **args)
39
+ instance.decrypt(value, **args)
40
+ end
41
+
42
+ def encrypt(value, **args)
43
+ instance.encrypt(value, **args)
44
+ end
45
+
46
+ def files
47
+ instance.files
48
+ end
49
+
50
+ def filenames
51
+ instance.filenames
52
+ end
53
+
54
+ def namespaces
55
+ instance.namespaces
56
+ end
57
+
58
+ def secure
59
+ instance.secure
60
+ end
61
+
62
+ def sign
63
+ instance.sign
64
+ end
65
+
66
+ def verify
67
+ instance.verify
68
+ end
69
+
70
+ def to_environment
71
+ instance.to_environment
72
+ end
73
+
74
+ def to_hash
75
+ instance.to_hash
76
+ end
77
+
78
+ def to_s(**args)
79
+ return '' unless @instance
80
+
81
+ instance.to_s(**args)
82
+ end
83
+
84
+ module_function :[],
85
+ :configuration,
86
+ :decrypt,
87
+ :dig!,
88
+ :dig,
89
+ :encrypt,
38
90
  :env,
91
+ :filenames,
92
+ :files,
39
93
  :instance,
40
94
  :instance=,
41
- :method_missing,
42
- :respond_to_missing?
95
+ :load,
96
+ :namespaces,
97
+ :respond_to_missing?,
98
+ :secure,
99
+ :sign,
100
+ :to_environment,
101
+ :to_hash,
102
+ :to_s,
103
+ :verify
43
104
  end
@@ -17,11 +17,11 @@ class CircleCi
17
17
  :username,
18
18
  :vcs_type
19
19
 
20
- def initialize(options = {})
21
- self.api_token = options.fetch(:api_token)
22
- self.project = options.fetch(:project)
23
- self.username = options.fetch(:username)
24
- self.vcs_type = options.fetch(:vcs_type)
20
+ def initialize(api_token:, project:, username:, vcs_type:)
21
+ self.api_token = api_token
22
+ self.project = project
23
+ self.username = username
24
+ self.vcs_type = vcs_type
25
25
  end
26
26
 
27
27
  def add_environment_variable(name, value)
@@ -39,18 +39,21 @@ class CircleCi
39
39
  response['name']
40
40
  end
41
41
 
42
+ # rubocop:disable Layout/MultilineAssignmentLayout
42
43
  def environment_variables
43
- @environment_variables ||= begin
44
- request = ::Net::HTTP::Get.new(request_uri(resource: 'envvar'))
44
+ @environment_variables ||= \
45
+ begin
46
+ request = ::Net::HTTP::Get.new(request_uri(resource: 'envvar'))
45
47
 
46
- request.basic_auth api_token, ''
47
- request['Content-Type'] = 'application/json'
48
+ request.basic_auth api_token, ''
49
+ request['Content-Type'] = 'application/json'
48
50
 
49
- ::JSON
50
- .parse(response(request).body)
51
- .each_with_object({}) { |e, m| m[e['name']] = e['value'] }
52
- end
51
+ ::JSON
52
+ .parse(response(request).body)
53
+ .each_with_object({}) { |e, m| m[e['name']] = e['value'] }
54
+ end
53
55
  end
56
+ # rubocop:enable Layout/MultilineAssignmentLayout
54
57
 
55
58
  def remove_environment_variable(name)
56
59
  request = ::Net::HTTP::Delete.new(request_uri(resource: "envvar/#{name}"))
@@ -8,38 +8,65 @@ module Chamber
8
8
  module Adapters
9
9
  module Cloud
10
10
  class Heroku
11
- attr_accessor :app
11
+ API_HOST = 'api.heroku.com'
12
+ API_PORT = 443
13
+ API_BASE_URI = ''
12
14
 
13
- def initialize(options = {})
14
- self.app = options.fetch(:app)
15
+ attr_accessor :api_token,
16
+ :app
17
+
18
+ def initialize(api_token:, app:)
19
+ self.api_token = api_token
20
+ self.app = app
15
21
  end
16
22
 
17
- def add_environment_variable(name, value)
18
- value = value.shellescape unless value =~ /\n/
23
+ def add_environment_variable(name, value) # rubocop:disable Metrics/AbcSize
24
+ value = value.gsub(/\n/, '\n') if value
25
+ request = ::Net::HTTP::Patch.new(config_vars_uri)
26
+
27
+ request['Authorization'] = "Bearer #{api_token}"
28
+ request['Accept'] = 'application/vnd.heroku+json; version=3'
29
+ request['Content-Type'] = 'application/json'
30
+ request.body = ::JSON.dump(::Hash[name, value])
19
31
 
20
- response = heroku(%Q{config:set #{name}="#{value}"})
32
+ response = ::JSON.parse(response(request).body)
21
33
 
22
- fail NameError, "The variable name '#{name}' is invalid" if response.match?(/invalid/)
34
+ fail ::NameError, response['message'] if response['message']
23
35
 
24
36
  response
25
37
  end
26
38
 
27
39
  def environment_variables
28
- @environment_variables ||= ::JSON.parse(heroku('config --json'))
40
+ request = ::Net::HTTP::Get.new(config_vars_uri)
41
+
42
+ request['Authorization'] = "Bearer #{api_token}"
43
+ request['Accept'] = 'application/vnd.heroku+json; version=3'
44
+
45
+ response = ::JSON.parse(response(request).body)
46
+
47
+ fail ::NameError, response['message'] if response['message']
48
+
49
+ response
29
50
  end
30
51
 
31
52
  def remove_environment_variable(name)
32
- heroku("config:unset #{name}")
53
+ add_environment_variable(name, nil)
33
54
  end
34
55
 
35
56
  private
36
57
 
37
- def heroku(command)
38
- Bundler.with_clean_env { `heroku #{command}#{app_option} 2>&1` }
58
+ def config_vars_uri
59
+ "#{API_BASE_URI}/apps/#{app}/config-vars"
60
+ end
61
+
62
+ def response(request)
63
+ connection.request(request)
39
64
  end
40
65
 
41
- def app_option
42
- app ? " --app='#{app}'" : ''
66
+ def connection
67
+ @connection ||= ::Net::HTTP.new(API_HOST, API_PORT).tap do |conn|
68
+ conn.use_ssl = true
69
+ end
43
70
  end
44
71
  end
45
72
  end
@@ -5,11 +5,13 @@ require 'chamber/commands/cloud/clear'
5
5
  require 'chamber/commands/cloud/push'
6
6
  require 'chamber/commands/cloud/pull'
7
7
  require 'chamber/commands/cloud/compare'
8
+ require 'chamber/refinements/hash'
8
9
 
9
10
  module Chamber
10
11
  module Binary
11
- class CircleCi < Thor
12
- include Thor::Actions
12
+ class CircleCi < ::Thor
13
+ include ::Thor::Actions
14
+ using ::Chamber::Refinements::Hash
13
15
 
14
16
  class_option :api_token,
15
17
  type: :string,
@@ -36,8 +38,9 @@ class CircleCi < Thor
36
38
  desc: 'The type of VCS your project is using.',
37
39
  enum: %w{github bitbucket}
38
40
 
39
- desc 'clear', 'Removes all CircleCi environment variables which match settings that ' \
40
- 'Chamber knows about'
41
+ desc 'clear',
42
+ 'Removes all CircleCi environment variables which match settings that Chamber ' \
43
+ 'knows about'
41
44
 
42
45
  method_option :dry_run,
43
46
  type: :boolean,
@@ -46,11 +49,14 @@ class CircleCi < Thor
46
49
  'would change if cleared'
47
50
 
48
51
  def clear
49
- Commands::Cloud::Clear.call(options.merge(shell: self, adapter: 'circle_ci'))
52
+ Commands::Cloud::Clear.call(**options
53
+ .deep_transform_keys(&:to_sym)
54
+ .merge(shell: self, adapter: 'circle_ci'))
50
55
  end
51
56
 
52
- desc 'push', 'Sends settings to CircleCi so that they may be used in the application ' \
53
- 'once it is deployed'
57
+ desc 'push',
58
+ 'Sends settings to CircleCi so that they may be used in the application ' \
59
+ 'once it is deployed'
54
60
 
55
61
  method_option :dry_run,
56
62
  type: :boolean,
@@ -75,11 +81,14 @@ class CircleCi < Thor
75
81
  'will be pushed'
76
82
 
77
83
  def push
78
- Commands::Cloud::Push.call(options.merge(shell: self, adapter: 'circle_ci'))
84
+ Commands::Cloud::Push.call(**options
85
+ .deep_transform_keys(&:to_sym)
86
+ .merge(shell: self, adapter: 'circle_ci'))
79
87
  end
80
88
 
81
- desc 'pull', 'Retrieves the environment variables for the application and stores ' \
82
- 'them in a temporary file'
89
+ desc 'pull',
90
+ 'Retrieves the environment variables for the application and stores them in a ' \
91
+ 'temporary file'
83
92
 
84
93
  method_option :into,
85
94
  type: :string,
@@ -87,11 +96,14 @@ class CircleCi < Thor
87
96
  'stored. This file WILL BE OVERRIDDEN.'
88
97
 
89
98
  def pull
90
- Commands::Cloud::Pull.call(options.merge(shell: self, adapter: 'circle_ci'))
99
+ Commands::Cloud::Pull.call(**options
100
+ .deep_transform_keys(&:to_sym)
101
+ .merge(shell: self, adapter: 'circle_ci'))
91
102
  end
92
103
 
93
- desc 'compare', 'Displays the difference between what is currently stored in the ' \
94
- 'CircleCi application\'s config and what Chamber knows about locally'
104
+ desc 'compare',
105
+ 'Displays the difference between what is currently stored in the ' \
106
+ 'CircleCi application\'s config and what Chamber knows about locally'
95
107
 
96
108
  method_option :only_sensitive,
97
109
  type: :boolean,
@@ -102,7 +114,9 @@ class CircleCi < Thor
102
114
  'which are marked as "_secure"'
103
115
 
104
116
  def compare
105
- Commands::Cloud::Compare.call(options.merge(shell: self, adapter: 'circle_ci'))
117
+ Commands::Cloud::Compare.call(**options
118
+ .deep_transform_keys(&:to_sym)
119
+ .merge(shell: self, adapter: 'circle_ci'))
106
120
  end
107
121
  end
108
122
  end