gooddata 0.6.50 → 0.6.51

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +12 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +3 -0
  5. data/gooddata.gemspec +2 -1
  6. data/lib/gooddata/bricks/middleware/aws_middleware.rb +4 -0
  7. data/lib/gooddata/bricks/middleware/decode_params_middleware.rb +1 -1
  8. data/lib/gooddata/bricks/middleware/dwh_middleware.rb +1 -0
  9. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +1 -0
  10. data/lib/gooddata/bricks/middleware/logger_middleware.rb +2 -1
  11. data/lib/gooddata/core/nil_logger.rb +9 -0
  12. data/lib/gooddata/goodzilla/goodzilla.rb +1 -1
  13. data/lib/gooddata/helpers/data_helper.rb +1 -0
  14. data/lib/gooddata/helpers/global_helpers_params.rb +54 -27
  15. data/lib/gooddata/lcm/actions/apply_custom_maql.rb +70 -0
  16. data/lib/gooddata/lcm/actions/associate_clients.rb +17 -4
  17. data/lib/gooddata/lcm/actions/collect_clients.rb +4 -1
  18. data/lib/gooddata/lcm/actions/collect_segment_clients.rb +1 -0
  19. data/lib/gooddata/lcm/actions/collect_segments.rb +15 -2
  20. data/lib/gooddata/lcm/actions/create_segment_masters.rb +2 -2
  21. data/lib/gooddata/lcm/actions/provision_clients.rb +2 -4
  22. data/lib/gooddata/lcm/actions/purge_clients.rb +2 -2
  23. data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +81 -0
  24. data/lib/gooddata/lcm/actions/synchronize_label_types.rb +2 -2
  25. data/lib/gooddata/lcm/actions/synchronize_processes.rb +3 -1
  26. data/lib/gooddata/lcm/data/create_lcm_release.sql.erb +2 -1
  27. data/lib/gooddata/lcm/helpers/check_helper.rb +1 -1
  28. data/lib/gooddata/lcm/lcm.rb +29 -11
  29. data/lib/gooddata/lcm/lcm2.rb +82 -20
  30. data/lib/gooddata/models/domain.rb +22 -1
  31. data/lib/gooddata/models/metadata.rb +13 -8
  32. data/lib/gooddata/models/metadata/attribute.rb +1 -1
  33. data/lib/gooddata/models/metadata/report_definition.rb +1 -0
  34. data/lib/gooddata/models/profile.rb +1 -1
  35. data/lib/gooddata/models/project.rb +162 -38
  36. data/lib/gooddata/models/project_creator.rb +26 -6
  37. data/lib/gooddata/models/project_log_formatter.rb +204 -0
  38. data/lib/gooddata/models/schedule.rb +2 -21
  39. data/lib/gooddata/models/segment.rb +26 -0
  40. data/lib/gooddata/models/style_setting.rb +5 -1
  41. data/lib/gooddata/models/user_filters/user_filter_builder.rb +9 -0
  42. data/lib/gooddata/rest/connection.rb +4 -1
  43. data/lib/gooddata/version.rb +1 -1
  44. data/spec/environment/development.rb +29 -0
  45. data/spec/environment/environment.rb +14 -2
  46. data/spec/environment/{hotfix.rb → testing.rb} +0 -0
  47. data/spec/integration/date_dim_switch_spec.rb +3 -5
  48. data/spec/integration/lcm_spec.rb +24 -21
  49. data/spec/integration/project_spec.rb +16 -0
  50. data/spec/integration/segments_spec.rb +1 -1
  51. data/spec/unit/helpers/global_helpers_spec.rb +26 -2
  52. data/spec/unit/helpers_spec.rb +20 -0
  53. data/spec/unit/models/project_creator_spec.rb +3 -2
  54. metadata +29 -12
  55. data/lib/gooddata/lcm/actions/ensure_titles.rb +0 -54
  56. data/spec/environment/develop.rb +0 -46
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba2ae6d7826f6eb42b8f24eb7774313adebfcda7
4
- data.tar.gz: e7589c5893af0dcc78fcb16f8b9bd1a8562b2f00
3
+ metadata.gz: d1715a4ba9d7203654418b0a275dd7eaf7e5e1dc
4
+ data.tar.gz: 42547b8e7ccbef65b3a0c6b0cb276886c55adcd8
5
5
  SHA512:
