holistics 0.3.2 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1bba5c00d378d880776abee2c49de89169d805c446eb568cdd53dd06230875c3
4
- data.tar.gz: de6a9892e7731010c961783945cda2ea86ba26bcbda8492ddf53bbf57016029e
3
+ metadata.gz: 32364a4f3b5aa6da19afdc05c34a6a9c3361721a200a6788bbc81bd4c7039b52
4
+ data.tar.gz: a3a993895ae584784d2abe4b3ba4e27a21688e8a4222c71be942cad483bfa809
5
5
  SHA512:
6
- metadata.gz: 16de9d14ab01ab1c6a187ce74ddf00f3c366b026c227b5c3fd0e619084fc4d201063e136a677f59ce64a6dc3cef1db8eda1a60d01418cc8020280ebaf32d7c4b
7
- data.tar.gz: 73657415d7f7f527153f34440a01fbf0831505e11e242d0ff589590bed3551638db95167d4eb6002c66eba45963e7c1ff0e6fc87012908f2734d5982416bfdc5
6
+ metadata.gz: 8d5cfeb9ffc0990025139117aa02c31a0bada08b86c267bfd37e1257f240267221f9acb0d8eb162e7f9f1ab5a60a00a152c1d070c30ff8bc60a18dafd70c3919
7
+ data.tar.gz: 441660cafeee9c3b74f6a8cd6f9984b1e2b4e13bf7cbfd33c58d0a765ab98c45b5da371a3a36c315ea236287f5110b2a012aa3501e6caa85ba0f2931d84a4ff5
data/CHANGELOG.md CHANGED
@@ -2,32 +2,42 @@
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.0.11
6
- * Support invocation of transform from CLI: `holistics transform -j <id>`
5
+ ## v0.4.0
6
+ * Add `dbt upload` command
7
7
 
8
- ## v0.0.12
9
- * Support generation of transport config files from CLI: `holistics generate_configs -s <src_ds_id> -d <dest_ds_id> -t <tables> [-o <output>]`
8
+ ## v0.3.4
9
+ * Update retry mechanism for `fetch_job_details`
10
10
 
11
- ## v0.1.0
12
- * Modularized transport and data_sources commands. Rename existing transport command to transport_old.
11
+ ## v0.3.3
12
+ * Add "transform list" and "import list" commands
13
+ * Add "version" command
13
14
 
14
- ## v0.2.0
15
- * Support command to import csv into table
15
+ ## v0.3.2
16
+ * Add 'colorize' to gemspec dependencies
16
17
 
17
- ## v0.2.1
18
- * Fix dependency error
18
+ ## v0.3.1
19
+ * Add option to split a custom range Data Import execution into smaller ones
19
20
 
20
- ## v0.2.5
21
- * Support invoking email schedule with `holistics email_schedule trigger <id>`
21
+ ## v0.3.0
22
+ * Add option to execute Data Imports in custom range mode
22
23
 
23
24
  ## v0.2.6
24
25
  * Add error handling and retry mechanism for `fetch_job_details`
25
26
 
26
- ## v0.3.0
27
- * Add option to execute Data Imports in custom range mode
27
+ ## v0.2.5
28
+ * Support invoking email schedule with `holistics email_schedule trigger <id>`
28
29
 
29
- ## v0.3.1
30
- * Add option to split a custom range Data Import execution into smaller ones
30
+ ## v0.2.1
31
+ * Fix dependency error
31
32
 
32
- ## v0.3.2
33
- * Add 'colorize' to gemspec dependencies
33
+ ## v0.2.0
34
+ * Support command to import csv into table
35
+
36
+ ## v0.1.0
37
+ * Modularized transport and data_sources commands. Rename existing transport command to transport_old.
38
+
39
+ ## v0.0.12
40
+ * Support generation of transport config files from CLI: `holistics generate_configs -s <src_ds_id> -d <dest_ds_id> -t <tables> [-o <output>]`
41
+
42
+ ## v0.0.11
43
+ * 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
@@ -79,6 +80,11 @@ Example:
79
80
  [job:738] Hot-swapping with Redshift table public.users ...
80
81
  [job:738] Done.
81
82
 
83
+ ## dbt commands
84
+ ### Upload dbt's manifest.json file to Holistics
85
+ $ holistics dbt upload --file-path /path/to/manifest.json --data-source demodb
86
+
87
+
82
88
  ### Custom table build transport
83
89
 
84
90
  See `samples/clicks_mysql_to_redshift.json` for details of transport configs.
