MuranoCLI 3.0.4 → 3.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|