MuranoCLI 3.2.0.beta.1 → 3.2.0.beta.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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/.trustme.plugin +137 -0
  4. data/.trustme.sh +217 -117
  5. data/.trustme.vim +9 -3
  6. data/Gemfile +9 -3
  7. data/MuranoCLI.gemspec +8 -5
  8. data/Rakefile +1 -0
  9. data/dockers/Dockerfile.2.2.9 +6 -3
  10. data/dockers/Dockerfile.2.3.6 +6 -3
  11. data/dockers/Dockerfile.2.4.3 +6 -3
  12. data/dockers/Dockerfile.2.5.0 +6 -3
  13. data/dockers/Dockerfile.GemRelease +10 -8
  14. data/dockers/Dockerfile.m4 +23 -5
  15. data/dockers/docker-test.sh +65 -28
  16. data/docs/completions/murano_completion-bash +751 -57
  17. data/docs/develop.rst +10 -9
  18. data/lib/MrMurano/AccountBase.rb +95 -6
  19. data/lib/MrMurano/Commander-Entry.rb +9 -4
  20. data/lib/MrMurano/Config-Migrate.rb +2 -0
  21. data/lib/MrMurano/Config.rb +94 -26
  22. data/lib/MrMurano/Content.rb +1 -1
  23. data/lib/MrMurano/Exchange.rb +77 -42
  24. data/lib/MrMurano/Gateway.rb +1 -1
  25. data/lib/MrMurano/HttpAuthed.rb +20 -7
  26. data/lib/MrMurano/Logs.rb +10 -1
  27. data/lib/MrMurano/ProjectFile.rb +1 -1
  28. data/lib/MrMurano/ReCommander.rb +129 -73
  29. data/lib/MrMurano/Solution-ServiceConfig.rb +18 -11
  30. data/lib/MrMurano/Solution-Services.rb +78 -50
  31. data/lib/MrMurano/Solution-Users.rb +1 -1
  32. data/lib/MrMurano/Solution.rb +13 -63
  33. data/lib/MrMurano/SyncUpDown-Core.rb +185 -77
  34. data/lib/MrMurano/SyncUpDown-Item.rb +29 -4
  35. data/lib/MrMurano/SyncUpDown.rb +11 -11
  36. data/lib/MrMurano/Webservice-Cors.rb +1 -1
  37. data/lib/MrMurano/Webservice-Endpoint.rb +28 -17
  38. data/lib/MrMurano/Webservice-File.rb +103 -43
  39. data/lib/MrMurano/commands/domain.rb +1 -0
  40. data/lib/MrMurano/commands/element.rb +585 -0
  41. data/lib/MrMurano/commands/exchange.rb +211 -204
  42. data/lib/MrMurano/commands/gb.rb +1 -0
  43. data/lib/MrMurano/commands/globals.rb +17 -7
  44. data/lib/MrMurano/commands/init.rb +115 -101
  45. data/lib/MrMurano/commands/keystore.rb +1 -1
  46. data/lib/MrMurano/commands/logs.rb +2 -1
  47. data/lib/MrMurano/commands/postgresql.rb +17 -7
  48. data/lib/MrMurano/commands/service.rb +572 -0
  49. data/lib/MrMurano/commands/show.rb +7 -3
  50. data/lib/MrMurano/commands/solution.rb +2 -1
  51. data/lib/MrMurano/commands/solution_picker.rb +31 -15
  52. data/lib/MrMurano/commands/status.rb +205 -169
  53. data/lib/MrMurano/commands/sync.rb +70 -38
  54. data/lib/MrMurano/commands/token.rb +59 -14
  55. data/lib/MrMurano/commands/usage.rb +1 -0
  56. data/lib/MrMurano/commands.rb +2 -0
  57. data/lib/MrMurano/hash.rb +91 -0
  58. data/lib/MrMurano/http.rb +55 -6
  59. data/lib/MrMurano/makePretty.rb +47 -0
  60. data/lib/MrMurano/optparse.rb +60 -45
  61. data/lib/MrMurano/variegated/TruthyFalsey.rb +48 -0
  62. data/lib/MrMurano/variegated/ruby_dig.rb +64 -0
  63. data/lib/MrMurano/verbosing.rb +113 -3
  64. data/lib/MrMurano/version.rb +1 -1
  65. data/spec/Account_spec.rb +34 -20
  66. data/spec/Business_spec.rb +12 -9
  67. data/spec/Config_spec.rb +7 -1
  68. data/spec/Content_spec.rb +17 -1
  69. data/spec/GatewayBase_spec.rb +5 -2
  70. data/spec/GatewayDevice_spec.rb +4 -2
  71. data/spec/GatewayResource_spec.rb +4 -1
  72. data/spec/GatewaySettings_spec.rb +4 -1
  73. data/spec/HttpAuthed_spec.rb +73 -0
  74. data/spec/Http_spec.rb +32 -35
  75. data/spec/ProjectFile_spec.rb +1 -1
  76. data/spec/Solution-ServiceConfig_spec.rb +4 -1
  77. data/spec/Solution-ServiceEventHandler_spec.rb +6 -3
  78. data/spec/Solution-ServiceModules_spec.rb +4 -1
  79. data/spec/Solution-UsersRoles_spec.rb +4 -1
  80. data/spec/Solution_spec.rb +4 -1
  81. data/spec/SyncUpDown_spec.rb +1 -1
  82. data/spec/Webservice-Cors_spec.rb +4 -1
  83. data/spec/Webservice-Endpoint_spec.rb +9 -6
  84. data/spec/Webservice-File_spec.rb +17 -4
  85. data/spec/Webservice-Setting_spec.rb +6 -2
  86. data/spec/_workspace.rb +2 -0
  87. data/spec/cmd_common.rb +42 -13
  88. data/spec/cmd_content_spec.rb +17 -7
  89. data/spec/cmd_device_spec.rb +1 -1
  90. data/spec/cmd_domain_spec.rb +2 -2
  91. data/spec/cmd_element_spec.rb +400 -0
  92. data/spec/cmd_exchange_spec.rb +2 -2
  93. data/spec/cmd_init_spec.rb +59 -25
  94. data/spec/cmd_keystore_spec.rb +6 -3
  95. data/spec/cmd_link_spec.rb +10 -5
  96. data/spec/cmd_logs_spec.rb +1 -1
  97. data/spec/cmd_setting_application_spec.rb +18 -15
  98. data/spec/cmd_setting_product_spec.rb +7 -7
  99. data/spec/cmd_status_spec.rb +27 -17
  100. data/spec/cmd_syncdown_application_spec.rb +30 -3
  101. data/spec/cmd_syncdown_both_spec.rb +72 -18
  102. data/spec/cmd_syncup_spec.rb +71 -5
  103. data/spec/cmd_token_spec.rb +2 -2
  104. data/spec/cmd_usage_spec.rb +2 -2
  105. data/spec/dry_run_formatter.rb +27 -0
  106. data/spec/fixtures/dumped_config +8 -0
  107. data/spec/fixtures/exchange_element/element-show.json +1 -0
  108. data/spec/fixtures/exchange_element/swagger-mur-6407__10k.yaml +282 -0
  109. data/spec/fixtures/exchange_element/swagger-mur-6407__20k.yaml +588 -0
  110. data/spec/variegated_TruthyFalsey_spec.rb +29 -0
  111. metadata +51 -25
