holistics 0.0.6 → 0.0.7
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/lib/holistics/api_client.rb +133 -131
- data/lib/holistics/custom_logger.rb +31 -0
- data/lib/holistics/version.rb +1 -1
- data/lib/holistics.rb +15 -2
- data/lib/{holistics/tabular_formatter.rb → tabular_formatter.rb} +1 -2
- data/lib/{holistics/cucumber/vcr.rb → vcr.rb} +0 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61601d17f426d38122402a767f5b4534e6671b50
|
4
|
+
data.tar.gz: 0c533d1dcb1f12c193ebc79fb168db3524a2fde6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b77f45439562d748fd22fb498e5dc9f130f9d36e18cd67b2bdf05c5a1230e528d6bdba20e4cabd6135d3fe2364f0ac6a9012b8d824ac985ebd8a5827cd0aa6e
|
7
|
+
data.tar.gz: 9ae95aa35c514d7860963d07180d091d3f3b67a75a59e16bff113817e4e231865687accec89143688e7e6f33105a57750eec562d9cb09c5f7eb036735881f97a
|
data/lib/holistics/api_client.rb
CHANGED
@@ -1,169 +1,171 @@
|
|
1
1
|
require 'httparty'
|
2
|
-
require '
|
2
|
+
require 'tabular_formatter'
|
3
3
|
require 'yaml'
|
4
4
|
require 'json'
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
module Holistics
|
7
|
+
class ApiClient
|
8
|
+
SERVER_URL = 'https://secure.holistics.io/'
|
8
9
|
|
9
|
-
|
10
|
-
puts 'Logging in...'
|
11
|
-
response, ok = holistics_authenticate(token)
|
12
|
-
if ok
|
13
|
-
parsed = JSON.parse(response.body)
|
14
|
-
puts 'Authentication successful. Info:'
|
15
|
-
puts "- ID: #{parsed['id']}"
|
16
|
-
puts "- Email: #{parsed['email']}"
|
10
|
+
def initialize
|
17
11
|
|
18
|
-
write_token_to_gconfig(token)
|
19
|
-
else
|
20
|
-
puts 'Error logging in. Please check your token again.'
|
21
12
|
end
|
22
|
-
end
|
23
13
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
14
|
+
def login token
|
15
|
+
puts 'Logging in...'
|
16
|
+
response, ok = holistics_authenticate(token)
|
17
|
+
if ok
|
18
|
+
parsed = JSON.parse(response.body)
|
19
|
+
puts 'Authentication successful. Info:'
|
20
|
+
puts "- ID: #{parsed['id']}"
|
21
|
+
puts "- Email: #{parsed['email']}"
|
29
22
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
23
|
+
write_token_to_gconfig(token)
|
24
|
+
else
|
25
|
+
puts 'Error logging in. Please check your token again.'
|
26
|
+
end
|
27
|
+
end
|
34
28
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
29
|
+
def holistics_authenticate(token)
|
30
|
+
url = api_url_for('users/info.json', token)
|
31
|
+
response = HTTParty.get(url)
|
32
|
+
return response, (response.code == 200)
|
33
|
+
end
|
39
34
|
|
40
|
-
|
35
|
+
def job_show options
|
36
|
+
job_id = options[:job_id]
|
37
|
+
tail_job(job_id)
|
38
|
+
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
def ds_list
|
41
|
+
url = api_url_for('data_sources.json')
|
42
|
+
response = HTTParty.get(url)
|
43
|
+
err_and_exit('Error retrieving list of data sources', response) if response_has_error?(response)
|
45
44
|
|
46
|
-
|
47
|
-
end
|
45
|
+
parsed = JSON.parse(response.body)
|
48
46
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
response = submit_transport_job(params)
|
47
|
+
table = [%w(ID Type Name)]
|
48
|
+
rows = parsed.map { |record| [record['id'], record['dbtype'], record['name']] }
|
49
|
+
table.concat(rows)
|
53
50
|
|
54
|
-
|
51
|
+
puts TabularFormatter.new(table).to_pretty_table
|
52
|
+
end
|
55
53
|
|
56
|
-
|
57
|
-
|
54
|
+
def send_transport(options)
|
55
|
+
puts 'Submitting transport job ...'
|
56
|
+
params = build_submit_params(options)
|
57
|
+
response = submit_transport_job(params)
|
58
58
|
|
59
|
-
|
60
|
-
tail_job(job_id)
|
61
|
-
end
|
59
|
+
err_and_exit("Error submitting transport job", response) if response_has_error?(response)
|
62
60
|
|
63
|
-
def tail_job(job_id)
|
64
|
-
last_ts = ''
|
65
|
-
while true
|
66
|
-
response = fetch_job_status(job_id)
|
67
61
|
parsed = JSON.parse(response.body)
|
68
|
-
|
62
|
+
job_id = parsed['job_id']
|
69
63
|
|
70
|
-
|
71
|
-
|
72
|
-
print_log(log)
|
73
|
-
end
|
74
|
-
last_ts = logs.last['created_at'] if logs.size > 0
|
75
|
-
break unless has_more?(parsed['status'])
|
76
|
-
sleep 1
|
64
|
+
puts "Job submitted. Job ID: #{job_id}."
|
65
|
+
tail_job(job_id)
|
77
66
|
end
|
78
|
-
end
|
79
67
|
|
80
|
-
|
81
|
-
|
82
|
-
|
68
|
+
def tail_job(job_id)
|
69
|
+
last_id = 0
|
70
|
+
while true
|
71
|
+
response = fetch_job_details(job_id, last_id)
|
72
|
+
parsed = JSON.parse(response.body)
|
83
73
|
|
84
|
-
|
85
|
-
%w(running created).include?(status)
|
86
|
-
end
|
74
|
+
logs = parsed['logs']
|
87
75
|
|
88
|
-
|
89
|
-
HTTParty.post(server_url + 'transports/submit.json', body: params.to_json, headers: {'Content-Type' => 'application/json'})
|
90
|
-
end
|
76
|
+
logs.each { |log| print_log(log) }
|
91
77
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
elsif ENV['STAGING']
|
97
|
-
'https://staging.holistics.io'
|
98
|
-
elsif ENV['HOST']
|
99
|
-
ENV['HOST']
|
100
|
-
else
|
101
|
-
SERVER_URL
|
78
|
+
last_id = logs.last['id'] if logs.size > 0
|
79
|
+
break unless parsed['has_more']
|
80
|
+
|
81
|
+
sleep 0.5
|
102
82
|
end
|
103
|
-
|
104
|
-
host
|
105
|
-
end
|
83
|
+
end
|
106
84
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
params
|
111
|
-
end
|
85
|
+
def fetch_job_details(job_id, last_id = 0)
|
86
|
+
HTTParty.get(api_url_for("jobs/#{job_id}.json?last_id=#{last_id}"))
|
87
|
+
end
|
112
88
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
return JSON.parse(File.read(filepath))
|
117
|
-
elsif file_ext == '.yml'
|
118
|
-
return YAML.load(File.read(filepath))
|
119
|
-
else
|
120
|
-
raise StandardError.new 'Invalid config file extension. Please use either JSON or YML'
|
121
|
-
end
|
122
|
-
rescue StandardError => e
|
123
|
-
STDERR.puts "Error parsing transport config file: #{e.message}"
|
124
|
-
exit 1
|
125
|
-
end
|
89
|
+
def submit_transport_job(params)
|
90
|
+
HTTParty.post(server_url + 'transports/submit.json', body: params.to_json, headers: {'Content-Type' => 'application/json'})
|
91
|
+
end
|
126
92
|
|
127
|
-
|
128
|
-
|
129
|
-
|
93
|
+
def server_url
|
94
|
+
host =
|
95
|
+
if ENV['DEV'] || ENV['TEST']
|
96
|
+
'http://localhost:3000'
|
97
|
+
elsif ENV['STAGING']
|
98
|
+
'https://staging.holistics.io'
|
99
|
+
elsif ENV['HOST']
|
100
|
+
ENV['HOST']
|
101
|
+
else
|
102
|
+
SERVER_URL
|
103
|
+
end
|
104
|
+
host += '/' if host[-1] != '/'
|
105
|
+
host
|
106
|
+
end
|
130
107
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
else
|
136
|
-
raise StandardError.new 'Holistics config file not found'
|
108
|
+
def build_submit_params(options)
|
109
|
+
params = options.except(:config_path).merge(_utoken: get_token_from_gconfig)
|
110
|
+
params[:configs] = parse_transport_config(options[:config_path]).to_json if options[:config_path]
|
111
|
+
params
|
137
112
|
end
|
138
|
-
end
|
139
113
|
|
140
|
-
|
141
|
-
|
142
|
-
|
114
|
+
def parse_transport_config(filepath)
|
115
|
+
file_ext = File.extname(filepath).downcase
|
116
|
+
if file_ext == '.json'
|
117
|
+
return JSON.parse(File.read(filepath))
|
118
|
+
elsif file_ext == '.yml'
|
119
|
+
return YAML.load(File.read(filepath))
|
120
|
+
else
|
121
|
+
raise StandardError.new 'Invalid config file extension. Please use either JSON or YML'
|
122
|
+
end
|
123
|
+
rescue StandardError => e
|
124
|
+
STDERR.puts "Error parsing transport config file: #{e.message}"
|
125
|
+
exit 1
|
126
|
+
end
|
143
127
|
|
144
|
-
|
145
|
-
|
146
|
-
|
128
|
+
def authenticated?
|
129
|
+
File.exists?(get_gconfig_filepath)
|
130
|
+
end
|
147
131
|
|
148
|
-
|
149
|
-
|
150
|
-
|
132
|
+
def get_token_from_gconfig
|
133
|
+
if authenticated?
|
134
|
+
string = YAML.load_file(get_gconfig_filepath)
|
135
|
+
string['token']
|
136
|
+
else
|
137
|
+
raise StandardError.new 'Holistics config file not found'
|
138
|
+
end
|
139
|
+
end
|
151
140
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
STDERR.puts response.body
|
156
|
-
exit 1
|
157
|
-
end
|
141
|
+
def get_gconfig_filepath
|
142
|
+
File.expand_path('~/.holistics.yml', __FILE__)
|
143
|
+
end
|
158
144
|
|
159
|
-
|
160
|
-
|
161
|
-
|
145
|
+
def api_url_for(path, token = nil)
|
146
|
+
"#{server_url}#{path}?_utoken=#{token || get_token_from_gconfig}"
|
147
|
+
end
|
162
148
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
end
|
149
|
+
def print_log log
|
150
|
+
ts = Time.parse(log['created_at'])
|
151
|
+
Holistics.logger.log(log['level'], log['message'], timestamp: ts)
|
152
|
+
end
|
168
153
|
|
169
|
-
|
154
|
+
def err_and_exit(message, response)
|
155
|
+
STDERR.puts message
|
156
|
+
STDERR.puts "Error Response Code: #{response.code}"
|
157
|
+
STDERR.puts response.body
|
158
|
+
exit 1
|
159
|
+
end
|
160
|
+
|
161
|
+
def response_has_error?(response)
|
162
|
+
response.code != 200
|
163
|
+
end
|
164
|
+
|
165
|
+
def write_token_to_gconfig(token)
|
166
|
+
file_path = File.join(ENV['HOME'], '.holistics.yml')
|
167
|
+
h = {'token' => token}
|
168
|
+
File.write(file_path, h.to_yaml)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Custom logger class that allows
|
2
|
+
module Holistics
|
3
|
+
class CustomLogger
|
4
|
+
|
5
|
+
def initialize out
|
6
|
+
@out = out
|
7
|
+
end
|
8
|
+
|
9
|
+
def log(level, data, options = {})
|
10
|
+
t = options[:timestamp] || Time.now.utc
|
11
|
+
@out.puts "#{t} - #{level.to_s.upcase.ljust(5)} #{data}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def info data, options = {}
|
15
|
+
log('info', data, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug data, options = {}
|
19
|
+
log('debug', data, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def warn data, options = {}
|
23
|
+
log('warn', data, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def error data, options = {}
|
27
|
+
log('error', data, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/holistics/version.rb
CHANGED
data/lib/holistics.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'holistics/api_client'
|
3
|
-
require '
|
3
|
+
require 'vcr'
|
4
4
|
|
5
|
-
|
5
|
+
module Holistics
|
6
6
|
def self.root
|
7
7
|
Pathname.new(__FILE__).parent.parent
|
8
8
|
end
|
9
|
+
|
10
|
+
def logger
|
11
|
+
@logger ||= CustomLogger.new(STDOUT)
|
12
|
+
end
|
13
|
+
|
9
14
|
end
|
10
15
|
|
11
16
|
# Right now we can't do `holistics ds:list`
|
@@ -13,6 +18,14 @@ end
|
|
13
18
|
# Either we use other libs, or figure out an elegant way to do it without
|
14
19
|
|
15
20
|
class HolisticsRunner < Thor
|
21
|
+
|
22
|
+
method_option :verbosity, aliases: '-v', type: :numeric, default: 2, required: false,
|
23
|
+
desc: 'Set the logging verbosity. Values range from 1 (log everything) to 6 (log nothing)'
|
24
|
+
|
25
|
+
def initialize(args=[], options={}, config={})
|
26
|
+
super(args, options, config)
|
27
|
+
end
|
28
|
+
|
16
29
|
desc 'login [auth_token]', 'Perform authentication'
|
17
30
|
|
18
31
|
def login token
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'csv'
|
2
2
|
require 'active_support/all'
|
3
3
|
|
4
|
-
|
5
4
|
class TabularFormatter
|
6
5
|
|
7
6
|
def initialize input_data, options = {}
|
@@ -39,7 +38,7 @@ class TabularFormatter
|
|
39
38
|
str << "-#{'-' * l}-+"
|
40
39
|
end.chomp!("+")
|
41
40
|
divider = divider[1..-1]
|
42
|
-
output.insert(1,divider)
|
41
|
+
output.insert(1, divider)
|
43
42
|
output.join("\n").concat("\n")
|
44
43
|
end
|
45
44
|
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: holistics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thanh Dinh Khac
|
@@ -80,9 +80,10 @@ files:
|
|
80
80
|
- holistics.gemspec
|
81
81
|
- lib/holistics.rb
|
82
82
|
- lib/holistics/api_client.rb
|
83
|
-
- lib/holistics/
|
84
|
-
- lib/holistics/tabular_formatter.rb
|
83
|
+
- lib/holistics/custom_logger.rb
|
85
84
|
- lib/holistics/version.rb
|
85
|
+
- lib/tabular_formatter.rb
|
86
|
+
- lib/vcr.rb
|
86
87
|
homepage: http://rubygems.org/gems/holistics-cli
|
87
88
|
licenses:
|
88
89
|
- GPL
|