6
- metadata.gz: 7910edb7b3f5e2dc18f669034e983e5dee218dc9cf193017cfaf3f23b0a4fe9ddf3b3e5a4efdd1913aa95294e06edf30e1ee5feb38274deb29efc49471388484
7
- data.tar.gz: eb863dfe3ead470750f8b0fab9b402989c07a51aeaadfeefa08219a7975f9795a60d58dd441789112ee51263cb3db24539ca626442612267f8cc543da9bb412f
6
+ metadata.gz: d8120afa7ca7037fbd372960fe2ad02e9d2dc92d2d9dd17ce614b3f8d2a9d4e12412fe6ee8c3c2bd9f1c67ffdbf7962c099f612ec10a625188e2dfe0b5f8f2c8
7
+ data.tar.gz: a8485d9b645c943c91386111a4f4b6d12c66162d141bb747e4865761d2ca15ebdad92900d8ed6f3596ebdd55048af6c1ad3cf651049ccf04fb0e7b9edc2acfad
data/.editorconfig ADDED
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.{sh,markdown}]
12
+ indent_size = 4
data/.gitignore CHANGED
@@ -12,6 +12,7 @@ tmtags
12
12
 
13
13
  ## VIM
14
14
  *.swp
15
+ .tags*
15
16
 
16
17
  ## IDEA
17
18
  .idea/
data/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # GoodData Ruby SDK Changelog
2
2
 
3
+ ## 0.6.52
4
+
3
5
  ## 0.6.50
4
6
  - Add support for Email Notification Rules on Process
5
7
  - Add support for exclude_schedules option in Project#export_clone
@@ -10,6 +12,7 @@
10
12
  - Support for custom color palette
11
13
  - Support for trasfering attribute drill paths
12
14
  - Implemented basic version of LCM2
15
+ - Add more logging for user, user filter management
13
16
 
14
17
  ## 0.6.49
15
18
  - Implement Helpers::GD_MAX_RETRY to allow max retries override
data/gooddata.gemspec CHANGED
@@ -34,12 +34,13 @@ Gem::Specification.new do |s|
34
34
  s.add_development_dependency 'redcarpet', '~> 3.1' if RUBY_PLATFORM != 'java'
35
35
  s.add_development_dependency 'rspec', '~> 3.5'
36
36
  s.add_development_dependency 'rspec-expectations', '~> 3.5'
37
- s.add_development_dependency 'rubocop', '~> 0.47'
37
+ s.add_development_dependency 'rubocop', '< 0.48' # TODO: remove it after dealing with new rules introduced in 0.48 version
38
38
  s.add_development_dependency 'simplecov', '~> 0.12'
39
39
  s.add_development_dependency 'webmock', '~> 1.21'
40
40
  s.add_development_dependency 'yard', '~> 0.8'
41
41
  s.add_development_dependency 'yard-rspec', '~> 0.1'
42
42
  s.add_development_dependency 'ZenTest', '~> 4.11'
43
+ s.add_development_dependency 'pry'
43
44
 
44
45
  s.add_dependency 'aws-sdk', '~> 2.7'
45
46
  s.add_dependency 'nokogiri', '~> 1.6.8'
@@ -17,6 +17,10 @@ module GoodData
17
17
  raise 'Unable to connect to AWS. Parameter "aws_client" seems to be empty' unless params['aws_client']
18
18
  raise 'Unable to connect to AWS. Parameter "access_key_id" is missing' if params['aws_client']['access_key_id'].blank?
19
19
  raise 'Unable to connect to AWS. Parameter "secret_access_key" is missing' if params['aws_client']['secret_access_key'].blank?
20
+ if params['aws_client'].key?('use_ssl')
21
+ params['aws_client']['use_ssl'] =
22
+ params['aws_client']['use_ssl'].to_b
23
+ end
20
24
  s3 = AWS::S3.new(params['aws_client'])
21
25
  params['aws_client']['s3_client'] = s3
22
26
  end
@@ -14,7 +14,7 @@ module GoodData
14
14
  params = params.to_hash
15
15
 
16
16
  # Decode and resolve reference parameters in gd_encoded_params
17
- @app.call(GoodData::Helpers.decode_params(params, :resolve_reference_params => true))
17
+ @app.call(GoodData::Helpers.decode_params(params, resolve_reference_params: true, convert_pipe_delimited_params: true))
18
18
  end
19
19
  end
20
20
  end
@@ -10,6 +10,7 @@ require 'gooddata_datawarehouse' if RUBY_PLATFORM == 'java'
10
10
 
11
11
  module GoodData
12
12
  module Bricks
13
+ # Connects to the warehouse (ADS) and enriches parameters with GoodData::Datawarehouse
13
14
  class WarehouseMiddleware < Bricks::Middleware
14
15
  def call(params)
15
16
  if params.key?('ads_client') && (RUBY_PLATFORM == 'java')
