holistics 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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: []