MrMurano 1.11.1 → 1.11.2
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.
- checksums.yaml +4 -4
- data/.travis.yml +12 -0
- data/README.markdown +1 -1
- data/Rakefile +3 -0
- data/TODO.taskpaper +9 -2
- data/bin/mr +8 -1
- data/lib/MrMurano/Account.rb +6 -6
- data/lib/MrMurano/Config.rb +2 -0
- data/lib/MrMurano/Product-Resources.rb +2 -0
- data/lib/MrMurano/Solution-Endpoint.rb +1 -1
- data/lib/MrMurano/SyncUpDown.rb +3 -0
- data/lib/MrMurano/commands/config.rb +2 -5
- data/lib/MrMurano/commands/init.rb +6 -0
- data/lib/MrMurano/commands/tsdb.rb +20 -0
- data/lib/MrMurano/verbosing.rb +5 -0
- data/lib/MrMurano/version.rb +1 -1
- data/spec/Account_spec.rb +7 -7
- data/spec/ProductResources_spec.rb +2 -2
- data/spec/cmd_init_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7952441f550b0a314943de0c8bf2ced3e496b406
|
4
|
+
data.tar.gz: 1e10b41f47a6fbb668bd75c78593094f44835923
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9271fcc60621b98bdf94bf59392c473a952323eaf8d370d43542e5a88a6c91cc48d07e706a741c659c97f09c5d2bf509925ed158bf860f071189dac8fdc88a31
|
7
|
+
data.tar.gz: 98b2e10a2144ad74e0a6c55f2d7d05d773c2a31037a3ae11fc44a5f7c19c1e3362ac2ef3b28cfa98c590414fb7d0b358f4886c275dba1d411fb5e239a22cf08f
|
data/.travis.yml
CHANGED
@@ -3,3 +3,15 @@ rvm:
|
|
3
3
|
- 2.0
|
4
4
|
- 2.2
|
5
5
|
|
6
|
+
before_deploy: "rake build"
|
7
|
+
deploy:
|
8
|
+
provider: releases
|
9
|
+
api_key:
|
10
|
+
secure: oB28IBHoSQVgP0PtP1uc+cRMBNhqHCCfCCV+sLNspjCGJeIjhZ4lmLcMYSy8l0+TBWxmXl6VIQd6GbyEezbB5daA4+pxY/An0OpM649t29+QuMCK8iXrD8/HXfaUzY2CP5RP47GoC/5xyCwqv3EEUjFPEGhUb5hYc74kfe3nwBmhKliHFQpZvuDE0EHWTgcEOep+kf7O+3cVf7vJVddz+Vj05t1s6VCwhBQsbUvOV4/Jv7nhHa7q0UGoY9M7sTNpwgawFeMwqvtXxl8sVbiHPLm+u6vikSbVnSdyi7wlVAoe+DSkzmnVHYzMd/t1Io7kEiLEAyDyrlJPJYS+XTMqxQ/KUDJNhf/N2IJMW2vPA+6TjpxCqcdY4QwkLNb7JfFWgQb9X4UksAEQU24W6110+zPUGmbg37eM80OrsadTWy65IQbLJ0sFFhm8vu/e2i/3LadYscw6A0Tyc1JXgGfGKd0nqyAyKGLcSBw1+dwwzkyKNHWFAaLy5hAEKv2qZdVNrTtcLhJtuxv8VUuevd3gfT6FLOIN/XAyg71mSvC2BA12vzM6KkTPNIaSmUITDgEplT5cs5h8PZ4eRghpmnT2EA3k0O3p14Ng3eeACMImJYQRKWmU/yVWVo69VVH0GRfm5SWb6xlDLFXt/Mii1MPx9ruhC232wdRACoep18w1qUY=
|
11
|
+
file: "pkg/MrMurano-*.gem"
|
12
|
+
skip_cleanup: true
|
13
|
+
on:
|
14
|
+
repo: tadpol/MrMurano
|
15
|
+
tags: true
|
16
|
+
rvm: 2.2
|
17
|
+
|
data/README.markdown
CHANGED
@@ -29,7 +29,7 @@ Then deploy with `mr syncup`
|
|
29
29
|
There are a few steps and pieces to getting a solution with a product up and
|
30
30
|
running in Murano. Here is the list.
|
31
31
|
|
32
|
-
- Pick a
|
32
|
+
- Pick a business: `mr account --business`
|
33
33
|
- Set it: `mr config business.id ZZZZZZZZZ`
|
34
34
|
- Create a product: `mr product create myawesomeproduct`
|
35
35
|
- Save the result: `mr config product.id YYYYYYYYY`
|
data/Rakefile
CHANGED
data/TODO.taskpaper
CHANGED
@@ -28,7 +28,7 @@ Endpoints:
|
|
28
28
|
- Add directory support like in modules @done(2016-07-26)
|
29
29
|
|
30
30
|
Files:
|
31
|
-
- Add ignore patterns to config
|
31
|
+
- Add ignore patterns to config @done(2016-12-20)
|
32
32
|
- Switch to mime-types v3 @pri(low)
|
33
33
|
- Figure out how to make the hexed-sha checksum faster. @done(2016-09-23)
|
34
34
|
- Fix upload. @done(2016-08-01)
|
@@ -65,7 +65,7 @@ Product:
|
|
65
65
|
- Need to add way to set the product ID on a device eventhandler. @done(2016-08-01)
|
66
66
|
|
67
67
|
Service Device:
|
68
|
-
- When listing and
|
68
|
+
- When listing and business.id is missing, gracefully fall back to --idonly @done(2016-09-12)
|
69
69
|
|
70
70
|
Config:
|
71
71
|
- Add config tool.default_sync to set which things sync{up,down} by default
|
@@ -73,6 +73,13 @@ Config:
|
|
73
73
|
- Store passwords in system Keychain on system that have a Keychain.
|
74
74
|
mac OS does, various Linux desktops have a couple differnet ones. Not sure about
|
75
75
|
Windows.
|
76
|
+
MacOS: https://github.com/xli/mac-keychain
|
77
|
+
Windows8+: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465069.aspx
|
78
|
+
Linux: https://en.wikipedia.org/wiki/GNOME_Keyring
|
79
|
+
https://en.wikipedia.org/wiki/KWallet
|
80
|
+
|
81
|
+
Plus things like 1Password, LastPass, KeePass, and others.
|
82
|
+
|
76
83
|
- Add ENV['MR_CONFIGFILE'] path to file to load like --configfile @done(2016-09-22)
|
77
84
|
- Maybe add dotenv support. @done(2016-09-22)
|
78
85
|
- Think about adding dev,staging,prod system; how would that work? @done(2016-09-16)
|
data/bin/mr
CHANGED
@@ -31,8 +31,15 @@ global_option('-C', '--configfile FILE', %{Load additional configuration file})
|
|
31
31
|
}
|
32
32
|
global_option('-c', '--config KEY=VALUE', %{Set a single config key}) {|param|
|
33
33
|
key, value = param.split('=', 2)
|
34
|
+
# a=b :> ["a","b"]
|
35
|
+
# a= :> ["a",""]
|
36
|
+
# a :> ["a"]
|
34
37
|
raise "Bad config '#{param}'" if key.nil?
|
35
|
-
|
38
|
+
if value.nil? then
|
39
|
+
$cfg[key] = 'true'
|
40
|
+
else
|
41
|
+
$cfg[key] = value
|
42
|
+
end
|
36
43
|
}
|
37
44
|
|
38
45
|
default_command :help
|
data/lib/MrMurano/Account.rb
CHANGED
@@ -119,35 +119,35 @@ module MrMurano
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def products
|
122
|
-
raise "Missing
|
122
|
+
raise "Missing Business ID" if $cfg['business.id'].nil?
|
123
123
|
get('business/' + $cfg['business.id'] + '/product/')
|
124
124
|
end
|
125
125
|
|
126
126
|
## Create a new product in the current business
|
127
127
|
def new_product(name, type='onepModel')
|
128
|
-
raise "Missing
|
128
|
+
raise "Missing Business ID" if $cfg['business.id'].nil?
|
129
129
|
post('business/' + $cfg['business.id'] + '/product/', {:label=>name, :type=>type})
|
130
130
|
end
|
131
131
|
|
132
132
|
def delete_product(modelId)
|
133
|
-
raise "Missing
|
133
|
+
raise "Missing Business ID" if $cfg['business.id'].nil?
|
134
134
|
delete('business/' + $cfg['business.id'] + '/product/' + modelId)
|
135
135
|
end
|
136
136
|
|
137
137
|
def solutions
|
138
|
-
raise "Missing
|
138
|
+
raise "Missing Business ID" if $cfg['business.id'].nil?
|
139
139
|
get('business/' + $cfg['business.id'] + '/solution/')
|
140
140
|
end
|
141
141
|
|
142
142
|
## Create a new solution
|
143
143
|
def new_solution(name, type='dataApi')
|
144
|
-
raise "Missing
|
144
|
+
raise "Missing Business ID" if $cfg['business.id'].nil?
|
145
145
|
raise "Solution name must be lowercase" if name.match(/[A-Z]/)
|
146
146
|
post('business/' + $cfg['business.id'] + '/solution/', {:label=>name, :type=>type})
|
147
147
|
end
|
148
148
|
|
149
149
|
def delete_solution(apiId)
|
150
|
-
raise "Missing
|
150
|
+
raise "Missing Business ID" if $cfg['business.id'].nil?
|
151
151
|
delete('business/' + $cfg['business.id'] + '/solution/' + apiId)
|
152
152
|
end
|
153
153
|
|
data/lib/MrMurano/Config.rb
CHANGED
@@ -103,6 +103,8 @@ module MrMurano
|
|
103
103
|
set('modules.searchFor', '*.lua */*.lua', :defaults)
|
104
104
|
set('modules.ignoring', '*_test.lua *_spec.lua .*', :defaults)
|
105
105
|
|
106
|
+
set('product.spec', 'resources.yaml', :defaults)
|
107
|
+
|
106
108
|
set('diff.cmd', 'diff -u', :defaults)
|
107
109
|
end
|
108
110
|
|
@@ -132,6 +132,7 @@ module MrMurano
|
|
132
132
|
## Get a local list of items from the single file
|
133
133
|
def localitems(from)
|
134
134
|
from = Pathname.new(from) unless from.kind_of? Pathname
|
135
|
+
debug "#{self.class.to_s}: Getting local items from: #{from}"
|
135
136
|
if not from.exist? then
|
136
137
|
say_warning "Skipping missing #{from.to_s}"
|
137
138
|
return []
|
@@ -173,6 +174,7 @@ module MrMurano
|
|
173
174
|
end
|
174
175
|
here << item.reject{|k,v| k==:synckey or k==:rid}
|
175
176
|
here.map!{|i| Hash.transform_keys_to_strings(i)}
|
177
|
+
local.dirname.mkpath
|
176
178
|
local.open('wb') do |io|
|
177
179
|
io << {'resources'=>here}.to_yaml
|
178
180
|
end
|
data/lib/MrMurano/SyncUpDown.rb
CHANGED
@@ -240,6 +240,8 @@ module MrMurano
|
|
240
240
|
bitems = localitems(@locationbase + @location)
|
241
241
|
# use synckey for quicker merging.
|
242
242
|
bitems.each { |b| items[synckey(b)] = b }
|
243
|
+
else
|
244
|
+
warning "Skipping missing location #{@locationbase + @location}"
|
243
245
|
end
|
244
246
|
|
245
247
|
items.values
|
@@ -265,6 +267,7 @@ module MrMurano
|
|
265
267
|
# @param from Pathname: Directory of items to scan
|
266
268
|
# @return Array: of Hashes of item details
|
267
269
|
def localitems(from)
|
270
|
+
debug "#{self.class.to_s}: Getting local items from: #{from}"
|
268
271
|
searchIn = from.to_s
|
269
272
|
sf = searchFor.map{|i| ::File.join(searchIn, i)}
|
270
273
|
Dir[*sf].flatten.compact.reject do |p|
|
@@ -16,7 +16,6 @@ command :config do |c|
|
|
16
16
|
'mr config diff.cmd --unset'
|
17
17
|
|
18
18
|
|
19
|
-
c.option '--system', 'Use only the system config file. (/etc/mrmuranorc)'
|
20
19
|
c.option '--user', 'Use only the config file in $HOME (.mrmuranorc)'
|
21
20
|
c.option '--project', 'Use only the config file in the project (.mrmuranorc)'
|
22
21
|
c.option '--env', 'Use only the config file from $MR_CONFIGFILE'
|
@@ -32,12 +31,11 @@ command :config do |c|
|
|
32
31
|
elsif args.count == 0 then
|
33
32
|
say_error "Need a config key"
|
34
33
|
elsif args.count == 1 and not options.unset then
|
35
|
-
options.default :
|
34
|
+
options.default :user=>false, :project=>false,
|
36
35
|
:specified=>false, :env=>false
|
37
36
|
|
38
37
|
# For read, if no scopes, than all. Otherwise just those specified
|
39
38
|
scopes = []
|
40
|
-
scopes << :system if options.system
|
41
39
|
scopes << :user if options.user
|
42
40
|
scopes << :project if options.project
|
43
41
|
scopes << :env if options.env
|
@@ -47,11 +45,10 @@ command :config do |c|
|
|
47
45
|
say $cfg.get(args[0], scopes)
|
48
46
|
else
|
49
47
|
|
50
|
-
options.default :
|
48
|
+
options.default :user=>false, :project=>false,
|
51
49
|
:specified=>false, :env=>false
|
52
50
|
# For write, if scope is specified, only write to that scope.
|
53
51
|
scope = :project
|
54
|
-
scope = :system if options.system
|
55
52
|
scope = :user if options.user
|
56
53
|
scope = :project if options.project
|
57
54
|
scope = :env if options.env
|
@@ -12,6 +12,7 @@ command :init do |c|
|
|
12
12
|
c.action do |args, options|
|
13
13
|
options.default :force=>false, :mkdirs=>true
|
14
14
|
acc = MrMurano::Account.new
|
15
|
+
puts ''
|
15
16
|
|
16
17
|
if Pathname.new(Dir.pwd).realpath == Pathname.new(Dir.home).realpath then
|
17
18
|
acc.error "Cannot init a project in your HOME directory."
|
@@ -23,6 +24,8 @@ command :init do |c|
|
|
23
24
|
exit 0 unless y =~ /^n/i
|
24
25
|
end
|
25
26
|
|
27
|
+
say "Found project base directory at #{$cfg['location.base'].to_s}"
|
28
|
+
puts ''
|
26
29
|
|
27
30
|
# If they have never logged in, then asking for the business.id will also ask
|
28
31
|
# for their username and password.
|
@@ -101,6 +104,8 @@ command :init do |c|
|
|
101
104
|
say "Ok, In business ID: #{$cfg['business.id']} using Solution ID: #{$cfg['solution.id']} with Product ID: #{$cfg['product.id']}"
|
102
105
|
|
103
106
|
if options.mkdirs then
|
107
|
+
base = $cfg['location.base']
|
108
|
+
base = Pathname.new(base) unless base.kind_of? Pathname
|
104
109
|
%w{
|
105
110
|
location.files
|
106
111
|
location.endpoints
|
@@ -110,6 +115,7 @@ command :init do |c|
|
|
110
115
|
}.each do |cfgi|
|
111
116
|
path = $cfg[cfgi]
|
112
117
|
path = Pathname.new(path) unless path.kind_of? Pathname
|
118
|
+
path = base + path
|
113
119
|
path.mkpath unless path.exist?
|
114
120
|
end
|
115
121
|
say "Default directories created"
|
@@ -184,6 +184,26 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
184
184
|
io = File.open(options.output, 'w')
|
185
185
|
end
|
186
186
|
sol.outf sol.query(query) do |dd, ios|
|
187
|
+
# If aggregated, then we need to break up the columns. since each is now a
|
188
|
+
# hash of the aggregated functions
|
189
|
+
unless options.aggregate.nil? then
|
190
|
+
dd[:values].map! do |row|
|
191
|
+
row.map do |value|
|
192
|
+
if value.kind_of? Hash then
|
193
|
+
query[:aggregate].map{|qa| value[qa.to_sym]}
|
194
|
+
else
|
195
|
+
value
|
196
|
+
end
|
197
|
+
end.flatten
|
198
|
+
end
|
199
|
+
dd[:columns].map! do |col|
|
200
|
+
if col == 'time' then
|
201
|
+
col
|
202
|
+
else
|
203
|
+
query[:aggregate].map{|qa| "#{col}.#{qa.to_s}"}
|
204
|
+
end
|
205
|
+
end.flatten!
|
206
|
+
end
|
187
207
|
sol.tabularize({
|
188
208
|
:headers=>dd[:columns],
|
189
209
|
:rows=>dd[:values]
|
data/lib/MrMurano/verbosing.rb
CHANGED
@@ -27,6 +27,10 @@ module MrMurano
|
|
27
27
|
$stderr.puts HighLine.color(msg, :red)
|
28
28
|
end
|
29
29
|
|
30
|
+
## Output tabular data
|
31
|
+
# +data+:: Data to write. Preferably a Hash with :headers and :rows
|
32
|
+
# +ios+:: Output stream to write to, if nil, then use $stdout
|
33
|
+
# Output is either a nice visual table or CSV.
|
30
34
|
def tabularize(data, ios=nil)
|
31
35
|
fmt = $cfg['tool.outformat']
|
32
36
|
ios = $stdout if ios.nil?
|
@@ -59,6 +63,7 @@ module MrMurano
|
|
59
63
|
end
|
60
64
|
|
61
65
|
## Format and print the object
|
66
|
+
# Handles many of the raw 'unpolished' formats.
|
62
67
|
def outf(obj, ios=nil, &block)
|
63
68
|
fmt = $cfg['tool.outformat']
|
64
69
|
ios = $stdout if ios.nil?
|
data/lib/MrMurano/version.rb
CHANGED
data/spec/Account_spec.rb
CHANGED
@@ -19,7 +19,7 @@ RSpec.describe MrMurano::Account do
|
|
19
19
|
expect(uri.to_s).to eq("https://bizapi.hosted.exosite.io/api:1/")
|
20
20
|
end
|
21
21
|
|
22
|
-
it "lists
|
22
|
+
it "lists business" do
|
23
23
|
bizlist = [{"bizid"=>"XXX","role"=>"admin","name"=>"MPS"},
|
24
24
|
{"bizid"=>"YYY","role"=>"admin","name"=>"MAE"}]
|
25
25
|
stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/user/BoB@place.net/membership/").
|
@@ -42,7 +42,7 @@ RSpec.describe MrMurano::Account do
|
|
42
42
|
|
43
43
|
it "lists products; without biz.id" do
|
44
44
|
allow($cfg).to receive(:get).with('business.id').and_return(nil)
|
45
|
-
expect { @acc.products }.to raise_error("Missing
|
45
|
+
expect { @acc.products }.to raise_error("Missing Business ID")
|
46
46
|
end
|
47
47
|
|
48
48
|
it "creates product" do
|
@@ -56,7 +56,7 @@ RSpec.describe MrMurano::Account do
|
|
56
56
|
|
57
57
|
it "creates product; without biz.id" do
|
58
58
|
allow($cfg).to receive(:get).with('business.id').and_return(nil)
|
59
|
-
expect { @acc.new_product("ONe") }.to raise_error("Missing
|
59
|
+
expect { @acc.new_product("ONe") }.to raise_error("Missing Business ID")
|
60
60
|
end
|
61
61
|
|
62
62
|
it "deletes product" do
|
@@ -69,7 +69,7 @@ RSpec.describe MrMurano::Account do
|
|
69
69
|
|
70
70
|
it "deletes product; without biz.id" do
|
71
71
|
allow($cfg).to receive(:get).with('business.id').and_return(nil)
|
72
|
-
expect { @acc.delete_product("ONe") }.to raise_error("Missing
|
72
|
+
expect { @acc.delete_product("ONe") }.to raise_error("Missing Business ID")
|
73
73
|
end
|
74
74
|
|
75
75
|
|
@@ -93,7 +93,7 @@ RSpec.describe MrMurano::Account do
|
|
93
93
|
|
94
94
|
it "lists solutions; without biz.id" do
|
95
95
|
allow($cfg).to receive(:get).with('business.id').and_return(nil)
|
96
|
-
expect { @acc.solutions }.to raise_error("Missing
|
96
|
+
expect { @acc.solutions }.to raise_error("Missing Business ID")
|
97
97
|
end
|
98
98
|
|
99
99
|
it "creates solution" do
|
@@ -111,7 +111,7 @@ RSpec.describe MrMurano::Account do
|
|
111
111
|
|
112
112
|
it "creates solution; without biz.id" do
|
113
113
|
allow($cfg).to receive(:get).with('business.id').and_return(nil)
|
114
|
-
expect { @acc.new_solution("one") }.to raise_error("Missing
|
114
|
+
expect { @acc.new_solution("one") }.to raise_error("Missing Business ID")
|
115
115
|
end
|
116
116
|
|
117
117
|
it "deletes solution" do
|
@@ -124,7 +124,7 @@ RSpec.describe MrMurano::Account do
|
|
124
124
|
|
125
125
|
it "deletes solution; without biz.id" do
|
126
126
|
allow($cfg).to receive(:get).with('business.id').and_return(nil)
|
127
|
-
expect { @acc.delete_solution("one") }.to raise_error("Missing
|
127
|
+
expect { @acc.delete_solution("one") }.to raise_error("Missing Business ID")
|
128
128
|
end
|
129
129
|
|
130
130
|
end
|
@@ -44,10 +44,10 @@ RSpec.describe MrMurano::ProductResources do
|
|
44
44
|
expect(loc).to eq("magical.file")
|
45
45
|
end
|
46
46
|
|
47
|
-
it "
|
47
|
+
it "Uses default spec file name" do
|
48
48
|
$cfg['product.spec'] = nil
|
49
49
|
$cfg['product.id'] = nil
|
50
|
-
expect
|
50
|
+
expect(@prd.location).to eq('specs/resources.yaml')
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
data/spec/cmd_init_spec.rb
CHANGED
@@ -10,7 +10,7 @@ RSpec.describe 'mr init' do
|
|
10
10
|
# this is in the project dir. Want to be in HOME
|
11
11
|
Dir.chdir(ENV['HOME']) do
|
12
12
|
out, err, status = Open3.capture3(capcmd('mr', 'init', '--trace'))
|
13
|
-
expect(out).to eq("")
|
13
|
+
expect(out).to eq("\n")
|
14
14
|
expect(err).to eq("\e[31mCannot init a project in your HOME directory.\e[0m\n")
|
15
15
|
expect(status.exitstatus).to eq(2)
|
16
16
|
end
|
@@ -19,7 +19,7 @@ RSpec.describe 'mr init' do
|
|
19
19
|
it "Asks to import if Solutionfile exists" do
|
20
20
|
FileUtils.touch('Solutionfile.json')
|
21
21
|
out, err, status = Open3.capture3(capcmd('mr', 'init', '--trace'), :stdin_data=>'y')
|
22
|
-
expect(out).to eq("
|
22
|
+
expect(out).to eq("\nA Solutionfile.json exists, Do you want exit and run `mr config import` instead? [yN]\n")
|
23
23
|
expect(err).to eq("")
|
24
24
|
expect(status.exitstatus).to eq(0)
|
25
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: MrMurano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.11.
|
4
|
+
version: 1.11.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Conrad Tadpol Tilstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|