@@ -8,6 +8,7 @@ require_relative 'base_middleware'
8
8
 
9
9
  module GoodData
10
10
  module Bricks
11
+ # Connects to platform and enriches parameters with GoodData::Client
11
12
  class GoodDataMiddleware < Bricks::Middleware
12
13
  DEFAULT_PROTOCOL = 'https'
13
14
  DEFAULT_HOSTNAME = 'secure.gooddata.com'
@@ -17,9 +17,10 @@ module GoodData
17
17
  if params['GDC_LOGGING_OFF']
18
18
  logger = NilLogger.new
19
19
  else
20
- logger = params['GDC_LOGGER'] = params[:GDC_LOGGER_FILE].nil? ? Logger.new(STDOUT) : Logger.new(params[:GDC_LOGGER_FILE])
20
+ logger = params[:GDC_LOGGER_FILE].nil? ? Logger.new(STDOUT) : Logger.new(params[:GDC_LOGGER_FILE])
21
21
  logger.info('Pipeline starts')
22
22
  end
23
+ params['GDC_LOGGER'] = logger
23
24
  returning(@app.call(params)) do |_result|
24
25
  logger.info('Pipeline ending')
25
26
  end
@@ -19,5 +19,14 @@ module GoodData
19
19
  alias_method :info, :debug
20
20
  alias_method :warn, :debug
21
21
  alias_method :error, :debug
22
+
23
+ def debug?
24
+ false
25
+ end
26
+
27
+ alias_method :info?, :debug?
28
+ alias_method :warn?, :debug?
29
+ alias_method :error?, :debug?
30
+ alias_method :fatal?, :debug?
22
31
  end
23
32
  end
@@ -11,7 +11,7 @@ module GoodData
11
11
  # @param maql Input MAQL string
12
12
  # @return [Array<Array>] Pairs [attribute, attribute_element]
13
13
  def extract_element_uri_pairs(maql)
14
- arr = maql.scan(%r{\[([^\[\]]*)\/elements\?id=(\d+)\]}).flatten
14
+ arr = maql.scan(%r{(\/gdc\/(?:projects|md)\/[a-zA-Z\d]+\/obj\/\d+)\/elements\?id=(\d+)}).flatten
15
15
  evens = arr.select.each_with_index { |_, i| i.even? }
16
16
  odds = arr.select.each_with_index { |_, i| i.odd? }.map(&:to_i)
17
17
  evens.zip(odds)
@@ -102,6 +102,7 @@ module GoodData
102
102
  end
103
103
 
104
104
  def realize_s3(params)
105
+ params = GoodData::Helpers.stringify_keys(params)
105
106
  s3_client = params['aws_client'] && params['aws_client']['s3_client']
106
107
  raise 'AWS client not present. Perhaps S3Middleware is missing in the brick definition?' if !s3_client || !s3_client.respond_to?(:buckets)
107
108
  bucket_name = @options[:bucket]
@@ -57,26 +57,6 @@ module GoodData
57
57
  # @option options [Boolean] :resolve_reference_params Resolve reference parameters in gd_encoded_params or not
58
58
  # @return [Hash] Decoded parameters
59
59
  def decode_params(params, options = {})
60
- convert_secure_params = lambda do |args|
61
- args = args.select { |k, _| k.include? "|" }
62
- lines = args.keys.map do |key|
63
- hash = {}
64
- last_a = nil
65
- last_e = nil
66
- key.split("|").reduce(hash) do |a, e|
67
- last_a = a
68
- last_e = e
69
- a[e] = {}
70
- end
71
- last_a[last_e] = args[key]
72
- hash
73
- end
74
-
75
- lines.reduce({}) do |a, e|
76
- a.deep_merge(e)
77
- end
78
- end
79
-
80
60
  key = ENCODED_PARAMS_KEY.to_s
81
61
  hidden_key = ENCODED_HIDDEN_PARAMS_KEY.to_s
82
62
  data_params = params[key] || '{}'
@@ -103,6 +83,8 @@ module GoodData
103
83
  v.map do |v2|
104
84
  resolve_reference.call(v2)
105
85
  end
86
+ elsif !v.is_a?(String)
87
+ v
106
88
  else
107
89
  v.gsub(regexps) do |match|
108
90
  if match =~ /\\\\/
@@ -130,21 +112,47 @@ module GoodData
130
112
  begin
131
113
  parsed_data_params = data_params.is_a?(Hash) ? data_params : JSON.parse(data_params)
132
114
  parsed_hidden_data_params = hidden_data_params.is_a?(Hash) ? hidden_data_params : JSON.parse(hidden_data_params)