data/holistics.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.0"
24
24
 
25
- spec.add_dependency 'activesupport', '~> 4.2'
25
+ spec.add_dependency 'activesupport'
26
26
  spec.add_dependency 'httparty', '~> 0.13'
27
27
  spec.add_dependency 'thor', '~> 0.19'
28
28
  spec.add_dependency 'multipart-post', '~> 2.0'
data/lib/dbt.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'thor'
2
+ require 'holistics/helpers/http_request'
3
+
4
+ module Holistics
5
+ class Dbt < Thor
6
+ method_option :filepath, aliases: '--file-path', type: :string, required: false, desc: 'Path to manifest.json file'
7
+ method_option :data_source_name, aliases: '--data-source', type: :string, required: false, desc: 'Name of data_source'
8
+ desc 'upload', 'Upload manifest.json file to Holistics'
9
+ def upload
10
+ data_source_name = options[:data_source_name]
11
+ manifest_file = get_manifest_file_from(options)
12
+
13
+ params = {
14
+ data_source_name: data_source_name
15
+ }
16
+
17
+ http_request.post_file('api/v2/data_sources/upload_dbt_manifest.json', params, manifest_file, 'application/json',
18
+ 'Error uploading manifest.json file')
19
+
20
+ puts 'Upload completed!'
21
+ end
22
+
23
+ private
24
+
25
+ def get_manifest_file_from(options)
26
+ local_filepath =
27
+ if options[:filepath].present?
28
+ options[:filepath]
29
+ else
30
+ Dir['./**/manifest.json'].first
31
+ end
32
+
33
+ begin
34
+ file = File.open(local_filepath)
35
+ rescue StandardError
36
+ warn "Could not open file at '#{local_filepath}'."
37
+ puts 'Invalid file path. Please check your file path.'
38
+ return
39
+ end
40
+
41
+ file
42
+ end
43
+
44
+ def http_request
45
+ @http_request ||= Helpers::HttpRequest.new
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'tabular_formatter'
2
4
  require 'yaml'
3
5
  require 'json'
@@ -10,16 +12,16 @@ module Holistics
10
12
  class ImportError < StandardError
11
13
  end
12
14
 
13
- def import_csv options
15
+ def import_csv(options)
14
16
  local_filepath = options[:filepath]
15
17
  dest_ds_id = options[:dest_ds_id]
16
18
  dest_fqname = options[:dest_table_name]
17
19
 
18
20
  begin
19
21
  file = File.open local_filepath
20
- rescue
21
- STDERR.puts "Could not open file at '#{local_filepath}'."
22
- puts "Invalid file path. Please check your file path."
22
+ rescue StandardError
23
+ warn "Could not open file at '#{local_filepath}'."
24
+ puts 'Invalid file path. Please check your file path.'
23
25
 
24
26
  return
25
27
  end
@@ -31,7 +33,7 @@ module Holistics
31
33
  dest_ds_id: dest_ds_id
32
34
  }
33
35
 
34
- json = http_request.post_csv 'data_imports/import_csv.json', params, file, 'Error uploading CSV file'
36
+ json = http_request.post_file 'data_imports/import_csv.json', params, file, 'text/csv', 'Error uploading CSV file'
35
37
 
36
38
  job_id = json['message']['job_id']
37
39
 
@@ -42,8 +44,28 @@ module Holistics
42
44
  def ds_list
43
45
  result = http_request.get 'data_sources.json', 'Error retrieving list of data sources'
44
46
 
45
- table = [%w(ID Type Name)]
46
- rows = result.map {|record| [record['id'], record['dbtype'], record['name']]}
47
+ table = [%w[ID Type Name]]
48
+ rows = result.map { |record| [record['id'], record['dbtype'], record['name']] }
49
+ table.concat(rows)
50
+
51
+ puts TabularFormatter.new(table).to_pretty_table
52
+ end
53
+
54
+ def import_list
55
+ result = http_request.get 'data_imports.json', 'Error retrieving list of data imports'
56
+
57
+ table = [%w[ID Name]]
58
+ rows = result.map { |record| [record['id'], record['title']] }
59
+ table.concat(rows)
60
+
61
+ puts TabularFormatter.new(table).to_pretty_table
62
+ end
63
+
64
+ def transform_list
65
+ result = http_request.get 'data_transforms.json', 'Error retrieving list of data transports'
66
+
67
+ table = [%w[ID Name]]
68
+ rows = result.map { |record| [record['id'], record['title']] }
47
69
  table.concat(rows)
