holistics 0.3.0 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -12
- data/README.md +1 -0
- data/holistics.gemspec +1 -0
- data/lib/holistics.rb +9 -7
- data/lib/holistics/api_client.rb +26 -0
- data/lib/holistics/helpers/job_manager.rb +16 -5
- data/lib/holistics/version.rb +2 -2
- data/lib/import.rb +46 -2
- data/lib/import_chunking.rb +52 -0
- data/lib/transform.rb +29 -0
- data/lib/transport.rb +1 -1
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cab913239d13210e0e3c091b01bc3f9b61cdc78d
|
4
|
+
data.tar.gz: 53b64ba89eb7ffb7134b7b80c15948d291b75efe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89b361bb3763a3c89c59ffe4845d5f3b1625da74292fd6e19164dfb19ee1814566e9c8f246f7d7a753fb56a4e926c7894738099006dad0063f2c4dc1e1753925
|
7
|
+
data.tar.gz: f115d45d5baa6972a7d30d2b9610032aa39b924d1cf97c1ff98101cfc20e9ca8e6b640b5830245c77f39b1a2915e3c424ebdc40d3959eb7d68d90b8646eefa1c
|
data/CHANGELOG.md
CHANGED
@@ -2,24 +2,39 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
4
|
|
5
|
-
## v0.
|
6
|
-
*
|
5
|
+
## v0.3.4
|
6
|
+
* Update retry mechanism for `fetch_job_details`
|
7
7
|
|
8
|
-
## v0.
|
9
|
-
*
|
8
|
+
## v0.3.3
|
9
|
+
* Add "transform list" and "import list" commands
|
10
|
+
* Add "version" command
|
10
11
|
|
11
|
-
## v0.
|
12
|
-
*
|
12
|
+
## v0.3.2
|
13
|
+
* Add 'colorize' to gemspec dependencies
|
13
14
|
|
14
|
-
## v0.
|
15
|
-
*
|
15
|
+
## v0.3.1
|
16
|
+
* Add option to split a custom range Data Import execution into smaller ones
|
16
17
|
|
17
|
-
## v0.
|
18
|
-
*
|
18
|
+
## v0.3.0
|
19
|
+
* Add option to execute Data Imports in custom range mode
|
20
|
+
|
21
|
+
## v0.2.6
|
22
|
+
* Add error handling and retry mechanism for `fetch_job_details`
|
19
23
|
|
20
24
|
## v0.2.5
|
21
25
|
* Support invoking email schedule with `holistics email_schedule trigger <id>`
|
22
26
|
|
23
|
-
## v0.2.
|
24
|
-
*
|
27
|
+
## v0.2.1
|
28
|
+
* Fix dependency error
|
29
|
+
|
30
|
+
## v0.2.0
|
31
|
+
* Support command to import csv into table
|
32
|
+
|
33
|
+
## v0.1.0
|
34
|
+
* Modularized transport and data_sources commands. Rename existing transport command to transport_old.
|
25
35
|
|
36
|
+
## v0.0.12
|
37
|
+
* Support generation of transport config files from CLI: `holistics generate_configs -s <src_ds_id> -d <dest_ds_id> -t <tables> [-o <output>]`
|
38
|
+
|
39
|
+
## v0.0.11
|
40
|
+
* Support invocation of transform from CLI: `holistics transform -j <id>`
|
data/README.md
CHANGED
@@ -8,6 +8,7 @@ Command-line interface to Holistics API
|
|
8
8
|
First, open `version.rb` and increase the version number. Please also update the changelog too.
|
9
9
|
|
10
10
|
Then run the following:
|
11
|
+
$ git tag -a v0.0.3 && git push --tags
|
11
12
|
|
12
13
|
$ gem build holistics.gemspec
|
13
14
|
WARNING: description and summary are identical
|
data/holistics.gemspec
CHANGED
data/lib/holistics.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'vcr_helper'
|
3
3
|
|
4
|
+
require 'holistics/version'
|
4
5
|
require 'holistics/api_client'
|
5
6
|
require 'holistics/custom_logger'
|
6
7
|
require 'holistics/auth_api_client'
|
7
8
|
|
8
9
|
require 'import'
|
10
|
+
require 'import_chunking'
|
9
11
|
require 'transport'
|
12
|
+
require 'transform'
|
10
13
|
require 'data_sources'
|
11
14
|
require 'email_schedule'
|
12
15
|
|
@@ -42,7 +45,9 @@ module Holistics
|
|
42
45
|
end
|
43
46
|
|
44
47
|
register(Holistics::Import, 'import', 'import <command>', "Execute import commands")
|
48
|
+
register(Holistics::ImportChunking, 'import_chunking', 'import_chunking <command>', "Generate import chunks for date range imports")
|
45
49
|
register(Holistics::Transport, 'transport', 'transport <command>', "Execute transport module's commands")
|
50
|
+
register(Holistics::Transform, 'transform', 'transform <command>', "Execute transform module's commands")
|
46
51
|
register(Holistics::DataSources, 'data_sources', 'data_sources <command>', "Execute data_sources module's commands")
|
47
52
|
register(Holistics::EmailSchedule, 'email_schedule', 'email_schedule <command>', "Execute email schedule's commands")
|
48
53
|
|
@@ -69,13 +74,6 @@ module Holistics
|
|
69
74
|
api_client.ds_list
|
70
75
|
end
|
71
76
|
|
72
|
-
method_option :transform_id, aliases: '-j', type: :string, required: true, desc: 'ID of transform job to be executed'
|
73
|
-
desc 'transform', 'Invoke a transform'
|
74
|
-
|
75
|
-
def transform
|
76
|
-
api_client.send_transform(options.dup)
|
77
|
-
end
|
78
|
-
|
79
77
|
method_option :job_id, aliases: '-j', type: :string, required: true, desc: 'Job ID'
|
80
78
|
desc 'job_show', 'Show job log'
|
81
79
|
|
@@ -83,5 +81,9 @@ module Holistics
|
|
83
81
|
api_client.job_show(options.dup)
|
84
82
|
end
|
85
83
|
|
84
|
+
desc 'version', "Show current Holistics gem's version"
|
85
|
+
def version
|
86
|
+
puts Holistics::VERSION
|
87
|
+
end
|
86
88
|
end
|
87
89
|
end
|
data/lib/holistics/api_client.rb
CHANGED
@@ -7,6 +7,8 @@ require 'holistics/helpers/job_manager'
|
|
7
7
|
|
8
8
|
module Holistics
|
9
9
|
class ApiClient
|
10
|
+
class ImportError < StandardError
|
11
|
+
end
|
10
12
|
|
11
13
|
def import_csv options
|
12
14
|
local_filepath = options[:filepath]
|
@@ -47,6 +49,26 @@ module Holistics
|
|
47
49
|
puts TabularFormatter.new(table).to_pretty_table
|
48
50
|
end
|
49
51
|
|
52
|
+
def import_list
|
53
|
+
result = http_request.get 'data_imports.json', 'Error retrieving list of data imports'
|
54
|
+
|
55
|
+
table = [%w(ID Name)]
|
56
|
+
rows = result.map {|record| [record['id'], record['title']]}
|
57
|
+
table.concat(rows)
|
58
|
+
|
59
|
+
puts TabularFormatter.new(table).to_pretty_table
|
60
|
+
end
|
61
|
+
|
62
|
+
def transform_list
|
63
|
+
result = http_request.get 'data_transforms.json', 'Error retrieving list of data transports'
|
64
|
+
|
65
|
+
table = [%w(ID Name)]
|
66
|
+
rows = result.map {|record| [record['id'], record['title']]}
|
67
|
+
table.concat(rows)
|
68
|
+
|
69
|
+
puts TabularFormatter.new(table).to_pretty_table
|
70
|
+
end
|
71
|
+
|
50
72
|
def send_transport(options)
|
51
73
|
puts 'Submitting transport job ...'
|
52
74
|
|
@@ -89,6 +111,10 @@ module Holistics
|
|
89
111
|
|
90
112
|
puts "Job submitted. Job ID: #{job_id}."
|
91
113
|
job_manager.tail_logs job_id
|
114
|
+
res = job_manager.fetch_job_results job_id
|
115
|
+
unless res['status'] == 'success'
|
116
|
+
raise ImportError.new("Failed Import Job #{job_id}: #{res['error']}")
|
117
|
+
end
|
92
118
|
end
|
93
119
|
|
94
120
|
def job_show(options)
|
@@ -9,19 +9,24 @@ module Holistics
|
|
9
9
|
|
10
10
|
def fetch_job_details(job_id, last_id = 0)
|
11
11
|
tries ||= MAX_RETRIES
|
12
|
-
|
12
|
+
|
13
13
|
url = auth_helper.api_url_for("jobs/#{job_id}/logs.json", last_id: last_id)
|
14
|
-
response =
|
15
|
-
|
14
|
+
response = http_request.simple_get url
|
15
|
+
|
16
16
|
JSON.parse(response.body)
|
17
|
-
rescue
|
17
|
+
rescue StandardError => e
|
18
18
|
sleep 2 ** (MAX_RETRIES - tries) unless Holistics.test?
|
19
19
|
if (tries -= 1) >= 0
|
20
20
|
puts 'Retrying...'
|
21
21
|
retry
|
22
22
|
end
|
23
23
|
puts 'Retry exceeded... Raise error'
|
24
|
-
raise
|
24
|
+
raise e
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch_job_results(job_id)
|
28
|
+
url = "jobs/#{job_id}/get_results.json"
|
29
|
+
http_request.get(url, "Cannot fetch info of job #{job_id}")
|
25
30
|
end
|
26
31
|
|
27
32
|
def job_show options
|
@@ -47,6 +52,12 @@ module Holistics
|
|
47
52
|
ts = Time.parse(log['timestamp'])
|
48
53
|
Holistics.logger.log(log['level'], log['message'], timestamp: ts)
|
49
54
|
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def http_request
|
59
|
+
@http_request ||= HttpRequest.new
|
60
|
+
end
|
50
61
|
end
|
51
62
|
end
|
52
63
|
end
|
data/lib/holistics/version.rb
CHANGED
data/lib/import.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'thor'
|
2
|
+
require 'colorize'
|
2
3
|
|
3
4
|
module Holistics
|
4
5
|
class Import < Thor
|
@@ -18,6 +19,7 @@ module Holistics
|
|
18
19
|
method_option :custom_range, aliases: '--custom-range', type: :boolean, lazy_default: true, required: false, desc: 'Execution type is custom_range. The range of left-closed right-opened range `[start, end)`.'
|
19
20
|
method_option :range_start, aliases: '--range-start', type: :string, required: false, desc: 'start range'
|
20
21
|
method_option :range_end, aliases: '--range-end', type: :string, required: false, desc: 'end range'
|
22
|
+
method_option :split_mode, aliases: '--split-mode', type: :string, required: false, desc: "Import splitting mode. Use 'daily' to split your custom range import to multiple executions, each covering one day of data."
|
21
23
|
desc 'execute', 'Invoke an import job'
|
22
24
|
|
23
25
|
def execute
|
@@ -30,8 +32,19 @@ module Holistics
|
|
30
32
|
params[:range_start] = options[:range_start]
|
31
33
|
params[:range_end] = options[:range_end]
|
32
34
|
params[:execution_mode] = 'custom_range'
|
35
|
+
if options[:split_mode] == 'daily'
|
36
|
+
return daily_splitted_import(params.dup)
|
37
|
+
end
|
33
38
|
end
|
34
|
-
|
39
|
+
send_import(params)
|
40
|
+
rescue => e
|
41
|
+
STDERR.puts e.message.red
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'list', 'List all data imports'
|
46
|
+
def list
|
47
|
+
api_client.import_list
|
35
48
|
end
|
36
49
|
|
37
50
|
no_commands do
|
@@ -39,5 +52,36 @@ module Holistics
|
|
39
52
|
@api_client ||= ApiClient.new
|
40
53
|
end
|
41
54
|
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def daily_splitted_import(params)
|
59
|
+
start_date = Date.parse(params[:range_start]) rescue raise("Invalid range start")
|
60
|
+
if params[:range_end]
|
61
|
+
end_date = Date.parse(params[:range_end]) rescue raise("Invalid range end")
|
62
|
+
else
|
63
|
+
end_date = Date.today
|
64
|
+
end
|
65
|
+
while start_date + 1 < end_date
|
66
|
+
params[:range_start] = start_date.strftime('%Y-%m-%d')
|
67
|
+
params[:range_end] = (start_date + 1).strftime('%Y-%m-%d')
|
68
|
+
puts "Importing range '#{params[:range_start]}' - '#{params[:range_end]}'".green
|
69
|
+
send_import(params, tries: 2)
|
70
|
+
start_date = start_date + 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def send_import(params, tries: 0)
|
75
|
+
total_trials ||= tries
|
76
|
+
api_client.send_import(params.dup)
|
77
|
+
rescue ApiClient::ImportError => e
|
78
|
+
sleep 2 ** (total_trials - tries) unless Holistics.test?
|
79
|
+
if (tries -= 1) >= 0
|
80
|
+
puts 'Retrying...'.orange
|
81
|
+
retry
|
82
|
+
end
|
83
|
+
puts "Exceeded retry count of #{total_trials}...".orange if total_trials > 0
|
84
|
+
raise
|
85
|
+
end
|
42
86
|
end
|
43
|
-
end
|
87
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'colorize'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module Holistics
|
6
|
+
class ImportChunking < Thor
|
7
|
+
|
8
|
+
|
9
|
+
# Example
|
10
|
+
# holistics import_chunking execute -j 29283 --range-start 2020-8-01T00:00:00Z --range-end 2021-9-01T00:00:00Z --chunk-days 10
|
11
|
+
|
12
|
+
|
13
|
+
method_option :import_id, aliases: '-j', type: :string, required: true, desc: 'ID of import job to be executed'
|
14
|
+
method_option :range_start, aliases: '--range-start', type: :string, required: true, desc: 'start range'
|
15
|
+
method_option :range_end, aliases: '--range-end', type: :string, required: true, desc: 'end range'
|
16
|
+
method_option :chunk_days, aliases: '--chunk-days', type: :numeric, required: true, desc: 'The range in days of each import'
|
17
|
+
|
18
|
+
desc 'execute', 'Generate import chunks for a date range'
|
19
|
+
def execute
|
20
|
+
one_day = 86_400
|
21
|
+
chunk_duration = one_day * options[:chunk_days]
|
22
|
+
|
23
|
+
date_start = Time.parse(options[:range_start])
|
24
|
+
date_end = Time.parse(options[:range_end])
|
25
|
+
|
26
|
+
generated_result = []
|
27
|
+
|
28
|
+
current_time = date_start
|
29
|
+
|
30
|
+
while current_time < date_end
|
31
|
+
chunk_start = current_time
|
32
|
+
chunk_end = current_time + chunk_duration
|
33
|
+
|
34
|
+
generated_result << gen_command(options[:import_id],
|
35
|
+
chunk_start,
|
36
|
+
chunk_end < date_end ? chunk_end : date_end)
|
37
|
+
|
38
|
+
current_time += chunk_duration
|
39
|
+
end
|
40
|
+
|
41
|
+
puts generated_result.join(" && \\ \n")
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def gen_command(id, range_start, range_end)
|
47
|
+
start_str = range_start.utc.iso8601
|
48
|
+
end_str = range_end.utc.iso8601
|
49
|
+
"holistics import execute -j #{id} --custom-range --range-start #{start_str} --range-end #{end_str}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/transform.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Holistics
|
4
|
+
class Transform < Thor
|
5
|
+
|
6
|
+
no_commands do
|
7
|
+
def api_client
|
8
|
+
@api_client ||= ApiClient.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
method_option :transform_id, aliases: '-j', type: :string, desc: 'ID of transform job to be executed'
|
13
|
+
desc 'transform', 'Invoke a transform'
|
14
|
+
|
15
|
+
def transform
|
16
|
+
unless options['transform_id']
|
17
|
+
puts "Please include a tranform job ID to execute. Usage: 'holistics transform --transform-id <id>'."
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
api_client.send_transform(options.dup)
|
21
|
+
end
|
22
|
+
default_task :transform
|
23
|
+
|
24
|
+
desc 'list', 'List all data transforms'
|
25
|
+
def list
|
26
|
+
api_client.transform_list
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/transport.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: holistics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thanh Dinh Khac
|
8
8
|
- Huy Nguyen
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-04-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '2.0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: colorize
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 0.8.1
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 0.8.1
|
84
98
|
description: CLI interface for Holistics
|
85
99
|
email: huy@holistics.io
|
86
100
|
executables:
|
@@ -104,14 +118,16 @@ files:
|
|
104
118
|
- lib/holistics/helpers/job_manager.rb
|
105
119
|
- lib/holistics/version.rb
|
106
120
|
- lib/import.rb
|
121
|
+
- lib/import_chunking.rb
|
107
122
|
- lib/tabular_formatter.rb
|
123
|
+
- lib/transform.rb
|
108
124
|
- lib/transport.rb
|
109
125
|
- lib/vcr_helper.rb
|
110
126
|
homepage: http://rubygems.org/gems/holistics-cli
|
111
127
|
licenses:
|
112
128
|
- GPL
|
113
129
|
metadata: {}
|
114
|
-
post_install_message:
|
130
|
+
post_install_message:
|
115
131
|
rdoc_options: []
|
116
132
|
require_paths:
|
117
133
|
- lib
|
@@ -127,9 +143,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
143
|
- !ruby/object:Gem::Version
|
128
144
|
version: '0'
|
129
145
|
requirements: []
|
130
|
-
rubyforge_project:
|
146
|
+
rubyforge_project:
|
131
147
|
rubygems_version: 2.5.1
|
132
|
-
signing_key:
|
148
|
+
signing_key:
|
133
149
|
specification_version: 4
|
134
150
|
summary: CLI interface for Holistics
|
135
151
|
test_files: []
|