133
- rescue JSON::ParserError => e
134
- raise e.class, "Error reading json from '#{key}' or '#{hidden_key}', reason: #{e.message}"
115
+ rescue JSON::ParserError => exception
116
+ raise exception.class, "Error reading json from '#{key}' or '#{hidden_key}', reason: #{exception.message}"
135
117
  end
136
118
 
137
119
  # Add the nil on ENCODED_HIDDEN_PARAMS_KEY
138
120
  # if the data was retrieved from API You will not have the actual values so encode -> decode is not losless. The nil on the key prevents the server from deleting the key
139
121
  parsed_hidden_data_params[ENCODED_HIDDEN_PARAMS_KEY] = nil unless parsed_hidden_data_params.empty?
140
- secure_params = convert_secure_params.call(params)
141
- params.delete_if do |k, _|
142
- k.include?('|')
143
- end
144
122
 
145
123
  params.delete(key)
146
124
  params.delete(hidden_key)
147
- params.deep_merge(parsed_data_params).deep_merge(parsed_hidden_data_params).deep_merge(secure_params)
125
+ params = params.deep_merge(parsed_data_params).deep_merge(parsed_hidden_data_params)
126
+
127
+ if options[:convert_pipe_delimited_params]
128
+ convert_pipe_delimited_params = lambda do |args|
129
+ args = args.select { |k, _| k.include? "|" }
130
+ lines = args.keys.map do |k|
131
+ hash = {}
132
+ last_a = nil
133
+ last_e = nil
134
+ k.split("|").reduce(hash) do |a, e|
135
+ last_a = a
136
+ last_e = e
137
+ a[e] = {}
138
+ end
139
+ last_a[last_e] = args[k]
140
+ hash
141
+ end
142
+
143
+ lines.reduce({}) do |a, e|
144
+ a.deep_merge(e)
145
+ end
146
+ end
147
+
148
+ pipe_delimited_params = convert_pipe_delimited_params.call(params)
149
+ params.delete_if do |k, _|
150
+ k.include?('|')
151
+ end
152
+ params = params.deep_merge(pipe_delimited_params)
153
+ end
154
+
155
+ params
148
156
  end
149
157
 
150
158
  # A helper which allows you to diff two lists of objects. The objects
@@ -233,6 +241,25 @@ module GoodData
233
241
  end
234
242
  lookup
235
243
  end
244
+
245
+ def stringify_values(value)
246
+ case value
247
+ when nil
248
+ value
249
+ when Hash
250
+ Hash[
251
+ value.map do |k, v|
252
+ [k, stringify_values(v)]
253
+ end
254
+ ]
255
+ when Array
256
+ value.map do |v|
257
+ stringify_values(v)
258
+ end
259
+ else
260
+ value.to_s
261
+ end
262
+ end
236
263
  end
237
264
  end
238
265
  end
@@ -0,0 +1,70 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative 'base_action'
8
+
9
+ module GoodData
10
+ module LCM2
11
+ # Applies custom MAQL DDL to all client projects so customized
12
+ # labels and fiscal calendars are not deleted.
13
+ # To ease up further automation, the MAQL DDL may be
14
+ # stored in separate field in lcm_release
15
+ # table as we will need custom Release brick action which will populate it.
16
+ class ApplyCustomMaql < BaseAction
17
+ DESCRIPTION = 'Apply Custom MAQL DDL'
18
+
19
+ PARAMS = define_params(self) do
20
+ description 'Should be custom MAQL DDL Applied'
21
+ param :apply_maql_ddl, instance_of(Type::BooleanType), required: false, default: false
22
+ end
23
+
24
+ RESULT_HEADER = [
25
+ :segment,
26
+ :maql,
27
+ :status
28
+ ]
29
+
30
+ class << self
31
+ def call(params)
32
+ return [] unless params.apply_maql_ddl.to_b
33
+
34
+ client = params.gdc_gd_client
35
+
36
+ domain_name = params.organization || params.domain
37
+ domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
38
+
39
+ segment_ids = params.segments.map(&:segment_id)
40
+ domain_segments = domain.segments.select do |ds|
41
+ segment_ids.include?(ds.segment_id)
42
+ end
43
+
44
+ res = []
45
+ domain_segments.peach do |ds|
46
+ maql = 'CREATE DATASET {dataset.quotes} VISUAL (TITLE "Stock Quotes Data");'
47
+
48
+ unless maql.empty?
49
+ ds.clients.peach do |dc|
50
+ project = dc.project
51
+
52
+ r = project.execute_maql(maql)
53
+
54
+ item = {
55
+ segment: ds.segment_id,
56
+ maql: maql,
57
+ status: r
58
+ }
59
+
60
+ res.push(item)
61
+ end
62
+ end
63
+ end
64
+
65
+ res
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -31,14 +31,27 @@ module GoodData
31
31
 