48
70
 
49
71
  puts TabularFormatter.new(table).to_pretty_table
@@ -93,7 +115,7 @@ module Holistics
93
115
  job_manager.tail_logs job_id
94
116
  res = job_manager.fetch_job_results job_id
95
117
  unless res['status'] == 'success'
96
- raise ImportError.new("Failed Import Job #{job_id}: #{res['error']}")
118
+ raise ImportError, "Failed Import Job #{job_id}: #{res['error']}"
97
119
  end
98
120
  end
99
121
 
@@ -103,16 +125,14 @@ module Holistics
103
125
  end
104
126
 
105
127
  def generate_configs(options)
106
- unless Dir.exist?(options['output'])
107
- raise 'Output location is invalid.'
108
- end
128
+ raise 'Output location is invalid.' unless Dir.exist?(options['output'])
109
129
 
110
130
  puts "Generating transport JSON config files to #{options['output']} directory..."
111
131
 
112
132
  result = http_request.post_json 'transports/generate_configs.json', options, 'Error generating transport configs'
113
133
 
114
134
  result.each do |table_data|
115
- File.open("#{options['output']}/#{table_data['filename']}", "w") do |f|
135
+ File.open("#{options['output']}/#{table_data['filename']}", 'w') do |f|
116
136
  f.write(JSON.pretty_generate(table_data['json_content']))
117
137
  end
118
138
 
@@ -125,24 +145,28 @@ module Holistics
125
145
 
126
146
  def build_submit_params(options)
127
147
  params = options.except(:config_path)
128
- params[:configs] = parse_transport_config(options[:config_path]).to_json if options[:config_path]
148
+ if options[:config_path]
149
+ params[:configs] = parse_transport_config(options[:config_path]).to_json
150
+ end
129
151
  params
130
152
  end
131
153
 
132
154
  def parse_transport_config(filepath)
133
155
  file_ext = File.extname(filepath).downcase
134
156
  if file_ext == '.json'
135
- return JSON.parse(File.read(filepath))
157
+ JSON.parse(File.read(filepath))
136
158
  elsif file_ext == '.yml'
137
- return YAML.load(File.read(filepath))
159
+ YAML.safe_load(File.read(filepath))
138
160
  else
139
- raise StandardError.new 'Invalid config file extension. Please use either JSON or YML'
161
+ raise StandardError, 'Invalid config file extension. Please use either JSON or YML'
140
162
  end
141
163
  rescue StandardError => e
142
- STDERR.puts "Error parsing transport config file: #{e.message}"
164
+ warn "Error parsing transport config file: #{e.message}"
143
165
  exit 1
144
166
  end
145
167
 
168
+ def dbt_upload(filepath, ds_name); end
169
+
146
170
  private
147
171
 
148
172
  def file_manager
@@ -160,7 +184,5 @@ module Holistics
160
184
  def auth_info
161
185
  @auth_info ||= Helpers::AuthInfo.new
162
186
  end
163
-
164
-
165
187
  end
166
188
  end
@@ -34,7 +34,7 @@ module Holistics
34
34
  exit_if_error(msg_if_error, response)
35
35
  JSON.parse response.body
36
36
  end
37
-
37
+
38
38
  def simple_get(url, token = nil)
39
39
  HTTParty
40
40
  .get url, headers: { API_KEY_HEADER => token || auth_helper.get_token_from_gconfig }
@@ -61,11 +61,11 @@ module Holistics
61
61
  #
62
62
  # see this link for setting it
63
63
  # https://github.com/nicksieger/multipart-post/issues/18#issuecomment-171479987
64
- def post_csv url, params, file, msg_if_error = DEFAULT_ERROR_MSG
64
+ def post_file url, params, file, content_type, msg_if_error = DEFAULT_ERROR_MSG
65
65
  uri = URI.parse(endpoint_for(url))
66
- csv = UploadIO.new file, "text/csv", File.basename(file.path)
67
- params = params.merge file: csv
68
-
66
+ upload_file = UploadIO.new file, content_type, File.basename(file.path)
67
+ params = params.merge file: upload_file
68
+
69
69
  post_data = Net::HTTP::Post::Multipart.new uri.path, params
70
70
  post_data.add_field(API_KEY_HEADER, auth_helper.get_token_from_gconfig)
71
71
 
@@ -14,14 +14,14 @@ module Holistics
14
14
  response = http_request.simple_get url
15
15
 
16
16
  JSON.parse(response.body)
