MuranoCLI 3.0.4 → 3.0.5
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/{.agignore → .ignore} +2 -0
- data/.trustme.sh +14 -1
- data/.trustme.vim +2 -0
- data/README.markdown +0 -5
- data/lib/MrMurano/Account.rb +157 -27
- data/lib/MrMurano/Business.rb +2 -7
- data/lib/MrMurano/Config.rb +2 -2
- data/lib/MrMurano/Exchange-Element.rb +88 -24
- data/lib/MrMurano/Exchange.rb +35 -6
- data/lib/MrMurano/Passwords.rb +5 -1
- data/lib/MrMurano/SyncUpDown.rb +5 -1
- data/lib/MrMurano/commands/business.rb +11 -1
- data/lib/MrMurano/commands/cors.rb +29 -2
- data/lib/MrMurano/commands/exchange.rb +4 -2
- data/lib/MrMurano/commands/login.rb +6 -33
- data/lib/MrMurano/commands/usage.rb +5 -4
- data/lib/MrMurano/hash.rb +2 -2
- data/lib/MrMurano/http.rb +2 -2
- data/lib/MrMurano/version.rb +2 -2
- data/spec/Account_spec.rb +4 -1
- data/spec/Content_spec.rb +9 -1
- data/spec/cmd_syncdown_application_spec.rb +124 -0
- data/spec/{cmd_syncdown_spec.rb → cmd_syncdown_both_spec.rb} +22 -9
- data/spec/cmd_syncup_spec.rb +2 -2
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73e2f9256da32058214bb3f721407d9fd480b951
|
4
|
+
data.tar.gz: 947a9c30a1632fae14e8c5e1560a52050bc0748b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 770f834abc53c64993f18fff880379b6ebb2ed24905fb662a856e66b103ac8d36cca955fa893fd9cca8a355cbbe39f08c38a71153450680fa1e8e8c5b493935f
|
7
|
+
data.tar.gz: 5f6ccacfaa8a60c09c8e551bbb17844266e5ddb7156f52b701b470c07faaff24fe5203c81b790580f8c3876f110667e4cef2530b815996a0ebda5027838ae247
|
data/{.agignore → .ignore}
RENAMED
data/.trustme.sh
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/bin/bash
|
2
|
-
# Last Modified: 2017.
|
2
|
+
# Last Modified: 2017.09.20
|
3
3
|
# vim:tw=0:ts=2:sw=2:et:norl:spell
|
4
4
|
|
5
5
|
# WHAT: A Continuous Integration (CI) script for kicking the build
|
@@ -171,6 +171,19 @@ function rspec_it() {
|
|
171
171
|
# business as you do when developing.
|
172
172
|
#rspec_it
|
173
173
|
|
174
|
+
function ctags_it() {
|
175
|
+
annoucement "CTAGS IT"
|
176
|
+
ctags -R \
|
177
|
+
--exclude=coverage \
|
178
|
+
--exclude=docs \
|
179
|
+
--exclude=pkg \
|
180
|
+
--exclude=report \
|
181
|
+
--exclude=spec \
|
182
|
+
--verbose=yes
|
183
|
+
/bin/ls -la tags >> ${OUT_FILE}
|
184
|
+
}
|
185
|
+
ctags_it
|
186
|
+
|
174
187
|
time_n=$(date +%s.%N)
|
175
188
|
time_elapsed=$(echo "$time_n - $time_0" | bc -l)
|
176
189
|
annoucement "DONE!"
|
data/.trustme.vim
CHANGED
data/README.markdown
CHANGED
@@ -1,10 +1,5 @@
|
|
1
1
|
# Murano Command Line Interface (CLI)
|
2
2
|
|
3
|
-
[](https://badge.fury.io/rb/MuranoCLI)
|
5
|
-
[](https://travis-ci.org/exosite/MuranoCLI)
|
6
|
-
[](http://inch-ci.org/github/exosite/MuranoCLI)
|
7
|
-
|
8
3
|
Do more from the command line with [Murano](https://exosite.com/platform/).
|
9
4
|
|
10
5
|
MuranoCLI interacts with Murano and makes different tasks easier.
|
data/lib/MrMurano/Account.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.21 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -55,6 +55,7 @@ Or set your password with `murano password set <username>`.
|
|
55
55
|
|
56
56
|
def login_info
|
57
57
|
warned_once = false
|
58
|
+
|
58
59
|
if user.empty?
|
59
60
|
prologue = 'No Murano user account found.'
|
60
61
|
unless $cfg.prompt_if_logged_off
|
@@ -70,9 +71,8 @@ Or set your password with `murano password set <username>`.
|
|
70
71
|
$project.refresh_user_name
|
71
72
|
MrMurano::Verbose.whirly_unpause
|
72
73
|
end
|
73
|
-
|
74
|
-
pwd_file =
|
75
|
-
pwd_file.load
|
74
|
+
|
75
|
+
pwd_file = pwd_file_load
|
76
76
|
user_pass = pwd_file.get(host, user)
|
77
77
|
if user_pass.nil?
|
78
78
|
prologue = "No Murano password found for #{user}."
|
@@ -85,19 +85,42 @@ Or set your password with `murano password set <username>`.
|
|
85
85
|
error(%(#{prologue} #{LOGIN_NOTICE}).strip) unless warned_once
|
86
86
|
user_pass = ask('Password: ') { |q| q.echo = '*' }
|
87
87
|
pwd_file.set(host, user, user_pass)
|
88
|
+
pwd_file.set(host, user + '/twofactor', nil)
|
88
89
|
pwd_file.save
|
89
90
|
MrMurano::Verbose.whirly_unpause
|
91
|
+
else
|
92
|
+
@twofactor_token = token_twofactor_lookup(pwd_file)
|
90
93
|
end
|
91
|
-
|
94
|
+
|
95
|
+
{
|
92
96
|
email: user,
|
93
97
|
password: user_pass,
|
94
98
|
}
|
95
|
-
|
99
|
+
end
|
100
|
+
|
101
|
+
def pwd_file_load
|
102
|
+
pwd_path = $cfg.file_at('passwords', :user)
|
103
|
+
pwd_file = MrMurano::Passwords.new(pwd_path)
|
104
|
+
pwd_file.load
|
105
|
+
pwd_file
|
106
|
+
end
|
107
|
+
|
108
|
+
def token_twofactor_lookup(pwd_file)
|
109
|
+
twoftoken = pwd_file.lookup(host, user + '/twofactor')
|
110
|
+
if twoftoken.to_s.empty?
|
111
|
+
nil
|
112
|
+
elsif twoftoken !~ /^[a-fA-F0-9]+$/
|
113
|
+
warning "Malformed twofactor token: #{twoftoken}"
|
114
|
+
nil
|
115
|
+
else
|
116
|
+
twoftoken
|
117
|
+
end
|
96
118
|
end
|
97
119
|
|
98
120
|
# ---------------------------------------------------------------------
|
99
121
|
|
100
122
|
def token
|
123
|
+
return '' if defined?(@logging_on) && @logging_on
|
101
124
|
token_fetch if @token.to_s.empty?
|
102
125
|
@token
|
103
126
|
end
|
@@ -107,32 +130,139 @@ Or set your password with `murano password set <username>`.
|
|
107
130
|
end
|
108
131
|
|
109
132
|
def token_fetch
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
133
|
+
@logging_on = true
|
134
|
+
creds = login_info
|
135
|
+
@token = nil
|
136
|
+
|
137
|
+
# If 2fa token found, verify it works.
|
138
|
+
unless @twofactor_token.nil?
|
139
|
+
get('token/' + @twofactor_token) do |request, http|
|
140
|
+
http.request(request) do |response|
|
141
|
+
if response.is_a?(Net::HTTPSuccess)
|
142
|
+
# response.body is, e.g., "{\"email\":\"xxx@yyy.zzz\",\"ttl\":172800}"
|
143
|
+
@token = @twofactor_token
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
unless @token.nil?
|
148
|
+
@logging_on = false
|
149
|
+
return
|
150
|
+
end
|
151
|
+
@twofactor_token = nil
|
152
|
+
end
|
118
153
|
|
119
154
|
MrMurano::Verbose.whirly_start('Logging in...')
|
120
|
-
|
155
|
+
post('token/', creds) do |request, http|
|
156
|
+
http.request(request) do |response|
|
157
|
+
reply = JSON.parse(response.body, json_opts)
|
158
|
+
if response.is_a?(Net::HTTPSuccess)
|
159
|
+
@token = reply[:token]
|
160
|
+
elsif response.is_a?(Net::HTTPConflict) && reply[:message] == 'twofactor'
|
161
|
+
MrMurano::Verbose.whirly_interject do
|
162
|
+
# Prompt user for emailed code.
|
163
|
+
token_twofactor_fetch(creds)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
showHttpError(request, response)
|
167
|
+
error 'Check to see if username and password are correct.'
|
168
|
+
unless ENV['MURANO_PASSWORD'].to_s.empty?
|
169
|
+
pwd_path = $cfg.file_at('passwords', :user)
|
170
|
+
warning "NOTE: MURANO_PASSWORD specifies the password; it was not read from #{pwd_path}"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
121
175
|
MrMurano::Verbose.whirly_stop
|
176
|
+
@logging_on = false
|
177
|
+
end
|
122
178
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
179
|
+
def token_twofactor_fetch(creds)
|
180
|
+
error 'Two-factor Authentication'
|
181
|
+
warning 'A verification code has been sent to your email.'
|
182
|
+
code = ask('Please enter the code here to continue: ').strip
|
183
|
+
unless code =~ /^[a-fA-F0-9]+$/
|
184
|
+
error 'Expected token to contain only numbers and hexadecimal letters.'
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
MrMurano::Verbose.whirly_start('Verifying code...')
|
188
|
+
|
189
|
+
path = 'key/' + code
|
190
|
+
|
191
|
+
response = get(path)
|
192
|
+
# Response is, e.g., {
|
193
|
+
# purpose: "twofactor",
|
194
|
+
# status: "exists",
|
195
|
+
# email: "xxx@yyy.zzz",
|
196
|
+
# bizid: null,
|
197
|
+
# businessName: null, }
|
198
|
+
return if response.nil?
|
199
|
+
|
200
|
+
response = post(path, password: creds[:password])
|
201
|
+
# Response is, e.g., { "token": "..." }
|
202
|
+
return if response.nil?
|
203
|
+
|
204
|
+
@twofactor_token = response[:token]
|
205
|
+
pwd_file = pwd_file_load
|
206
|
+
pwd_file.set(host, user + '/twofactor', @twofactor_token)
|
207
|
+
pwd_file.save
|
208
|
+
@token = @twofactor_token
|
209
|
+
MrMurano::Verbose.whirly_stop
|
210
|
+
|
211
|
+
warning 'Please run `murano logout --token` to clear your two-factor token when finished.'
|
212
|
+
end
|
213
|
+
|
214
|
+
def logout(token_delete_only)
|
215
|
+
@logging_on = true
|
216
|
+
|
217
|
+
pwd_file = pwd_file_load
|
218
|
+
twoftoken = token_twofactor_lookup(pwd_file)
|
219
|
+
|
220
|
+
# First, delete/invalidate the remote token.
|
221
|
+
unless twoftoken.to_s.empty?
|
222
|
+
@suppress_error = true
|
223
|
+
delete('token/' + twoftoken)
|
224
|
+
# The response is nil if the token was not recognized, otherwise it's
|
225
|
+
# {}. We don't really care, since we're going to forget our copy of
|
226
|
+
# the token, anyway.
|
227
|
+
@suppress_error = false
|
228
|
+
end
|
229
|
+
|
230
|
+
net_host = verify_set('net.host')
|
231
|
+
user_name = verify_set('user.name')
|
232
|
+
if net_host && user_name
|
233
|
+
pwd_file = MrMurano::Passwords.new
|
234
|
+
pwd_file.load
|
235
|
+
pwd_file.remove(net_host, user_name) unless token_delete_only
|
236
|
+
pwd_file.remove(net_host, user_name + '/twofactor')
|
237
|
+
pwd_file.save
|
238
|
+
end
|
239
|
+
|
240
|
+
clear_from_config(net_host, user_name) unless token_delete_only
|
241
|
+
|
242
|
+
@logging_on = false
|
243
|
+
end
|
244
|
+
|
245
|
+
def clear_from_config(net_host, user_name)
|
246
|
+
user_net_host = $cfg.get('net.host', :user)
|
247
|
+
user_net_host = $cfg.get('net.host', :defaults) if user_net_host.nil?
|
248
|
+
user_user_name = $cfg.get('user.name', :user)
|
249
|
+
# Only clear user name from the user config if the net.host
|
250
|
+
# or user.name did not come from a different config, like the
|
251
|
+
# --project config.
|
252
|
+
return unless (user_net_host == net_host) && (user_user_name == user_name)
|
253
|
+
$cfg.set('user.name', nil, :user)
|
254
|
+
$cfg.set('business.id', nil, :user)
|
255
|
+
$cfg.set('business.name', nil, :user)
|
256
|
+
end
|
257
|
+
|
258
|
+
def verify_set(cfg_key)
|
259
|
+
cfg_val = $cfg.get(cfg_key)
|
260
|
+
if cfg_val.to_s.empty?
|
261
|
+
cfg_val = nil
|
262
|
+
cfg_key_q = MrMurano::Verbose.fancy_ticks(cfg_key)
|
263
|
+
MrMurano::Verbose.warning("No config key #{cfg_key_q}: no password to delete")
|
135
264
|
end
|
265
|
+
cfg_val
|
136
266
|
end
|
137
267
|
|
138
268
|
# ---------------------------------------------------------------------
|
data/lib/MrMurano/Business.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -109,12 +109,7 @@ module MrMurano
|
|
109
109
|
|
110
110
|
def self.missing_business_id_msg
|
111
111
|
%(
|
112
|
-
|
113
|
-
Call `#{MrMurano::EXE_NAME} business list` to get a list of business IDs.
|
114
|
-
Set the ID temporarily using --config business.id=<ID>
|
115
|
-
or add to the project config using \`#{MrMurano::EXE_NAME} config business.id <ID>\`
|
116
|
-
or add to the user config using \`#{MrMurano::EXE_NAME} config business.id <ID> --user\`
|
117
|
-
or set it interactively using \`#{MrMurano::EXE_NAME} init\`
|
112
|
+
business ID not specified. For hints: #{MrMurano::EXE_NAME} business --help
|
118
113
|
).strip
|
119
114
|
end
|
120
115
|
|
data/lib/MrMurano/Config.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -301,7 +301,7 @@ module MrMurano
|
|
301
301
|
if the_cmd.name != 'help' && !the_cmd.project_not_required && !@project_exists
|
302
302
|
error %(The "#{the_cmd.name}" command only works in a Murano project.)
|
303
303
|
say INVALID_PROJECT_HINT
|
304
|
-
# Note that
|
304
|
+
# Note that commander-rb uses an at_exit hook, which we hack around.
|
305
305
|
@runner.command_exit = 1
|
306
306
|
false
|
307
307
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.27 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -9,37 +9,44 @@ module MrMurano
|
|
9
9
|
class ExchangeElement
|
10
10
|
include HashInit
|
11
11
|
|
12
|
-
#
|
13
|
-
# i.e., all of the other attrs in a Hash.
|
14
|
-
attr_reader :meta
|
12
|
+
# *** BizAPI members.
|
15
13
|
|
16
|
-
#
|
17
|
-
|
14
|
+
# These members are a copy of and ordered according to
|
15
|
+
# (the moving target known as) BizAPI. See:
|
16
|
+
#
|
17
|
+
# <bizapi>/lib/api/route/exchange/schemas/element.js::elementWithoutId
|
18
|
+
#
|
19
|
+
# But really what's returned is what's in the Mongo store, ha!
|
18
20
|
|
19
21
|
# The Exchange Element's Element ID.
|
22
|
+
# [lb] tempted to say :element_id, but keep it matchy, in spite of #linter.
|
20
23
|
attr_accessor :elementId
|
21
|
-
#attr_accessor :element_id
|
22
24
|
|
23
|
-
# The
|
24
|
-
attr_accessor :
|
25
|
-
#attr_accessor :purchase_id
|
26
|
-
|
27
|
-
# The <bizId>/exchange/ endpoint returns a list of flat dictionaries.
|
28
|
-
# The <bizId>/purchase/ endpoint, on the other hand, puts the remaining
|
29
|
-
# items in an object under an "element" key.
|
25
|
+
# The Exchange Element's Business ID context.
|
26
|
+
attr_accessor :bizid
|
30
27
|
|
31
|
-
# The type is one of: download
|
28
|
+
# The type is one of: download | product | application | contactSales
|
29
|
+
# though BizAPI 'list' command also accepts: service
|
32
30
|
attr_accessor :type
|
33
|
-
#attr_accessor :action_type
|
34
31
|
|
35
32
|
# The friendly, descriptive name of the Exchange Element.
|
36
33
|
attr_accessor :name
|
37
34
|
|
38
|
-
# FIXME/EXPLAIN: Is this what the Lua code calls the service?
|
39
|
-
attr_accessor :apiServiceName
|
40
|
-
|
41
35
|
# The image associated with the Exchange Element; not used by the CLI.
|
42
36
|
attr_accessor :image
|
37
|
+
# Contains ancestors:
|
38
|
+
# :thumbnail
|
39
|
+
# :url
|
40
|
+
# :filename
|
41
|
+
# :color
|
42
|
+
# :type
|
43
|
+
# :size
|
44
|
+
# :detail
|
45
|
+
# :url
|
46
|
+
# :filename
|
47
|
+
# :color
|
48
|
+
# :type
|
49
|
+
# :size
|
43
50
|
|
44
51
|
# The short description describing the Exchange Element.
|
45
52
|
attr_accessor :description
|
@@ -47,19 +54,75 @@ module MrMurano
|
|
47
54
|
# The long description describing the Exchange Element.
|
48
55
|
attr_accessor :markdown
|
49
56
|
|
50
|
-
# The
|
51
|
-
|
52
|
-
|
57
|
+
# The source associated with the Exchange Element; not currently used.
|
58
|
+
attr_accessor :source
|
59
|
+
# Contains ancestors:
|
60
|
+
# :from
|
61
|
+
# - One of: service | github | attachment | url
|
62
|
+
# :name
|
63
|
+
# :url
|
64
|
+
# :token
|
53
65
|
|
54
|
-
#
|
66
|
+
# Array of tags used to describe the Exchange Element.
|
55
67
|
attr_accessor :tags
|
56
68
|
|
69
|
+
# The attachment associated with 'attachment' sources; not currently used.
|
70
|
+
attr_accessor :attachment
|
71
|
+
# Contains ancestors:
|
72
|
+
# :download
|
73
|
+
# :url
|
74
|
+
# :filename
|
75
|
+
# :type
|
76
|
+
# :size
|
77
|
+
|
78
|
+
# The contact the user wrote for with the Exchange Element; not currently used.
|
79
|
+
attr_accessor :contact
|
80
|
+
|
81
|
+
# The specs the user wrote for the Exchange Element; not currently used.
|
82
|
+
attr_accessor :specs
|
83
|
+
|
84
|
+
# The active value is boolean; not currently used.
|
85
|
+
attr_accessor :active
|
86
|
+
|
87
|
+
# The access associated with the Exchange Element; not currently used.
|
88
|
+
# One of: public | private | network.
|
89
|
+
attr_accessor :access
|
90
|
+
|
91
|
+
# "approval" is not really documented. Code shows values: pending | approved.
|
92
|
+
attr_accessor :approval
|
93
|
+
|
94
|
+
# *** Values returned from BizAPI but defined specially.
|
95
|
+
|
96
|
+
# The Purchase ID is nil unless the user has added/purchased this element.
|
97
|
+
attr_accessor :purchaseId
|
98
|
+
#attr_accessor :purchase_id
|
99
|
+
|
100
|
+
# The <bizId>/exchange/ endpoint returns a list of flat dictionaries.
|
101
|
+
# The <bizId>/purchase/ endpoint, on the other hand, puts the remaining
|
102
|
+
# items in an object under an "element" key.
|
103
|
+
|
104
|
+
# FIXME/EXPLAIN: Is this what the Lua code calls the service?
|
105
|
+
attr_accessor :apiServiceName
|
106
|
+
|
107
|
+
# The Murano business tiers to which this element applies.
|
108
|
+
# Zero or more of: ["free", "developer", "professional", "enterprise"]
|
109
|
+
# NOTE: The 'tiers' values appears to be returned directly from Mongo DB.
|
110
|
+
# Specifically, BizAPI sets tiers = [] on new elements, but for global
|
111
|
+
# elements (in bootstrap/db/element.json), tiers is non-empty. [lb]
|
112
|
+
attr_accessor :tiers
|
113
|
+
|
57
114
|
# Actions associated with the Exchange Element.
|
58
115
|
attr_accessor :actions
|
59
116
|
# The actions is an array with one dict element with:
|
60
117
|
# 'url', 'type' (e.g., 'download), and 'primary' (bool).
|
61
118
|
|
62
|
-
#
|
119
|
+
# *** Internal Murano CLI variables (i.e., not in BizAPI).
|
120
|
+
|
121
|
+
# The meta is the Hash of the Exchange Element returned from the platform.
|
122
|
+
attr_reader :meta
|
123
|
+
|
124
|
+
# Based on purchaseId and tiers, state of Element in Business. One of:
|
125
|
+
# :available | :upgrade | :added
|
63
126
|
attr_accessor :statusable
|
64
127
|
|
65
128
|
ELEM_KEY_TRANSLATE = {
|
@@ -68,6 +131,7 @@ module MrMurano
|
|
68
131
|
}.freeze
|
69
132
|
|
70
133
|
def initialize(*hash)
|
134
|
+
@show_errors = $cfg['tool.verbose']
|
71
135
|
hash = [hash] unless hash.is_a? Array
|
72
136
|
camel_cased = {}
|
73
137
|
hash.first.each do |key, val|
|
data/lib/MrMurano/Exchange.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.27 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -24,7 +24,21 @@ module MrMurano
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def fetch_type(part)
|
27
|
-
|
27
|
+
# [lb] not super happy about mixing presentation with other logic
|
28
|
+
# but this is quick and dirty.
|
29
|
+
case part
|
30
|
+
when '/element/'
|
31
|
+
qualifier = 'All'
|
32
|
+
when '/purchase/'
|
33
|
+
qualifier = 'Purchased'
|
34
|
+
else
|
35
|
+
raise 'Unexpected error'
|
36
|
+
end
|
37
|
+
whirly_start("Fetching #{qualifier} Elements...")
|
38
|
+
|
39
|
+
# FIXME/2017-09-27: Support Pagination. BizAPI accepts four settings:
|
40
|
+
# type, offset, limit, and select.
|
41
|
+
# <bizapi>/lib/api/route/exchange/schemas/element.js
|
28
42
|
ret = get('exchange/' + bid + part) do |request, http|
|
29
43
|
response = http.request(request)
|
30
44
|
case response
|
@@ -50,14 +64,23 @@ module MrMurano
|
|
50
64
|
lookp = {}
|
51
65
|
# Get the user's Business metadata, including their Business tier.
|
52
66
|
overview if @ometa.nil?
|
67
|
+
elems = fetch_elements(lookp)
|
68
|
+
fetch_purchased(lookp)
|
69
|
+
prepare_elements(elems, **opts)
|
70
|
+
end
|
71
|
+
|
72
|
+
def fetch_elements(lookp)
|
53
73
|
# Fetch the list of Elements, including Added, Available, and Upgradeable.
|
54
74
|
items = fetch_type('/element/')
|
55
75
|
# Prepare a lookup of the Elements.
|
56
|
-
|
76
|
+
items.map do |meta|
|
57
77
|
elem = MrMurano::ExchangeElement.new(meta)
|
58
78
|
lookp[elem.elementId] = elem
|
59
79
|
elem
|
60
80
|
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def fetch_purchased(lookp)
|
61
84
|
# Fetch the list of Purchased elements.
|
62
85
|
items = fetch_type('/purchase/')
|
63
86
|
# Update the list of all Elements to indicate which have been purchased.
|
@@ -67,8 +90,8 @@ module MrMurano
|
|
67
90
|
elem.purchaseId = meta[:purchaseId]
|
68
91
|
# Sanity check.
|
69
92
|
meta[:element].each do |key, val|
|
70
|
-
next if elem
|
71
|
-
|
93
|
+
next if verify_purchase_vs_element(elem, key, val)
|
94
|
+
verbose(
|
72
95
|
'Unexpected: Exchange Purchase element meta differs: ' \
|
73
96
|
"key: #{key} / elem: #{elem.send(key)} / purchase: #{val}"
|
74
97
|
)
|
@@ -77,7 +100,13 @@ module MrMurano
|
|
77
100
|
warning("Unexpected: No Element found for Exchange Purchase: elementId: #{meta[:elementId]}")
|
78
101
|
end
|
79
102
|
end
|
80
|
-
|
103
|
+
end
|
104
|
+
|
105
|
+
def verify_purchase_vs_element(elem, key, val)
|
106
|
+
elem.send(key) == val
|
107
|
+
rescue NoMethodError
|
108
|
+
verbose("Unexpected: Exchange Element missing key found in Purchase Element: #{key}")
|
109
|
+
true
|
81
110
|
end
|
82
111
|
|
83
112
|
def prepare_elements(elems, filter_id: nil, filter_name: nil, filter_fuzzy: nil)
|
data/lib/MrMurano/Passwords.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -69,6 +69,10 @@ module MrMurano
|
|
69
69
|
).strip
|
70
70
|
return ENV['MR_PASSWORD']
|
71
71
|
end
|
72
|
+
lookup(host, user)
|
73
|
+
end
|
74
|
+
|
75
|
+
def lookup(host, user)
|
72
76
|
return nil unless @data.is_a?(Hash)
|
73
77
|
return nil unless @data.key?(host)
|
74
78
|
return nil unless @data[host].is_a?(Hash)
|
data/lib/MrMurano/SyncUpDown.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.21 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -665,6 +665,8 @@ module MrMurano
|
|
665
665
|
# @param options [Hash, Commander::Command::Options] Options on operation
|
666
666
|
# @param selected [Array<String>] Filters for _matcher
|
667
667
|
def syncup(options={}, selected=[])
|
668
|
+
return 0 unless api_id?
|
669
|
+
|
668
670
|
options = elevate_hash(options)
|
669
671
|
options[:asdown] = false
|
670
672
|
|
@@ -727,6 +729,8 @@ module MrMurano
|
|
727
729
|
# @param options [Hash, Commander::Command::Options] Options on operation
|
728
730
|
# @param selected [Array<String>] Filters for _matcher
|
729
731
|
def syncdown(options={}, selected=[])
|
732
|
+
return 0 unless api_id?
|
733
|
+
|
730
734
|
options = elevate_hash(options)
|
731
735
|
options[:asdown] = true
|
732
736
|
options[:skip_missing_warning] = true
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -20,6 +20,16 @@ command :business do |c|
|
|
20
20
|
c.summary = %(About business)
|
21
21
|
c.description = %(
|
22
22
|
Commands for working with businesses.
|
23
|
+
|
24
|
+
If you need to set the business ID, try some of the following:
|
25
|
+
|
26
|
+
- Get a list of Business IDs: #{MrMurano::EXE_NAME} business list
|
27
|
+
|
28
|
+
- Specify the ID explictly: #{MrMurano::EXE_NAME} <cmd> --config business.id=<ID>
|
29
|
+
Add the ID to a project config: #{MrMurano::EXE_NAME} config business.id <ID>
|
30
|
+
Add the ID to the user config: #{MrMurano::EXE_NAME} config business.id <ID> --user
|
31
|
+
Setup a project interactively: #{MrMurano::EXE_NAME} init
|
32
|
+
|
23
33
|
).strip
|
24
34
|
c.project_not_required = true
|
25
35
|
c.subcmdgrouphelp = true
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.13 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -19,11 +19,38 @@ Set the CORS with `murano cors set`.
|
|
19
19
|
).strip
|
20
20
|
c.project_not_required = true
|
21
21
|
|
22
|
+
c.example %(
|
23
|
+
Output CORS parameters in an ASCII table.
|
24
|
+
).strip, 'murano cors'
|
25
|
+
|
26
|
+
c.example %(
|
27
|
+
Output CORS parameters as JSON.
|
28
|
+
).strip, 'murano cors --json'
|
29
|
+
|
30
|
+
c.example %(
|
31
|
+
Output CORS parameters in Yaml.
|
32
|
+
).strip, 'murano cors --yaml'
|
33
|
+
|
34
|
+
c.example %(
|
35
|
+
Output CORS parameters as comma-separated values.
|
36
|
+
).strip, 'murano cors --csv'
|
37
|
+
|
38
|
+
c.example %(
|
39
|
+
Output CORS parameters pretty-printed as a Ruby Hash.
|
40
|
+
).strip, 'murano cors --pp'
|
41
|
+
|
22
42
|
c.action do |args, _options|
|
23
43
|
c.verify_arg_count!(args)
|
24
44
|
sol = MrMurano::Webservice::Cors.new
|
25
45
|
ret = sol.fetch
|
26
|
-
sol.outf
|
46
|
+
sol.outf(ret) do |obj, ios|
|
47
|
+
# Called if tool.outformat is 'best' or 'csv' (not 'json', 'yaml', or 'pp').
|
48
|
+
headers = obj.keys.sort
|
49
|
+
row = []
|
50
|
+
headers.each { |key| row << obj[key] }
|
51
|
+
rows = [row]
|
52
|
+
sol.tabularize({ headers: headers, rows: rows }, ios)
|
53
|
+
end
|
27
54
|
end
|
28
55
|
end
|
29
56
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -62,6 +62,7 @@ Element status:
|
|
62
62
|
cmd_defaults_id_and_name(options)
|
63
63
|
|
64
64
|
xchg = MrMurano::Exchange.new
|
65
|
+
xchg.must_business_id!
|
65
66
|
|
66
67
|
elems, available, purchased = find_elements(xchg, options, args[0])
|
67
68
|
if options.added.nil?
|
@@ -169,7 +170,7 @@ def cmd_exchange_header_and_elems(elems, options)
|
|
169
170
|
# Calculate the width of each column except the last (:description).
|
170
171
|
headers[0..-2].each do |key|
|
171
172
|
elem_with_max = elems.max { |a, b| a.send(key).length <=> b.send(key).length }
|
172
|
-
width_taken += elem_with_max.send(key).length
|
173
|
+
width_taken += elem_with_max.send(key).length unless elem_with_max.nil?
|
173
174
|
width_taken += ' | '.length
|
174
175
|
end
|
175
176
|
width_taken += ' | '.length
|
@@ -233,6 +234,7 @@ Add an Exchange Element to your Business.
|
|
233
234
|
cmd_defaults_id_and_name(options)
|
234
235
|
|
235
236
|
xchg = MrMurano::Exchange.new
|
237
|
+
xchg.must_business_id!
|
236
238
|
|
237
239
|
# If the user specifies filter_id, we could try to fetch that Element
|
238
240
|
# directly (e.g., by calling exchange/<bizId>/element/<elemId>),
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.21 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -42,43 +42,16 @@ it will remove that user's password from the password file.
|
|
42
42
|
Essentially, this command is the same as:
|
43
43
|
|
44
44
|
murano password delete <username>
|
45
|
+
murano password delete <username>/twofactor
|
45
46
|
murano config --unset --user user.name
|
46
47
|
).strip
|
47
48
|
c.project_not_required = true
|
48
49
|
|
49
|
-
c.
|
50
|
-
c.verify_arg_count!(args)
|
51
|
-
|
52
|
-
net_host = verify_set('net.host')
|
53
|
-
user_name = verify_set('user.name')
|
54
|
-
if net_host && user_name
|
55
|
-
psd = MrMurano::Passwords.new
|
56
|
-
psd.load
|
57
|
-
psd.remove(net_host, user_name)
|
58
|
-
psd.save
|
59
|
-
end
|
60
|
-
|
61
|
-
user_net_host = $cfg.get('net.host', :user)
|
62
|
-
user_net_host = $cfg.get('net.host', :defaults) if user_net_host.nil?
|
63
|
-
user_user_name = $cfg.get('user.name', :user)
|
64
|
-
if (user_net_host == net_host) && (user_user_name == user_name)
|
65
|
-
# Only clear user name from the user config if the net.host
|
66
|
-
# or user.name did not come from a different config, like the
|
67
|
-
# --project config.
|
68
|
-
$cfg.set('user.name', nil, :user)
|
69
|
-
$cfg.set('business.id', nil, :user)
|
70
|
-
$cfg.set('business.name', nil, :user)
|
71
|
-
end
|
72
|
-
end
|
50
|
+
c.option '--token', 'Remove just the two-factor token'
|
73
51
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
cfg_val = nil
|
78
|
-
cfg_key_q = MrMurano::Verbose.fancy_ticks(cfg_key)
|
79
|
-
MrMurano::Verbose.warning("No config key #{cfg_key_q}: no password to delete")
|
80
|
-
end
|
81
|
-
cfg_val
|
52
|
+
c.action do |args, options|
|
53
|
+
c.verify_arg_count!(args)
|
54
|
+
MrMurano::Account.instance.logout(options.token)
|
82
55
|
end
|
83
56
|
end
|
84
57
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -10,15 +10,16 @@ require 'MrMurano/Solution'
|
|
10
10
|
|
11
11
|
command :usage do |c|
|
12
12
|
c.syntax = %(murano usage)
|
13
|
-
c.summary = %(Get usage info for
|
13
|
+
c.summary = %(Get usage info for the Application and Product)
|
14
14
|
c.description = %(
|
15
|
-
Get usage info for
|
15
|
+
Get usage info for the Application and Product.
|
16
16
|
).strip
|
17
|
+
c.project_not_required = true
|
17
18
|
|
18
19
|
# Add flag: --type [application|product|all].
|
19
20
|
cmd_add_solntype_pickers(c)
|
20
21
|
|
21
|
-
c.option '--[no-]all', 'Show usage for all Solutions in Business
|
22
|
+
c.option '--[no-]all', 'Show usage for all Solutions in Business'
|
22
23
|
c.option(
|
23
24
|
'--[no-]header', %(Output solution descriptions (default: true))
|
24
25
|
)
|
data/lib/MrMurano/hash.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.27 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -113,7 +113,7 @@ module HashInit
|
|
113
113
|
hash.first.each do |key, val|
|
114
114
|
if respond_to? key
|
115
115
|
send("#{key}=", val)
|
116
|
-
|
116
|
+
elsif defined?(@show_errors) && @show_errors
|
117
117
|
$stderr.puts %(HashInit: missing hash key "#{key}")
|
118
118
|
end
|
119
119
|
end
|
data/lib/MrMurano/http.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -108,7 +108,7 @@ module MrMurano
|
|
108
108
|
# 2017-08-14: MrMurano::Account overrides the token method, and
|
109
109
|
# it doesn't exit if no token, and then we end up here.
|
110
110
|
ensure_token! token
|
111
|
-
request['Authorization'] = 'token ' + token
|
111
|
+
request['Authorization'] = 'token ' + token unless token.to_s.empty?
|
112
112
|
request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
|
113
113
|
request
|
114
114
|
end
|
data/lib/MrMurano/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.28 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -26,7 +26,7 @@ module MrMurano
|
|
26
26
|
# '3.0.0-beta.2' is changed to '3.0.0.pre.beta.2'
|
27
27
|
# which breaks our build (which expects the version to match herein).
|
28
28
|
# So stick to using the '.pre.X' syntax, which ruby/gems knows.
|
29
|
-
VERSION = '3.0.
|
29
|
+
VERSION = '3.0.5'
|
30
30
|
EXE_NAME = File.basename($PROGRAM_NAME)
|
31
31
|
SIGN_UP_URL = 'https://exosite.com/signup/'
|
32
32
|
end
|
data/spec/Account_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.21 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -45,6 +45,7 @@ RSpec.describe MrMurano::Account, 'token' do
|
|
45
45
|
it 'Asks for nothing' do
|
46
46
|
$cfg['user.name'] = 'bob'
|
47
47
|
expect(@pswd).to receive(:get).once.and_return('built')
|
48
|
+
expect(@pswd).to receive(:lookup).once.and_return(nil)
|
48
49
|
|
49
50
|
ret = @acc.login_info
|
50
51
|
expect(ret).to eq(email: 'bob', password: 'built')
|
@@ -56,6 +57,7 @@ RSpec.describe MrMurano::Account, 'token' do
|
|
56
57
|
expect(@acc).to receive(:error).once
|
57
58
|
expect($cfg).to receive(:set).with('user.name', 'bob', :user).once.and_call_original
|
58
59
|
expect(@pswd).to receive(:get).once.and_return('built')
|
60
|
+
expect(@pswd).to receive(:lookup).once.and_return(nil)
|
59
61
|
|
60
62
|
ret = @acc.login_info
|
61
63
|
expect(ret).to eq(email: 'bob', password: 'built')
|
@@ -67,6 +69,7 @@ RSpec.describe MrMurano::Account, 'token' do
|
|
67
69
|
expect(@acc).to receive(:error).once
|
68
70
|
expect($terminal).to receive(:ask).once.and_return('dog')
|
69
71
|
expect(@pswd).to receive(:set).once.with('bizapi.hosted.exosite.io', 'bob', 'dog')
|
72
|
+
expect(@pswd).to receive(:set).once.with('bizapi.hosted.exosite.io', 'bob/twofactor', nil)
|
70
73
|
# 2017-07-31: login_info may exit unless the command okays prompting for the password.
|
71
74
|
# (If we don't set this, login_info exits, which we'd want to
|
72
75
|
# catch with
|
data/spec/Content_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -11,6 +11,14 @@ require 'MrMurano/Content'
|
|
11
11
|
require 'MrMurano/SyncRoot'
|
12
12
|
require '_workspace'
|
13
13
|
|
14
|
+
# rubocop:disable Style/HashSyntax
|
15
|
+
# - 'Use the new Ruby 1.9 hash syntax.'
|
16
|
+
# E.g.,
|
17
|
+
# :'x-amz-meta-name' => 'Solutionfile.json',
|
18
|
+
# because quoted string keys, e.g.,
|
19
|
+
# 'x-amz-meta-name': 'Solutionfile.json',
|
20
|
+
# are not supported in Ruby 2.0.
|
21
|
+
|
14
22
|
RSpec.describe MrMurano::Content::Base do
|
15
23
|
include_context 'WORKSPACE'
|
16
24
|
before(:example) do
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# Last Modified: 2017.09.28 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
8
|
+
require 'fileutils'
|
9
|
+
require 'open3'
|
10
|
+
require 'pathname'
|
11
|
+
require 'cmd_common'
|
12
|
+
|
13
|
+
# NOTE: This file is a copy of, and subset of, cmd_syncdown_both_spec.rb.
|
14
|
+
|
15
|
+
RSpec.describe 'murano single sync', :cmd, :needs_password do
|
16
|
+
include_context 'CI_CMD'
|
17
|
+
|
18
|
+
before(:example) do
|
19
|
+
@applctn_name = rname('syncdownTestApp')
|
20
|
+
out, err, status = Open3.capture3(
|
21
|
+
capcmd('murano', 'application', 'create', @applctn_name, '--save')
|
22
|
+
)
|
23
|
+
expect(err).to eq('')
|
24
|
+
soln_id = out
|
25
|
+
expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
|
26
|
+
expect(status.exitstatus).to eq(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
after(:example) do
|
30
|
+
out, err, status = Open3.capture3(
|
31
|
+
capcmd('murano', 'solution', 'delete', '-y', @applctn_name)
|
32
|
+
)
|
33
|
+
expect(out).to eq('')
|
34
|
+
expect(err).to eq('')
|
35
|
+
expect(status.exitstatus).to eq(0)
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'without ProjectFile' do
|
39
|
+
before(:example) do
|
40
|
+
FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
|
41
|
+
FileUtils.move('assets', 'files')
|
42
|
+
FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_conflict/.'), '.')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'syncdown' do
|
46
|
+
out, err, status = Open3.capture3(capcmd('murano', 'syncup'))
|
47
|
+
out_lines = out.lines.map { |line| strip_fancy(line) }
|
48
|
+
expect(out_lines).to match_array(
|
49
|
+
[
|
50
|
+
"Adding item table_util\n",
|
51
|
+
a_string_starting_with('Updating item '),
|
52
|
+
"Updating item user_account\n",
|
53
|
+
"Adding item POST_/api/fire\n",
|
54
|
+
"Adding item PUT_/api/fire/{code}\n",
|
55
|
+
"Adding item DELETE_/api/fire/{code}\n",
|
56
|
+
"Adding item GET_/api/onfire\n",
|
57
|
+
"Adding item /icon.png\n",
|
58
|
+
"Adding item /\n",
|
59
|
+
"Adding item /js/script.js\n",
|
60
|
+
]
|
61
|
+
)
|
62
|
+
|
63
|
+
expect(err).to eq('')
|
64
|
+
expect(status.exitstatus).to eq(0)
|
65
|
+
|
66
|
+
FileUtils.rm_r(%w[files modules routes services])
|
67
|
+
expect(Dir['**/*']).to eq([])
|
68
|
+
|
69
|
+
out, err, status = Open3.capture3(capcmd('murano', 'syncdown'))
|
70
|
+
out_lines = out.lines.map { |line| strip_fancy(line) }
|
71
|
+
expect(out_lines).to match_array(
|
72
|
+
[
|
73
|
+
"Adding item table_util\n",
|
74
|
+
# 2017-08-08: This says updating now because timer.timer is undeletable.
|
75
|
+
#"Adding item timer_timer\n",
|
76
|
+
"Updating item timer_timer\n",
|
77
|
+
"Adding item POST_/api/fire\n",
|
78
|
+
"Adding item DELETE_/api/fire/{code}\n",
|
79
|
+
"Adding item PUT_/api/fire/{code}\n",
|
80
|
+
"Adding item GET_/api/onfire\n",
|
81
|
+
"Adding item /js/script.js\n",
|
82
|
+
"Adding item /icon.png\n",
|
83
|
+
"Adding item /\n",
|
84
|
+
]
|
85
|
+
)
|
86
|
+
expect(err).to eq('')
|
87
|
+
expect(status.exitstatus).to eq(0)
|
88
|
+
|
89
|
+
after = Dir['**/*'].sort
|
90
|
+
expect(after).to include(
|
91
|
+
'files',
|
92
|
+
'files/icon.png',
|
93
|
+
'files/index.html',
|
94
|
+
'files/js',
|
95
|
+
'files/js/script.js',
|
96
|
+
'modules',
|
97
|
+
'modules/table_util.lua',
|
98
|
+
'routes',
|
99
|
+
'routes/api-fire-{code}.delete.lua',
|
100
|
+
'routes/api-fire-{code}.put.lua',
|
101
|
+
'routes/api-fire.post.lua',
|
102
|
+
'routes/api-onfire.get.lua',
|
103
|
+
'services',
|
104
|
+
'services/timer_timer.lua',
|
105
|
+
)
|
106
|
+
|
107
|
+
# A status should show no differences.
|
108
|
+
out, err, status = Open3.capture3(capcmd('murano', 'status'))
|
109
|
+
expect(err).to eq('')
|
110
|
+
expect(out.lines).to match(
|
111
|
+
[
|
112
|
+
"Nothing new locally\n",
|
113
|
+
"Nothing new remotely\n",
|
114
|
+
"Nothing that differs\n",
|
115
|
+
"Items without a solution:\n",
|
116
|
+
" - R Resource\n",
|
117
|
+
" - I Interface\n",
|
118
|
+
]
|
119
|
+
)
|
120
|
+
expect(status.exitstatus).to eq(0)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.25 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -15,14 +15,18 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
|
|
15
15
|
|
16
16
|
before(:example) do
|
17
17
|
@product_name = rname('syncdownTestPrd')
|
18
|
-
out, err, status = Open3.capture3(
|
18
|
+
out, err, status = Open3.capture3(
|
19
|
+
capcmd('murano', 'product', 'create', @product_name, '--save')
|
20
|
+
)
|
19
21
|
expect(err).to eq('')
|
20
22
|
soln_id = out
|
21
23
|
expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
|
22
24
|
expect(status.exitstatus).to eq(0)
|
23
25
|
|
24
26
|
@applctn_name = rname('syncdownTestApp')
|
25
|
-
out, err, status = Open3.capture3(
|
27
|
+
out, err, status = Open3.capture3(
|
28
|
+
capcmd('murano', 'application', 'create', @applctn_name, '--save')
|
29
|
+
)
|
26
30
|
expect(err).to eq('')
|
27
31
|
soln_id = out
|
28
32
|
expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
|
@@ -31,7 +35,9 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
|
|
31
35
|
out, err, status = Open3.capture3(capcmd('murano', 'assign', 'set'))
|
32
36
|
#expect(out).to a_string_starting_with("Linked product #{@product_name}")
|
33
37
|
olines = out.lines
|
34
|
-
expect(strip_fancy(olines[0])).to eq(
|
38
|
+
expect(strip_fancy(olines[0])).to eq(
|
39
|
+
"Linked '#{@product_name}' to '#{@applctn_name}'\n"
|
40
|
+
)
|
35
41
|
expect(olines[1]).to eq("Created default event handler\n")
|
36
42
|
expect(err).to eq('')
|
37
43
|
expect(status.exitstatus).to eq(0)
|
@@ -40,12 +46,16 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
|
|
40
46
|
after(:example) do
|
41
47
|
# VERIFY/2017-07-03: Skipping assign unset. Murano will clean up, right?
|
42
48
|
|
43
|
-
out, err, status = Open3.capture3(
|
49
|
+
out, err, status = Open3.capture3(
|
50
|
+
capcmd('murano', 'solution', 'delete', '-y', @applctn_name)
|
51
|
+
)
|
44
52
|
expect(out).to eq('')
|
45
53
|
expect(err).to eq('')
|
46
54
|
expect(status.exitstatus).to eq(0)
|
47
55
|
|
48
|
-
out, err, status = Open3.capture3(
|
56
|
+
out, err, status = Open3.capture3(
|
57
|
+
capcmd('murano', 'solution', 'delete', '--yes', @product_name)
|
58
|
+
)
|
49
59
|
expect(out).to eq('')
|
50
60
|
expect(err).to eq('')
|
51
61
|
expect(status.exitstatus).to eq(0)
|
@@ -56,8 +66,10 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
|
|
56
66
|
FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
|
57
67
|
FileUtils.move('assets', 'files')
|
58
68
|
#FileUtils.mkpath('specs')
|
59
|
-
#FileUtils.copy(
|
60
|
-
# '
|
69
|
+
#FileUtils.copy(
|
70
|
+
# File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'),
|
71
|
+
# 'specs/resources.yaml'
|
72
|
+
#)
|
61
73
|
# 2017-07-03: So long as this command does not syncdown first, these
|
62
74
|
# two files -- that conflict in name with what's on the platform --
|
63
75
|
# won't be a problem (but would be if we synceddown first).
|
@@ -143,7 +155,8 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
|
|
143
155
|
'routes/api-fire-{code}.put.lua',
|
144
156
|
'routes/api-fire.post.lua',
|
145
157
|
'routes/api-onfire.get.lua',
|
146
|
-
# 2017-07-03: services/ would not exist if we did not include
|
158
|
+
# 2017-07-03: services/ would not exist if we did not include
|
159
|
+
# fixtures/syncable_conflict/.
|
147
160
|
'services',
|
148
161
|
# 2017-07-13: No longer syncing device2_event; is internal to platform.
|
149
162
|
#'services/device2_event.lua',
|
data/spec/cmd_syncup_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.09.
|
1
|
+
# Last Modified: 2017.09.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -82,7 +82,7 @@ RSpec.describe 'murano syncup', :cmd, :needs_password do
|
|
82
82
|
# Windows is insane:
|
83
83
|
# "Adding item ........................Administrator.AppData.Local.Temp.2.d20170913-3860-pgji6g.project.modules.table_util\n"
|
84
84
|
#expect(outl[5]).to eq("Adding item table_util\n")
|
85
|
-
expect(outl[5]).to start_with(
|
85
|
+
expect(outl[5]).to start_with('Adding item ')
|
86
86
|
expect(outl[5]).to end_with("table_util\n")
|
87
87
|
#expect(outl[6]).to eq("Updating item c3juj9vnmec000000_event\n")
|
88
88
|
# The order isn't always consistent, so just do start_with.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: MuranoCLI
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.5
|
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: 2017-09-
|
11
|
+
date: 2017-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: certified
|
@@ -405,8 +405,8 @@ executables:
|
|
405
405
|
extensions: []
|
406
406
|
extra_rdoc_files: []
|
407
407
|
files:
|
408
|
-
- ".agignore"
|
409
408
|
- ".gitignore"
|
409
|
+
- ".ignore"
|
410
410
|
- ".rspec"
|
411
411
|
- ".rubocop.yml"
|
412
412
|
- ".travis.yml"
|
@@ -542,7 +542,8 @@ files:
|
|
542
542
|
- spec/cmd_setting_application_spec.rb
|
543
543
|
- spec/cmd_setting_product_spec.rb
|
544
544
|
- spec/cmd_status_spec.rb
|
545
|
-
- spec/
|
545
|
+
- spec/cmd_syncdown_application_spec.rb
|
546
|
+
- spec/cmd_syncdown_both_spec.rb
|
546
547
|
- spec/cmd_syncup_spec.rb
|
547
548
|
- spec/cmd_usage_spec.rb
|
548
549
|
- spec/fixtures/.mrmuranorc
|