32
32
  client = params.gdc_gd_client
33
33
 
34
- delete_projects = GoodData::Helpers.to_boolean(params.delete_projects)
35
- delete_extra = GoodData::Helpers.to_boolean(params.delete_extra)
36
-
37
34
  domain_name = params.organization || params.domain
38
35
  domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
39
36
 
40
37
  domain.update_clients_settings(params.clients)
41
- domain.update_clients(params.clients, delete_extra: delete_extra, delete_projects: delete_projects)
38
+
39
+ delete_projects = GoodData::Helpers.to_boolean(params.delete_projects)
40
+ delete_extra = GoodData::Helpers.to_boolean(params.delete_extra)
41
+ options = { delete_projects: delete_projects }
42
+ options.merge!(delete_extra_option(params)) if delete_extra
43
+
44
+ domain.update_clients(params.clients, options)
45
+ end
46
+
47
+ private
48
+
49
+ def delete_extra_option(params)
50
+ if params.segments_filter && params.segments_filter.any?
51
+ { delete_extra_in_segments: params.segments_filter }
52
+ else
53
+ { delete_extra: delete_extra }
54
+ end
42
55
  end
43
56
  end
44
57
  end
@@ -65,11 +65,14 @@ module GoodData
65
65
  id: row[client_id_column],
66
66
  segment: segment_name,
67
67
  project: row[project_id_column],
68
- project_title: row[project_title_column],
69
68
  settings: [
70
69
  {
71
70
  name: 'lcm.token',
72
71
  value: row[project_token_column]
72
+ },
73
+ {
74
+ name: 'lcm.title',
75
+ value: row[project_title_column]
73
76
  }
74
77
  ]
75
78
  }.compact
@@ -66,6 +66,7 @@ module GoodData
66
66
  master_name = master.title
67
67
 
68
68
  sync_info = {
69
+ segment_id: segment.segment_id,
69
70
  from: master_pid,
70
71
  to: segment.clients.map do |segment_client|
71
72
  client_project = segment_client.project
@@ -30,10 +30,23 @@ module GoodData
30
30
  domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
31
31
  domain_segments = domain.segments
32
32
 
33
+ if params.segments_filter
34
+ domain_segments.select! do |segment|
35
+ params.segments_filter.include?(segment.segment_id)
36
+ end
37
+ end
38
+
33
39
  segments = domain_segments.map do |segment|
34
- project = segment.master_project
40
+ project = nil
41
+
42
+ begin
43
+ project = segment.master_project
44
+ rescue RestClient::BadRequest => e
45
+ params.gdc_logger.error "Failed to retrieve master project for segment #{segment.id}. Error: #{e}"
46
+ raise
47
+ end
35
48
 
36
- # TODO: Check if project exists!
49
+ raise "Master project for segment #{segment.id} doesn't exist." unless project
37
50
 
38
51
  {
39
52
  segment_id: segment.segment_id,
@@ -21,8 +21,8 @@ module GoodData
21
21
  description 'ADS Client'
22
22
  param :ads_client, instance_of(Type::AdsClientType), required: true
23
23
 
24
- description 'Queries Used'
25
- param :query, instance_of(Type::ReleaseQueryType), required: false
24
+ # description 'Queries Used'
25
+ # param :query, instance_of(Type::ReleaseQueryType), required: false
26
26
 
27
27
  description 'Segments to manage'
28
28
  param :segments, array_of(instance_of(Type::SegmentType)), required: true
@@ -39,7 +39,6 @@ module GoodData
39
39
 
40
40
  domain_name = params.organization || params.domain
41
41
  domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
42
- domain_segments = domain.segments
43
42
 
44
43
  synchronize_projects = []
45
44
  results = params.segments.map do |segment|
@@ -47,11 +46,10 @@ module GoodData
47
46
  Hash[m.each_pair.to_a].merge(type: :provision_result)
48
47
  end
49
48
 
50
- segment_master = domain_segments.find(segment.segment_id).first.master_project.pid
51
-
52
49
  unless tmp.empty?
53
50
  synchronize_projects << {
54
- from: segment_master,
51
+ segment_id: segment.segment_id,
52
+ from: segment.development_pid,
55
53
  to: tmp.map do |entry|
56
54
  {
57
55
  pid: entry[:project_uri].split('/').last,