envoy-cli 1.0.0rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +95 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/bin/envoy +12 -0
- data/bin/envoy.bak +485 -0
- data/bootstrap/base/.envoyrc +1 -0
- data/bootstrap/base/.jshintrc +91 -0
- data/bootstrap/base/.nvmrc +1 -0
- data/bootstrap/base/config/.gitkeep +0 -0
- data/bootstrap/base/docs/.gitkeep +0 -0
- data/bootstrap/base/gulpfile.js +0 -0
- data/bootstrap/base/i18n/.gitkeep +0 -0
- data/bootstrap/base/index.js +5 -0
- data/bootstrap/base/lib/.gitkeep +0 -0
- data/bootstrap/base/routes/.gitkeep +0 -0
- data/bootstrap/base/views/.gitkeep +0 -0
- data/bootstrap/base/workers/.gitkeep +0 -0
- data/bootstrap/events/generic.json +6 -0
- data/bootstrap/events/host_notification.json +27 -0
- data/bootstrap/events/route.json +6 -0
- data/bootstrap/events/sms_host_notification.json +158 -0
- data/bootstrap/templates/docs/about.md.erb +3 -0
- data/bootstrap/templates/gitignore.erb +8 -0
- data/bootstrap/templates/index.js.erb +5 -0
- data/bootstrap/templates/license.md.erb +1 -0
- data/bootstrap/templates/npmignore.erb +0 -0
- data/bootstrap/templates/package.json +24 -0
- data/bootstrap/templates/readme.md.erb +9 -0
- data/bootstrap/templates/routes/callback.js.erb +10 -0
- data/bootstrap/templates/routes/html.js.erb +9 -0
- data/bootstrap/templates/routes/json.js.erb +9 -0
- data/bootstrap/templates/routes/other.js.erb +9 -0
- data/bootstrap/templates/views/hello.html.erb +91 -0
- data/bootstrap/templates/views/starter.html.erb +10 -0
- data/bootstrap/templates/worker.js.erb +10 -0
- data/envoy-cli.gemspec +29 -0
- data/lib/envoy.rb +70 -0
- data/lib/envoy/version.rb +3 -0
- data/lib/inc/commands.rb +74 -0
- data/lib/inc/generator.rb +159 -0
- data/lib/inc/mixins.rb +347 -0
- data/lib/inc/runner.rb +21 -0
- data/lib/tasks/plugin.rb +181 -0
- data/lib/tasks/routes.rb +39 -0
- data/lib/tasks/test.rb +68 -0
- data/lib/tasks/workers.rb +39 -0
- data/readme.md +0 -0
- metadata +276 -0
data/envoy-cli.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
|
2
|
+
require 'envoy/version'
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'envoy-cli'
|
5
|
+
spec.version = Envoy::VERSION
|
6
|
+
spec.authors = ["David Boskovic"]
|
7
|
+
spec.email = ["david@envoy.com"]
|
8
|
+
|
9
|
+
spec.date = '2016-03-18'
|
10
|
+
spec.summary = 'Envoy platform command line interface.'
|
11
|
+
spec.description = 'The Envoy command line interface handles almost all the heavy lifting for you during '\
|
12
|
+
'development of platform plugins.'
|
13
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
14
|
+
spec.homepage = 'http://rubygemspec.org/gems/envoy-cli'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.add_runtime_dependency "thor", "~> 0.19", ">= 0.19.1"
|
18
|
+
spec.add_runtime_dependency "terminal-table", "~> 1.5", ">= 1.5.2"
|
19
|
+
spec.add_runtime_dependency "colorize", "~> 0.7", ">= 0.7.7"
|
20
|
+
spec.add_runtime_dependency "unirest", "~> 1.1", ">= 1.1.2"
|
21
|
+
spec.add_runtime_dependency "parseconfig", "~> 1.0", ">= 1.0.8"
|
22
|
+
spec.add_runtime_dependency "coderay", "~> 1.1", ">= 1.1.1"
|
23
|
+
spec.add_runtime_dependency "launchy", "~> 2.4", ">= 2.4.3"
|
24
|
+
spec.add_runtime_dependency "tty", "~> 0.5", ">= 0.5.0"
|
25
|
+
spec.add_runtime_dependency "net-http-uploadprogress", "~> 2.0", ">= 2.0.0"
|
26
|
+
|
27
|
+
spec.bindir = 'bin'
|
28
|
+
spec.executables << 'envoy'
|
29
|
+
end
|
data/lib/envoy.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'envoy/version'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
require 'inc/runner'
|
5
|
+
require 'inc/commands'
|
6
|
+
require 'inc/mixins'
|
7
|
+
require 'inc/generator'
|
8
|
+
|
9
|
+
require 'unirest'
|
10
|
+
require 'colorize'
|
11
|
+
|
12
|
+
project_root = File.dirname(File.absolute_path(__FILE__))
|
13
|
+
Dir.glob("#{project_root}/tasks/**/*.rb", &method(:require))
|
14
|
+
|
15
|
+
module Envoy
|
16
|
+
class Main < Commands
|
17
|
+
include Mixins
|
18
|
+
|
19
|
+
namespace :envoy
|
20
|
+
|
21
|
+
# Authenticates the user by storing their auth_token in ~/.envoy-cfg
|
22
|
+
# @param --local [String] will use localhost:3000 as the API url
|
23
|
+
# @param --path [String] can be used to override the endpoint for this profile
|
24
|
+
# @param --profile NAME [String] will save the login information for that profile, in order
|
25
|
+
# to use that info, you must specify the same profile name on other requests
|
26
|
+
|
27
|
+
desc "login", "Login to your account"
|
28
|
+
option :path, type: :string
|
29
|
+
|
30
|
+
def login
|
31
|
+
# collect login information
|
32
|
+
email = prompt.ask "Email:"
|
33
|
+
password = prompt.mask "Password:"
|
34
|
+
|
35
|
+
# attempt to obtain a working token
|
36
|
+
res = post('Authenticating', base_url!('oauth/token'), {
|
37
|
+
grant_type: 'password',
|
38
|
+
username: email,
|
39
|
+
password: password
|
40
|
+
})
|
41
|
+
|
42
|
+
# make sure the user has a developer account
|
43
|
+
post('Fetching developer profile', base_url!('./platform/developers'), {
|
44
|
+
access_token: res['access_token']
|
45
|
+
})
|
46
|
+
|
47
|
+
# save user to config
|
48
|
+
if options.profile && !config.groups.include?(options.profile)
|
49
|
+
config.groups.push options.profile
|
50
|
+
end
|
51
|
+
|
52
|
+
# setup data to save
|
53
|
+
conf = {
|
54
|
+
'email' => email,
|
55
|
+
'access_token' => res['access_token']
|
56
|
+
}
|
57
|
+
conf['local'] = true if options.local
|
58
|
+
conf['api_path'] = options.path if options.path
|
59
|
+
|
60
|
+
config.params[profile(options)] = conf
|
61
|
+
|
62
|
+
write_config!
|
63
|
+
|
64
|
+
say_status "Success", "You are now logged in.", :green
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Runner.setup Envoy
|
70
|
+
Runner.start
|
data/lib/inc/commands.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
|
2
|
+
require 'thor'
|
3
|
+
class Commands < Thor
|
4
|
+
include Thor::Actions
|
5
|
+
|
6
|
+
class_option :profile, type: :string
|
7
|
+
class_option :local, type: :boolean
|
8
|
+
class_option :debug, type: :boolean
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def source_root
|
12
|
+
File.expand_path('../../bootstrap', File.dirname(__FILE__))
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup(mod)
|
16
|
+
@mod = mod
|
17
|
+
end
|
18
|
+
|
19
|
+
# Override Thor#help so it can give information about any class and any method.
|
20
|
+
#
|
21
|
+
def help(shell, subcommand = false)
|
22
|
+
list = printable_commands(true, subcommand)
|
23
|
+
# puts Thor::Base.subclasses
|
24
|
+
thor_classes_in(@mod).each do |klass|
|
25
|
+
# puts klass.name
|
26
|
+
list += klass.printable_commands(false)
|
27
|
+
end
|
28
|
+
list.map! do |x|
|
29
|
+
x[0].sub!(basenamespace, '')
|
30
|
+
x
|
31
|
+
end
|
32
|
+
list.sort! do |a, b|
|
33
|
+
if a[0].include?(':') == false && b[0].include?(':') == true
|
34
|
+
out = -1
|
35
|
+
elsif a[0].include?(':') == true && b[0].include?(':') == false
|
36
|
+
out = +1
|
37
|
+
else
|
38
|
+
out = a[0] <=> b[0]
|
39
|
+
end
|
40
|
+
out
|
41
|
+
end
|
42
|
+
|
43
|
+
if defined?(@package_name) && @package_name
|
44
|
+
shell.say "#{@package_name} commands:"
|
45
|
+
else
|
46
|
+
shell.say "Commands:"
|
47
|
+
end
|
48
|
+
|
49
|
+
shell.print_table(list, indent: 2, truncate: true)
|
50
|
+
shell.say
|
51
|
+
class_options_help(shell)
|
52
|
+
end
|
53
|
+
|
54
|
+
def thor_classes_in(klass)
|
55
|
+
stringfied_constants = klass.constants.map &:to_s
|
56
|
+
out = Thor::Base.subclasses.select do |subclass|
|
57
|
+
next unless subclass.name
|
58
|
+
!stringfied_constants.select do |const|
|
59
|
+
subclass.name.gsub("#{klass.name}::", "").start_with?(const)
|
60
|
+
end.empty?
|
61
|
+
end
|
62
|
+
# puts out.inspect
|
63
|
+
out
|
64
|
+
end
|
65
|
+
|
66
|
+
def basenamespace
|
67
|
+
"#{basename}:"
|
68
|
+
end
|
69
|
+
|
70
|
+
def banner(command, _namespace = nil, subcommand = false)
|
71
|
+
"#{basename} #{command.formatted_usage(self, $thor_runner, subcommand).sub!(basenamespace, '')}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
module Envoy
|
3
|
+
module Generator
|
4
|
+
def setup_directories
|
5
|
+
directory 'base', '.'
|
6
|
+
end
|
7
|
+
|
8
|
+
def setup_config
|
9
|
+
create_file 'config/default.json' do
|
10
|
+
JSON.pretty_generate({
|
11
|
+
'permissions' => nil,
|
12
|
+
'installable_on' => ['location'],
|
13
|
+
'oauth2' => {},
|
14
|
+
'schema' => {},
|
15
|
+
'setup' => [],
|
16
|
+
'routes' => [],
|
17
|
+
'jobs_handled' => {}
|
18
|
+
})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def setup_docs
|
23
|
+
template 'templates/docs/about.md.erb', 'docs/about.md'
|
24
|
+
end
|
25
|
+
|
26
|
+
def setup_i18n
|
27
|
+
create_file 'i18n/en.yaml' do
|
28
|
+
{
|
29
|
+
'welcome' => 'Welcome'
|
30
|
+
}.to_yaml
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_route(name, cfg = {})
|
35
|
+
@route_name = name
|
36
|
+
cfg[:type] ||= prompt.select("Choose route type:", ["html", "json", "callback", "other"])
|
37
|
+
template "templates/routes/#{cfg[:type]}.js.erb", "routes/#{name}.js"
|
38
|
+
if cfg[:type] == 'html'
|
39
|
+
cfg[:view] ||= 'starter'
|
40
|
+
template "templates/views/#{cfg[:view]}.html.erb", "views/#{name}.html"
|
41
|
+
end
|
42
|
+
# get profiles, if more than one show select with default
|
43
|
+
profiles = Dir.entries("#{destination_root}/config")
|
44
|
+
.select { |file| file.end_with? '.json' }
|
45
|
+
.map { |file| file.chomp('.json') }
|
46
|
+
if profiles.length > 1
|
47
|
+
profiles = prompt.multi_select("Select profiles to add route to:", profiles)
|
48
|
+
end
|
49
|
+
profiles.each do |profile|
|
50
|
+
data = read_data("config/#{profile}.json")
|
51
|
+
index = data['routes'].index { |x| x['handler'] == name }
|
52
|
+
route_data = {
|
53
|
+
"path" => name,
|
54
|
+
"handler" => name
|
55
|
+
}
|
56
|
+
if index
|
57
|
+
data['routes'][index] = route_data
|
58
|
+
else
|
59
|
+
data['routes'].push route_data
|
60
|
+
end
|
61
|
+
write_data("config/#{profile}.json", data)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def teardown_route(name)
|
66
|
+
profiles = Dir.entries("#{destination_root}/config")
|
67
|
+
.select { |file| file.end_with? '.json' }
|
68
|
+
.map { |file| file.chomp('.json') }
|
69
|
+
if File.exist? "#{destination_root}/routes/#{name}.js"
|
70
|
+
remove_file "routes/#{name}.js"
|
71
|
+
else
|
72
|
+
say_status :info, "No route handler found for #{name}", :yellow
|
73
|
+
end
|
74
|
+
if File.exist? "#{destination_root}/views/#{name}.html"
|
75
|
+
remove_file "views/#{name}.html"
|
76
|
+
end
|
77
|
+
profiles.each do |profile|
|
78
|
+
data = read_data("config/#{profile}.json")
|
79
|
+
index = data['routes'].index { |x| x['handler'] == name }
|
80
|
+
if index
|
81
|
+
data['routes'].delete_at index
|
82
|
+
write_data("config/#{profile}.json", data)
|
83
|
+
else
|
84
|
+
say_status :info, "Route not in profile: #{profile}", :yellow
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_profiles(choose = true)
|
90
|
+
profiles = Dir.entries("#{destination_root}/config")
|
91
|
+
.select { |file| file.end_with? '.json' }
|
92
|
+
.map { |file| file.chomp('.json') }
|
93
|
+
if choose && profiles.length > 1
|
94
|
+
profiles = prompt.multi_select("Select profiles to add configuration to:", profiles)
|
95
|
+
end
|
96
|
+
profiles
|
97
|
+
end
|
98
|
+
|
99
|
+
def setup_worker(name)
|
100
|
+
@job_name = name
|
101
|
+
template "templates/worker.js.erb", "workers/#{name}.js"
|
102
|
+
profiles = get_profiles
|
103
|
+
profiles.each do |profile|
|
104
|
+
data = read_data("config/#{profile}.json")
|
105
|
+
unless data['jobs_handled'][name]
|
106
|
+
data['jobs_handled'][name] = {}
|
107
|
+
end
|
108
|
+
write_data("config/#{profile}.json", data)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def teardown_worker(name)
|
113
|
+
profiles = Dir.entries("#{destination_root}/config")
|
114
|
+
.select { |file| file.end_with? '.json' }
|
115
|
+
.map { |file| file.chomp('.json') }
|
116
|
+
if File.exist? "#{destination_root}/workers/#{name}.js"
|
117
|
+
remove_file "workers/#{name}.js"
|
118
|
+
else
|
119
|
+
say_status :info, "No worker found for #{name}", :yellow
|
120
|
+
end
|
121
|
+
profiles.each do |profile|
|
122
|
+
data = read_data("config/#{profile}.json")
|
123
|
+
if data['jobs_handled'][name]
|
124
|
+
data['jobs_handled'].delete name
|
125
|
+
write_data("config/#{profile}.json", data)
|
126
|
+
else
|
127
|
+
say_status :info, "Worker not in profile: #{profile}", :yellow
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def setup_license
|
133
|
+
template 'templates/license.md.erb', 'license.md'
|
134
|
+
end
|
135
|
+
|
136
|
+
def setup_dotfiles
|
137
|
+
template 'templates/gitignore.erb', '.gitignore'
|
138
|
+
template 'templates/npmignore.erb', '.npmignore'
|
139
|
+
end
|
140
|
+
|
141
|
+
def setup_npm
|
142
|
+
copy_file 'templates/package.json', 'package.json', force: true
|
143
|
+
data = read_data 'package.json'
|
144
|
+
data['name'] = @key
|
145
|
+
data['description'] = @description
|
146
|
+
data['version'] = @version
|
147
|
+
write_data 'package.json', data
|
148
|
+
end
|
149
|
+
|
150
|
+
def setup_readme
|
151
|
+
template 'templates/readme.md.erb', 'readme.md'
|
152
|
+
end
|
153
|
+
|
154
|
+
def setup_tests
|
155
|
+
say_status '@todo', 'bootstrap tests', :yellow
|
156
|
+
# template 'templates/tests/readme.md.erb', 'readme.md'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/lib/inc/mixins.rb
ADDED
@@ -0,0 +1,347 @@
|
|
1
|
+
require 'tty-prompt'
|
2
|
+
require 'parseconfig'
|
3
|
+
require 'json'
|
4
|
+
require 'coderay'
|
5
|
+
require 'unirest'
|
6
|
+
require 'yaml'
|
7
|
+
require "stringio"
|
8
|
+
|
9
|
+
module Envoy
|
10
|
+
module Mixins
|
11
|
+
def post!(path, body = {}, headers = {})
|
12
|
+
debug('Start', "POST #{base_url(path)}")
|
13
|
+
debug('Request', CodeRay.scan(JSON.pretty_generate(body.is_a?(Hash) && body || JSON.parse(body)), :json).terminal)
|
14
|
+
res = Unirest.post(base_url(path), parameters: body, headers: headers)
|
15
|
+
debug("End", res.code.to_s)
|
16
|
+
if res.body.instance_of?(Hash)
|
17
|
+
debug("Body", CodeRay.scan(JSON.pretty_generate(res.body), :json).terminal)
|
18
|
+
else
|
19
|
+
debug("Body", res.body.to_s)
|
20
|
+
end
|
21
|
+
res
|
22
|
+
rescue => e
|
23
|
+
# puts e.message
|
24
|
+
error(e.message)
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
def post(info, *args)
|
29
|
+
spin("Network: #{info}")
|
30
|
+
res = post!(*args)
|
31
|
+
if res.code.between?(200, 299)
|
32
|
+
spin_success
|
33
|
+
else
|
34
|
+
handle_errors(res)
|
35
|
+
end
|
36
|
+
res.body
|
37
|
+
end
|
38
|
+
|
39
|
+
def jsonapi_post(info, path, body = {}, headers = {})
|
40
|
+
headers[:'Content-Type'] = 'application/json'
|
41
|
+
headers[:Authorization] = "Bearer #{config[profile]['access_token']}"
|
42
|
+
post(info, path, { data: body }.to_json, headers)
|
43
|
+
end
|
44
|
+
|
45
|
+
def error(msg)
|
46
|
+
if spinner
|
47
|
+
spin_error msg
|
48
|
+
else
|
49
|
+
say_status 'Error', msg, :red
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle_errors(res)
|
54
|
+
if res.body.instance_of?(Hash) && (res.body['errors'].nil? || res.body['errors'].empty?)
|
55
|
+
if res.body.dig('meta', 'message')
|
56
|
+
error(res.body.dig('meta', 'message'))
|
57
|
+
elsif res.body.dig('error_description')
|
58
|
+
error(res.body.dig('error_description'))
|
59
|
+
else
|
60
|
+
error('Unkown error occured')
|
61
|
+
say CodeRay.scan(JSON.pretty_generate(res.body), :json).terminal
|
62
|
+
end
|
63
|
+
exit
|
64
|
+
elsif res.body.instance_of? String
|
65
|
+
error 'Unkown error occured'
|
66
|
+
if agree("View full response body? (y/n)")
|
67
|
+
ask_editor res.body
|
68
|
+
end
|
69
|
+
elsif res.body.instance_of?(Hash)
|
70
|
+
res.body['errors'].each do |err|
|
71
|
+
error err['detail']
|
72
|
+
end
|
73
|
+
else
|
74
|
+
error 'Unkown error occured'
|
75
|
+
say res.body
|
76
|
+
end
|
77
|
+
spin_error
|
78
|
+
exit
|
79
|
+
end
|
80
|
+
|
81
|
+
def base_url!(path)
|
82
|
+
base_url(path, true)
|
83
|
+
end
|
84
|
+
|
85
|
+
def base_url(path, ignore_profile = false)
|
86
|
+
return path if path.start_with?('http://', 'https://')
|
87
|
+
local = false
|
88
|
+
cfg = config[profile]
|
89
|
+
if !ignore_profile && cfg['local']
|
90
|
+
local = true
|
91
|
+
end
|
92
|
+
if options.local
|
93
|
+
local = true
|
94
|
+
end
|
95
|
+
if local
|
96
|
+
if cfg && cfg['api_path_local']
|
97
|
+
base = cfg['api_path_local']
|
98
|
+
else
|
99
|
+
base = 'http://localhost:3000'
|
100
|
+
end
|
101
|
+
elsif ignore_profile && options.path
|
102
|
+
base = options.path
|
103
|
+
elsif cfg && cfg['api_path']
|
104
|
+
base = cfg['api_path']
|
105
|
+
else
|
106
|
+
base = 'https://app.envoy.com'
|
107
|
+
end
|
108
|
+
if path.start_with?('./')
|
109
|
+
path = 'api/v2/' + path[2..-1]
|
110
|
+
end
|
111
|
+
if path.start_with?('/')
|
112
|
+
path = path[1..-1]
|
113
|
+
end
|
114
|
+
if options.trace
|
115
|
+
debug 'URL', "#{base}/#{path}"
|
116
|
+
end
|
117
|
+
"#{base}/#{path}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def debug(df, text, type = nil)
|
121
|
+
return unless options.trace || options.debug
|
122
|
+
say_status df, text, type
|
123
|
+
end
|
124
|
+
|
125
|
+
def debug_val(val, label)
|
126
|
+
debug label, val
|
127
|
+
val
|
128
|
+
end
|
129
|
+
|
130
|
+
def plugin_uuid
|
131
|
+
uuid = local_config["ENVOY_#{profile.upcase}_PLUGIN_UUID"]
|
132
|
+
unless uuid
|
133
|
+
error "No ENVOY_#{profile.upcase}_PLUGIN_UUID configuration"
|
134
|
+
exit
|
135
|
+
end
|
136
|
+
uuid
|
137
|
+
end
|
138
|
+
|
139
|
+
def profile(_ = false)
|
140
|
+
return debug_val(options.profile, 'Profile') if options.profile
|
141
|
+
cf = local_config
|
142
|
+
return debug_val(cf['ENVOY_PROFILE'], 'Profile') if cf['ENVOY_PROFILE']
|
143
|
+
debug_val('default', 'Profile')
|
144
|
+
end
|
145
|
+
|
146
|
+
def manifest
|
147
|
+
@manifest ||= JSON.parse(File.read(manifest_file)) || {}
|
148
|
+
end
|
149
|
+
|
150
|
+
def manifest_file(_ = false)
|
151
|
+
file = Dir.pwd + '/config/' + profile.downcase + '.json'
|
152
|
+
unless File.exist? file
|
153
|
+
file = Dir.pwd + '/config/default.json'
|
154
|
+
unless File.exist? file
|
155
|
+
error "Must have config/default.json or config/" + profile.downcase + '.json'
|
156
|
+
exit
|
157
|
+
end
|
158
|
+
end
|
159
|
+
debug_val file, 'Manifest'
|
160
|
+
end
|
161
|
+
|
162
|
+
def local_config
|
163
|
+
return @local_config if @local_config
|
164
|
+
unless File.exist? Dir.pwd + '/.envoyrc'
|
165
|
+
FileUtils.touch(Dir.pwd + '/.envoyrc')
|
166
|
+
end
|
167
|
+
@local_config = ParseConfig.new Dir.pwd + '/.envoyrc'
|
168
|
+
end
|
169
|
+
|
170
|
+
def print_event(event)
|
171
|
+
say "------------------------------------------------------------------------"
|
172
|
+
data = event['attributes']
|
173
|
+
say "Event UUID => #{event['id']}".green
|
174
|
+
say "Timestamp =>".yellow + " #{data['created-at']}"
|
175
|
+
say "Task Time =>".yellow + " #{data['task-time']}ms"
|
176
|
+
say "Execution Time =>".yellow + " #{data['process-time']}ms"
|
177
|
+
say "\n"
|
178
|
+
say "REQUEST META"
|
179
|
+
req_h = JSON.pretty_generate Envoy.min_json(data['request-meta'] || {})
|
180
|
+
say CodeRay.scan(req_h, :json).terminal(line_numbers: :table)
|
181
|
+
say "\n"
|
182
|
+
say "REQUEST BODY"
|
183
|
+
req_h = JSON.pretty_generate Envoy.min_json(data['request-body'] || {})
|
184
|
+
say CodeRay.scan(req_h, :json).terminal(line_numbers: :table)
|
185
|
+
say "\n"
|
186
|
+
say "REPONSE META"
|
187
|
+
req_h = JSON.pretty_generate Envoy.min_json(data['response-meta'] || {})
|
188
|
+
say CodeRay.scan(req_h, :json).terminal(line_numbers: :table)
|
189
|
+
say "\n"
|
190
|
+
say "RESPONSE BODY"
|
191
|
+
req_h = JSON.pretty_generate Envoy.min_json(data['response-body'] || {})
|
192
|
+
say CodeRay.scan(req_h, :json).terminal(line_numbers: :table)
|
193
|
+
say "\n"
|
194
|
+
say "LOG ENTRIES"
|
195
|
+
say data['tail']
|
196
|
+
# say data
|
197
|
+
end
|
198
|
+
|
199
|
+
def prompt
|
200
|
+
@prompt ||= TTY::Prompt.new
|
201
|
+
end
|
202
|
+
|
203
|
+
def config
|
204
|
+
@config ||= config!
|
205
|
+
end
|
206
|
+
|
207
|
+
def write_config!
|
208
|
+
file = File.open(Dir.home + '/.envoy-cfg', 'w')
|
209
|
+
config.write(file)
|
210
|
+
file.close
|
211
|
+
end
|
212
|
+
|
213
|
+
def write_local_config!
|
214
|
+
file = File.open(Dir.pwd + '/.envoyrc', 'w')
|
215
|
+
local_config.write(file)
|
216
|
+
file.close
|
217
|
+
end
|
218
|
+
|
219
|
+
def config!
|
220
|
+
if !File.exist?(Dir.home + '/.envoy-cfg')
|
221
|
+
file = File.open(Dir.home + '/.envoy-cfg', 'w')
|
222
|
+
cfg = ParseConfig.new
|
223
|
+
cfg.groups = ['default']
|
224
|
+
cfg.params = { 'default' => { 'access_token' => '', 'email' => '' } }
|
225
|
+
cfg.write(file)
|
226
|
+
file.close
|
227
|
+
else
|
228
|
+
cfg = ParseConfig.new Dir.home + '/.envoy-cfg'
|
229
|
+
end
|
230
|
+
cfg
|
231
|
+
end
|
232
|
+
|
233
|
+
def min_json(h)
|
234
|
+
out = {}
|
235
|
+
h.each do |key, val|
|
236
|
+
if val.instance_of?(String) && val.length > 500
|
237
|
+
val = '[long string, view specific record for full text]'
|
238
|
+
end
|
239
|
+
if val.instance_of?(Hash) && val.length > 20
|
240
|
+
if val['id']
|
241
|
+
out[key] = { id: val['id'], "[#{val.length} keys]": "..." }
|
242
|
+
else
|
243
|
+
out[key] = "{...#{val.length} keys}"
|
244
|
+
end
|
245
|
+
elsif val.instance_of?(Hash)
|
246
|
+
out[key] = min_json val
|
247
|
+
else
|
248
|
+
out[key] = val
|
249
|
+
end
|
250
|
+
end
|
251
|
+
out
|
252
|
+
end
|
253
|
+
|
254
|
+
attr_reader :spinner
|
255
|
+
|
256
|
+
def spin(task)
|
257
|
+
return if options.debug
|
258
|
+
if @spinner
|
259
|
+
@spinner.stop
|
260
|
+
end
|
261
|
+
spinner = TTY::Spinner.new(":spinner #{task}...", format: :spin_2, interval: 10)
|
262
|
+
spinner.start
|
263
|
+
@spinner = spinner
|
264
|
+
end
|
265
|
+
|
266
|
+
def spin_success(msg = nil)
|
267
|
+
return if options.debug
|
268
|
+
return unless @spinner
|
269
|
+
@spinner.success msg ? '> ' + msg : ''
|
270
|
+
@spinner = nil
|
271
|
+
end
|
272
|
+
|
273
|
+
def spin_error(msg = nil)
|
274
|
+
return if options.debug
|
275
|
+
return unless @spinner
|
276
|
+
@spinner.error msg ? '> ' + msg : ''
|
277
|
+
@spinner = nil
|
278
|
+
end
|
279
|
+
|
280
|
+
def read_data(file)
|
281
|
+
rfile = file
|
282
|
+
unless file.start_with? '/'
|
283
|
+
rfile = "#{destination_root}/#{file}"
|
284
|
+
end
|
285
|
+
unless File.exist? rfile
|
286
|
+
return {}
|
287
|
+
end
|
288
|
+
src = File.read rfile
|
289
|
+
return JSON.parse(src) if file.end_with? '.json'
|
290
|
+
return YAML.load(src) if file.end_with? '.yaml'
|
291
|
+
raise "Can only read data from json or yaml files."
|
292
|
+
end
|
293
|
+
|
294
|
+
def write_data(file, data)
|
295
|
+
rfile = file
|
296
|
+
unless file.start_with? '/'
|
297
|
+
rfile = "#{destination_root}/#{file}"
|
298
|
+
end
|
299
|
+
if file.end_with? '.json'
|
300
|
+
out = JSON.pretty_generate(data)
|
301
|
+
elsif file.end_with? '.yaml'
|
302
|
+
out = YAML.dump(data)
|
303
|
+
else
|
304
|
+
raise "Can only write data from json or yaml files."
|
305
|
+
end
|
306
|
+
File.write(rfile, out)
|
307
|
+
say_status :updated, file, :green
|
308
|
+
end
|
309
|
+
|
310
|
+
def indent(depth = 7)
|
311
|
+
start_indent depth
|
312
|
+
yield
|
313
|
+
ensure
|
314
|
+
stop_indent
|
315
|
+
end
|
316
|
+
|
317
|
+
def file_exist?(file)
|
318
|
+
File.exist?(Dir.pwd + '/' + file)
|
319
|
+
end
|
320
|
+
|
321
|
+
def start_indent(depth = 7)
|
322
|
+
$real_stdout = $stdout
|
323
|
+
$stdout_depth = depth
|
324
|
+
$stdout = StringIO.new
|
325
|
+
|
326
|
+
closure = lambda do |*args|
|
327
|
+
args.each do |line|
|
328
|
+
$real_stdout.puts((" " * $stdout_depth) + line)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
$stdout.define_singleton_method(:print, closure)
|
332
|
+
$stdout.define_singleton_method(:puts, closure)
|
333
|
+
end
|
334
|
+
|
335
|
+
def stop_indent
|
336
|
+
$stdout = $real_stdout
|
337
|
+
end
|
338
|
+
|
339
|
+
def pretty_json(body)
|
340
|
+
CodeRay.scan(JSON.pretty_generate(body.is_a?(Hash) && body || JSON.parse(body)), :json).terminal
|
341
|
+
end
|
342
|
+
|
343
|
+
def indent_lines(str, pad = 7)
|
344
|
+
str.each_line.map { |l| (' ' * pad) + l }.join
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|