17
- rescue JSON::ParserError => err
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
25
  end
26
26
 
27
27
  def fetch_job_results(job_id)
@@ -1,4 +1,4 @@
1
1
  module Holistics
2
- VERSION = '0.3.2'
3
- DATE = '2018-08-24'
2
+ VERSION = '0.4.0'
3
+ DATE = '2021-10-15'
4
4
  end
data/lib/holistics.rb CHANGED
@@ -1,14 +1,18 @@
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'
15
+ require 'dbt'
12
16
 
13
17
  module Holistics
14
18
  def self.root
@@ -42,9 +46,12 @@ module Holistics
42
46
  end
43
47
 
44
48
  register(Holistics::Import, 'import', 'import <command>', "Execute import commands")
49
+ register(Holistics::ImportChunking, 'import_chunking', 'import_chunking <command>', "Generate import chunks for date range imports")
45
50
  register(Holistics::Transport, 'transport', 'transport <command>', "Execute transport module's commands")
51
+ register(Holistics::Transform, 'transform', 'transform <command>', "Execute transform module's commands")
46
52
  register(Holistics::DataSources, 'data_sources', 'data_sources <command>', "Execute data_sources module's commands")
47
53
  register(Holistics::EmailSchedule, 'email_schedule', 'email_schedule <command>', "Execute email schedule's commands")
54
+ register(Holistics::Dbt, 'dbt', 'dbt <comnand>', 'dbt integration with Holistics')
48
55
 
49
56
  no_commands do
50
57
  def auth_api_client
@@ -69,13 +76,6 @@ module Holistics
69
76
  api_client.ds_list
70
77
  end
71
78
 
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
79
  method_option :job_id, aliases: '-j', type: :string, required: true, desc: 'Job ID'
80
80
  desc 'job_show', 'Show job log'
81
81
 
@@ -83,5 +83,9 @@ module Holistics
83
83
  api_client.job_show(options.dup)
84
84
  end
85
85
 
86
+ desc 'version', "Show current Holistics gem's version"
87
+ def version
88
+ puts Holistics::VERSION
89
+ end
86
90
  end
87
91
  end
data/lib/import.rb CHANGED
@@ -42,6 +42,11 @@ module Holistics
42
42
  exit 1
43
43
  end
44
44
 
45
+ desc 'list', 'List all data imports'
46
+ def list
47
+ api_client.import_list
48
+ end
49
+
45
50
  no_commands do
46
51
  def api_client
47
52
  @api_client ||= ApiClient.new
@@ -79,4 +84,4 @@ module Holistics
79
84
  raise
80
85
  end
81
86
  end
82
- 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
@@ -30,4 +30,4 @@ module Holistics
30
30
  api_client.generate_configs(options.dup)
31
31
  end
32
32
  end
33
- end
33
+ end
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.2
4
+ version: 0.4.0
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: 2018-08-24 00:00:00.000000000 Z
12
+ date: 2021-10-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -29,16 +29,16 @@ dependencies:
29
29
  name: activesupport
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '4.2'
34
+ version: '0'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '4.2'
41
+ version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: httparty
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,7 @@ files:
108
108
  - bin/holistics
109
109
  - holistics.gemspec
110
110
  - lib/data_sources.rb
111
+ - lib/dbt.rb
111
112
  - lib/email_schedule.rb
112
113
  - lib/holistics.rb
113
114
  - lib/holistics/api_client.rb
@@ -118,14 +119,16 @@ files:
118
119
  - lib/holistics/helpers/job_manager.rb
119
120
  - lib/holistics/version.rb
120
121
  - lib/import.rb
122
+ - lib/import_chunking.rb
121
123
  - lib/tabular_formatter.rb
124
+ - lib/transform.rb
122
125
  - lib/transport.rb
123
126
  - lib/vcr_helper.rb
124
127
  homepage: http://rubygems.org/gems/holistics-cli
125
128
  licenses:
126
129
  - GPL
127
130
  metadata: {}
128
- post_install_message:
131
+ post_install_message:
129
132
  rdoc_options: []
130
133
  require_paths:
131
134
  - lib
@@ -141,9 +144,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
144
  - !ruby/object:Gem::Version
142
145
  version: '0'
143
146
  requirements: []
144
- rubyforge_project:
145
- rubygems_version: 2.7.7
146
- signing_key:
147
+ rubygems_version: 3.1.6
148
+ signing_key:
147
149
  specification_version: 4
148
150
  summary: CLI interface for Holistics
149
151
  test_files: []