@@ -20,8 +20,10 @@ require 'MrMurano/commands/business'
20
20
  require 'MrMurano/commands/solution'
21
21
  require 'MrMurano/commands/sync'
22
22
 
23
- def init_cmd_description
24
- %(
23
+ class InitCmd
24
+ include MrMurano::Verbose
25
+
26
+ INIT_CMD_DESCRIPTION = %(
25
27
 
26
28
  The init command helps you create a new Murano project
27
29
  ======================================================
@@ -101,115 +103,117 @@ that you can edit.
101
103
  http://docs.exosite.com/
102
104
 
103
105
  ).strip
104
- end
105
-
106
- command :init do |c|
107
- c.syntax = %(murano init)
108
- c.summary = %(The easy way to start a project)
109
- c.description = init_cmd_description
110
106
 
111
- c.example %(
112
- Initialize Murano project using specific Business and Solutions
113
- ).strip, 'murano init --business-id 12345 --product-name myprod --application-name myapp'
107
+ def command_init(cmd)
108
+ cmd.syntax = %(murano init)
109
+ cmd.summary = %(The easy way to start a project)
110
+ cmd.description = INIT_CMD_DESCRIPTION
114
111
 
115
- # Let user specify existing business and/or solution IDs and/or names.
116
- cmd_option_business_pickers(c)
117
- cmd_option_application_pickers(c)
118
- cmd_option_product_pickers(c)
112
+ cmd.example %(
113
+ Initialize Murano project using specific Business and Solutions
114
+ ).strip, 'murano init --business-id 12345 --product-name myprod --application-name myapp'
119
115
 
120
- c.option('--refresh', %(Ignore Business and Solution IDs found in the config))
121
- c.option('--purge', %(Remove Project directories and files, and recreate anew))
122
- c.option('--[no-]sync', %(Pull down existing remote files (generally a good thing) (default: true)))
123
- c.option('--[no-]mkdirs', %(Create default directories))
116
+ # Let user specify existing business and/or solution IDs and/or names.
117
+ cmd_option_business_pickers(cmd)
118
+ cmd_option_application_pickers(cmd)
119
+ cmd_option_product_pickers(cmd)
124
120
 
125
- # This command can be run without a project config.
126
- c.project_not_required = true
127
- # This command should not walk up the directory tree
128
- # looking for a .murano/config project config file.
129
- c.restrict_to_cur_dir = true
130
- # Ask for user password if not found.
131
- c.prompt_if_logged_off = true
121
+ cmd.option('--refresh', %(Ignore Business and Solution IDs found in the config))
122
+ cmd.option('--purge', %(Remove Project directories and files, and recreate anew))
123
+ cmd.option('--[no-]sync', %(Pull down existing remote files (generally a good thing) (default: true)))
124
+ cmd.option('--[no-]mkdirs', %(Create default directories))
132
125
 
133
- c.action do |args, options|
134
- c.verify_arg_count!(args, 1)
135
- options.default(refresh: false, purge: false, sync: true, mkdirs: true)
126
+ # This command can be run without a project config.
127
+ cmd.project_not_required = true
128
+ # This command should not walk up the directory tree
129
+ # looking for a .murano/config project config file.
130
+ cmd.restrict_to_cur_dir = true
131
+ # Ask for user password if not found.
132
+ cmd.prompt_if_logged_off = true
136
133
 
137
- acc = MrMurano::Account.new
138
- validate_dir!(acc, args, options)
134
+ cmd.action do |args, options|
135
+ cmd.verify_arg_count!(args, 1)
136
+ options.default(refresh: false, purge: false, sync: true, mkdirs: true)
139
137
 
140
- puts('')
141
- if $cfg.project_exists
142
- verbage = 'Rebasing'
143
- else
144
- verbage = 'Creating'
145
- end
146
- say("#{verbage} project at #{Rainbow($cfg['location.base'].to_s).underline}")
138
+ acc = MrMurano::Account.new
139
+ validate_dir!(acc, args, options)
147
140
 
148
- puts('')
141
+ puts('')
142
+ if $cfg.project_exists
143
+ verbage = 'Rebasing'
144
+ else
145
+ verbage = 'Creating'
146
+ end
147
+ say("#{verbage} project at #{Rainbow($cfg['location.base'].to_s).underline}")
149
148
 
150
- # Try to import a .Solutionfile.secret.
151
- # NOTE/2017-06-29: .Solutionfile.secret and SolutionFile (see ProjectFile.rb)
152
- # are old MurCLI constructs; here we just try to migrate from the old format
153
- # to the new format (where config goes in .murano/config and there's an
154
- # explicit directory structure; the user cannot specify a different file
155
- # hierarchy).
156
- MrMurano::ConfigMigrate.new.import_secret
157
-
158
- # See if the config already specifies a Business ID. If not, see if the
159
- # config contains a username and password; otherwise, ask for them. With
160
- # a username and password, get the list of businesses from Murano; if
161
- # just one found, use that; if more than one found, ask user which one
162
- # to use; else, if no businesses found, spit out the new-account URL
163
- # and tell the user to use their browser to create a new Business.
164
- unless $cfg['user.name'].to_s.empty?
165
- say("Found User #{Rainbow($cfg['user.name']).underline}")
166
149
  puts('')
167
- end
168
150
 
169
- # Find and verify Business by ID (from $cfg) or by name (from --business),
170
- # or ask user which business to use. If user has not logged on, they will
171
- # be asked for their username and/or password first.
172
- biz = business_find_or_ask!(acc, options)
173
- # Save the 'business.id' and 'business.name' to the project config.
174
- # ([lb] guessing biz guaranteed to be not nil, but checking anyway.)
175
- biz.write unless biz.nil?
176
-
177
- # Verify or ask user to create Solutions.
178
- sol_opts = {
179
- create_ok: true,
180
- update_cfg: true,
181
- ignore_cfg: options.refresh,
182
- verbose: true,
183
- }
184
- # Get/Create Application ID
185
- sol_opts[:match_api_id] = options.application_id
186
- sol_opts[:match_name] = options.application_name
187
- sol_opts[:match_fuzzy] = options.application
188
- appl = solution_find_or_create(biz: biz, type: :application, **sol_opts)
189
- # Get/Create Product ID
190
- sol_opts[:match_api_id] = options.product_id
191
- sol_opts[:match_name] = options.product_name
192
- sol_opts[:match_fuzzy] = options.product
193
- prod = solution_find_or_create(biz: biz, type: :product, **sol_opts)
194
-
195
- # Automatically link solutions.
196
- link_opts = { verbose: true }
197
- link_solutions(appl, prod, link_opts)
198
-
199
- # If no ProjectFile, then write a ProjectFile.
200
- write_project_file
201
-
202
- if options.mkdirs
203
- # Make the directory structure.
204
- make_directories(purge: options.purge)
205
-
206
- # For new solutions, Murano creates a few empty and example event handlers.
207
- # For existing solutions, the user might already have created some files.
208
- # Grab them now.
209
- syncdown_new_and_existing if options.sync
210
- end
151
+ # Try to import a .Solutionfile.secret.
152
+ # NOTE/2017-06-29: .Solutionfile.secret and SolutionFile (see ProjectFile.rb)
153
+ # are old MurCLI constructs; here we just try to migrate from the old format
154
+ # to the new format (where config goes in .murano/config and there's an
155
+ # explicit directory structure; the user cannot specify a different file
156
+ # hierarchy).
157
+ MrMurano::ConfigMigrate.new.import_secret
158
+
159
+ # See if the config already specifies a Business ID. If not, see if the
160
+ # config contains a username and password; otherwise, ask for them. With
161
+ # a username and password, get the list of businesses from Murano; if
162
+ # just one found, use that; if more than one found, ask user which one
163
+ # to use; else, if no businesses found, spit out the new-account URL
164
+ # and tell the user to use their browser to create a new Business.
165
+ unless $cfg['user.name'].to_s.empty?
166
+ say("Found User #{Rainbow($cfg['user.name']).underline}")
167
+ puts('')
168
+ end
169
+
170
+ # Find and verify Business by ID (from $cfg) or by name (from --business),
171
+ # or ask user which business to use. If user has not logged on, they will
172
+ # be asked for their username and/or password first.
173
+ biz = business_find_or_ask!(acc, options)
174
+ # Save the 'business.id' and 'business.name' to the project config.
175
+ # ([lb] guessing biz guaranteed to be not nil, but checking anyway.)
176
+ biz.write unless biz.nil?
177
+
178
+ # Verify or ask user to create Solutions.
179
+ sol_opts = {
180
+ create_ok: true,
181
+ update_cfg: true,
182
+ ignore_cfg: options.refresh,
183
+ verbose: true,
184
+ }
185
+ # Get/Create Application ID
186
+ sol_opts[:match_api_id] = options.application_id
187
+ sol_opts[:match_name] = options.application_name
188
+ sol_opts[:match_fuzzy] = options.application
189
+ appl = solution_find_or_create(biz: biz, type: :application, **sol_opts)
190
+ # Get/Create Product ID
191
+ sol_opts[:match_api_id] = options.product_id
192
+ sol_opts[:match_name] = options.product_name
193
+ sol_opts[:match_fuzzy] = options.product
194
+ prod = solution_find_or_create(biz: biz, type: :product, **sol_opts)
195
+
196
+ # Automatically link solutions.
197
+ unless appl.nil? || prod.nil?
198
+ link_opts = { verbose: true }
199
+ link_solutions(appl, prod, link_opts)
200
+ end
201
+
202
+ # If no ProjectFile, then write a ProjectFile.
203
+ write_project_file
204
+
205
+ if options.mkdirs
206
+ # Make the directory structure.
207
+ make_directories(purge: options.purge)
208
+
209
+ # For new solutions, Murano creates a few empty and example event handlers.
210
+ # For existing solutions, the user might already have created some files.
211
+ # Grab them now.
212
+ syncdown_new_and_existing if options.sync
213
+ end
211
214
 
212
- blather_success
215
+ blather_success
216
+ end
213
217
  end
214
218
 
215
219
  def highlight_id(id)
@@ -397,19 +401,29 @@ command :init do |c|
397
401
  important_ids = %w[business application product].freeze
398
402
  importantest_width = important_ids.map do |id_name|
399
403
  cfg_key = id_name + '.id'
404
+ # If the user did not set up an application or product, it's ID is nil.
405
+ next 0 if $cfg[cfg_key].nil?
400
406
  $cfg[cfg_key].length + id_postfix.length
401
407
  end.max # Max the map; get the length of the longest ID.
402
408
  important_ids.each do |id_name|
403
409
  # cfg_key is, e.g., 'business.id', 'product.id', 'application.id'
404
410
  cfg_key = id_name + '.id'
405
- next if $cfg[cfg_key].nil?
411
+ identifier = $cfg[cfg_key] || '<n/a>'
406
412
  #say "#{id_name.capitalize} ID: #{highlight_id($cfg[cfg_key])}"
407
413
  # Right-aligned:
408
414
  tmpl = format('%%%ds: %%s', importantest_width)
409
415
  # Left-aligned:
410
416
  #tmpl = format('%%-%ds: %%s', importantest_width)
411
- say(format(tmpl, id_name.capitalize + id_postfix, highlight_id($cfg[cfg_key])))
417
+ say(format(tmpl, id_name.capitalize + id_postfix, highlight_id(identifier)))
412
418
  end
413
419
  puts('')
414
420
  end
415
421
  end
422
+
423
+ def wire_cmd_init
424
+ init_cmd = InitCmd.new
425
+ command(:init) { |cmd| init_cmd.command_init(cmd) }
426
+ end
427
+
428
+ wire_cmd_init
429
+
@@ -7,7 +7,7 @@
7
7
 
8
8
  require 'MrMurano/Keystore'
9
9
  require 'MrMurano/ReCommander'
10
- require 'MrMurano/Solution-ServiceConfig'
10
+ require 'MrMurano/SubCmdGroupContext'
11
11
 
12
12
  command :keystore do |c|
13
13
  c.syntax = %(murano keystore)
@@ -14,6 +14,7 @@ require 'MrMurano/verbosing'
14
14
  require 'MrMurano/Logs'
15
15
  require 'MrMurano/ReCommander'
16
16
  require 'MrMurano/Solution'
17
+ require 'MrMurano/commands/solution_picker'
17
18
 
18
19
  # Because Ruby 2.0 does not support quoted keys, e.g., { '$eq': 'value' }.
19
20
  # rubocop:disable Style/HashSyntax
@@ -397,7 +398,7 @@ Use a "#{INCLUDE_INDICATOR}" or "#{EXCLUDE_INDICATOR}" prefix to include or excl
397
398
  n_formatting += 1 if @options.pp
398
399
  return unless n_formatting > 1
399
400
  format_options = '--raw, --message-only, --one-line, --json, --yaml, or --pp'
400
- warn "Try using just one of #{format_options}, but not two or more."
401
+ warning "Try using just one of #{format_options}, but not two or more."
401
402
  exit 1
402
403
  end
403
404
 
@@ -75,11 +75,8 @@ Queries can include $# escapes that are filled from the --param option.
75
75
  io = nil
76
76
  io = File.open(options.output, 'w') if options.output
77
77
 
78
- pg.outf(ret, io) do |dd, ios|
79
- dd = dd[:result]
80
- # Look for date cells and pretty them. (a Hash with specific fields)
81
- # All others, call to_s
82
- rows = dd[:rows].map do |row|
78
+ def pretty_res(pg, res, ios)
79
+ rows = res[:rows].map do |row|
83
80
  row.map do |cell|
84
81
  if cell.is_a?(Hash) && cell.keys.sort == %i[day hour min month sec usec year]
85
82
  t = Time.gm(
@@ -93,12 +90,22 @@ Queries can include $# escapes that are filled from the --param option.
93
90
  end
94
91
  pg.tabularize(
95
92
  {
96
- headers: dd[:columns],
93
+ headers: res[:columns],
97
94
  rows: rows,
98
95
  },
99
96
  ios
100
97
  )
101
98
  end
99
+ pg.outf(ret, io) do |dd, ios|
100
+ dd = dd[:result]
101
+ # Look for date cells and pretty them. (a Hash with specific fields)
102
+ # All others, call to_s
103
+ if dd.is_a? Array
104
+ dd.each { |d| pretty_res(pg, d, ios) }
105
+ else
106
+ pretty_res(pg, dd, ios)
107
+ end
108
+ end
102
109
  io.close unless io.nil?
103
110
  end
104
111
  end
@@ -149,7 +156,10 @@ extra table in your database. (__murano_cli__.migrate_version)
149
156
  CREATE TABLE IF NOT EXISTS __murano_cli__.migrate_version (version integer);
150
157
  SELECT version FROM __murano_cli__.migrate_version ORDER BY version DESC;
151
158
  ).gsub(/^\s+/, '')
152
- unless ret[:error].nil?
159
+ if ret.nil?
160
+ pg.error 'Unknown Postgresql failure determining version'
161
+ exit 1
162
+ elsif !ret[:error].nil?
153
163
  pp ret
154
164
  exit 1
155
165
  end