gooddata 2.1.8-java → 2.1.13-java

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/.travis.yml +2 -4
  4. data/CHANGELOG.md +43 -0
  5. data/Dockerfile +19 -4
  6. data/Dockerfile.jruby +4 -4
  7. data/Dockerfile.ruby +5 -4
  8. data/README.md +2 -0
  9. data/SDK_VERSION +1 -1
  10. data/VERSION +1 -1
  11. data/bin/provision.sh +2 -0
  12. data/bin/release.sh +2 -0
  13. data/bin/rollout.sh +2 -0
  14. data/bin/run_brick.rb +31 -7
  15. data/bin/test_projects_cleanup.rb +10 -2
  16. data/bin/user_filters.sh +2 -0
  17. data/ci.rake +1 -1
  18. data/ci/bigquery/pom.xml +54 -0
  19. data/ci/redshift/pom.xml +73 -0
  20. data/ci/snowflake/pom.xml +57 -0
  21. data/dev-gooddata-sso.pub.encrypted +40 -40
  22. data/gdc_fossa_lcm.yaml +2 -0
  23. data/gdc_fossa_ruby_sdk.yaml +4 -0
  24. data/gooddata.gemspec +6 -2
  25. data/k8s/charts/lcm-bricks/Chart.yaml +1 -1
  26. data/k8s/charts/lcm-bricks/templates/prometheus/alertingRules.yaml +22 -12
  27. data/lcm.rake +14 -0
  28. data/lib/gooddata/bricks/middleware/execution_result_middleware.rb +68 -0
  29. data/lib/gooddata/bricks/middleware/logger_middleware.rb +2 -1
  30. data/lib/gooddata/bricks/middleware/mask_logger_decorator.rb +5 -1
  31. data/lib/gooddata/bricks/pipeline.rb +7 -0
  32. data/lib/gooddata/cloud_resources/bigquery/bigquery_client.rb +86 -0
  33. data/lib/gooddata/cloud_resources/bigquery/drivers/.gitkeepme +0 -0
  34. data/lib/gooddata/cloud_resources/cloud_resouce_factory.rb +28 -0
  35. data/lib/gooddata/cloud_resources/cloud_resource_client.rb +24 -0
  36. data/lib/gooddata/cloud_resources/cloud_resources.rb +12 -0
  37. data/lib/gooddata/cloud_resources/redshift/drivers/log4j.properties +15 -0
  38. data/lib/gooddata/cloud_resources/redshift/redshift_client.rb +101 -0
  39. data/lib/gooddata/cloud_resources/snowflake/drivers/.gitkeepme +0 -0
  40. data/lib/gooddata/cloud_resources/snowflake/snowflake_client.rb +84 -0
  41. data/lib/gooddata/exceptions/invalid_env_error.rb +15 -0
  42. data/lib/gooddata/helpers/data_helper.rb +10 -0
  43. data/lib/gooddata/helpers/data_source_helpers.rb +47 -0
  44. data/lib/gooddata/helpers/global_helpers.rb +4 -0
  45. data/lib/gooddata/helpers/global_helpers_params.rb +6 -9
  46. data/lib/gooddata/lcm/actions/collect_clients.rb +6 -6
  47. data/lib/gooddata/lcm/actions/collect_dynamic_schedule_params.rb +6 -6
  48. data/lib/gooddata/lcm/actions/collect_segment_clients.rb +4 -1
  49. data/lib/gooddata/lcm/actions/collect_segments.rb +1 -2
  50. data/lib/gooddata/lcm/actions/collect_users_brick_users.rb +7 -6
  51. data/lib/gooddata/lcm/actions/create_segment_masters.rb +5 -3
  52. data/lib/gooddata/lcm/actions/migrate_gdc_date_dimension.rb +116 -0
  53. data/lib/gooddata/lcm/actions/set_master_project.rb +76 -0
  54. data/lib/gooddata/lcm/actions/synchronize_clients.rb +1 -1
  55. data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +1 -2
  56. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +20 -3
  57. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +23 -3
  58. data/lib/gooddata/lcm/actions/synchronize_users.rb +50 -30
  59. data/lib/gooddata/lcm/actions/update_release_table.rb +7 -1
  60. data/lib/gooddata/lcm/exceptions/lcm_execution_error.rb +16 -0
  61. data/lib/gooddata/lcm/helpers/release_table_helper.rb +16 -8
  62. data/lib/gooddata/lcm/lcm2.rb +28 -5
  63. data/lib/gooddata/models/domain.rb +17 -15
  64. data/lib/gooddata/models/execution.rb +0 -1
  65. data/lib/gooddata/models/execution_detail.rb +0 -1
  66. data/lib/gooddata/models/from_wire.rb +1 -0
  67. data/lib/gooddata/models/process.rb +11 -3
  68. data/lib/gooddata/models/profile.rb +33 -11
  69. data/lib/gooddata/models/project.rb +120 -31
  70. data/lib/gooddata/models/project_creator.rb +2 -0
  71. data/lib/gooddata/models/schedule.rb +0 -1
  72. data/lib/gooddata/rest/client.rb +2 -2
  73. data/lib/gooddata/rest/connection.rb +5 -3
  74. data/rubydev_public.gpg.encrypted +51 -51
  75. data/rubydev_secret_keys.gpg.encrypted +109 -109
  76. metadata +32 -13
  77. data/lib/gooddata/extensions/hash.rb +0 -18
@@ -190,6 +190,9 @@ module GoodData
190
190
  create_non_existing_user_groups: create_non_existing_user_groups,
191
191
  user_groups_cache: nil
192
192
  }
193
+ GoodData.gd_logger.info("Synchronizing in mode=#{mode}, data_rows=#{new_users.size}")
194
+
195
+ GoodData.logger.info("Synchronizing in mode \"#{mode}\"")
193
196
  results = case mode
194
197
  when 'add_to_organization'
195
198
  domain.create_users(new_users.uniq { |u| u[:login] || u[:email] })
@@ -197,6 +200,8 @@ module GoodData
197
200
  user_ids = new_users.uniq { |u| u[:login] || u[:email] }.map { |u| u[:login] || u[:email] }
198
201
  users = user_ids.map { |u| domain.users(u, client: client) }
199
202
  params.gdc_logger.warn "Deleting #{users.count} users from domain #{domain_name}"
203
+
204
+ GoodData.gd_logger.info("Synchronizing in mode=#{mode}, domain=#{domain_name}, data_rows=#{users.count}")
200
205
  users.map(&:delete)
201
206
  when 'sync_project'
202
207
  project.import_users(new_users, common_params)
@@ -204,6 +209,8 @@ module GoodData
204
209
  new_users.group_by { |u| u[:pid] }.flat_map do |project_id, users|
205
210
  begin
206
211
  project = client.projects(project_id)
212
+
213
+ GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project_id}, data_rows=#{users.count}")
207
214
  project.import_users(users, common_params)
208
215
  rescue RestClient::ResourceNotFound
209
216
  fail "Project \"#{project_id}\" was not found. Please check your project ids in the source file"
@@ -215,6 +222,8 @@ module GoodData
215
222
  end
216
223
  when 'sync_one_project_based_on_pid'
217
224
  filtered_users = new_users.select { |u| u[:pid] == project.pid }
225
+
226
+ GoodData.gd_logger.info("Synchronizing in mode=#{mode}, data_rows=#{filtered_users.count}")
218
227
  project.import_users(filtered_users, common_params)
219
228
  when 'sync_one_project_based_on_custom_id'
220
229
  filter_value = UserBricksHelper.resolve_client_id(domain, project, data_product)
@@ -235,6 +244,7 @@ module GoodData
235
244
  end
236
245
 
237
246
  GoodData.logger.info("Project #{project.pid} will receive #{filtered_users.count} from #{new_users.count} users")
247
+ GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project.pid}, filtered_users=#{filtered_users.count}, data_rows=#{new_users.count}")
238
248
  project.import_users(filtered_users, common_params)
239
249
  when 'sync_multiple_projects_based_on_custom_id'
240
250
  all_clients = domain.clients(:all, data_product).to_a
@@ -248,6 +258,8 @@ module GoodData
248
258
  fail "Client #{client_id} does not have project." unless project
249
259
 
250
260
  GoodData.logger.info("Project #{project.pid} of client #{client_id} will receive #{users.count} users")
261
+
262
+ GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project.pid}, data_rows=#{users.count}")
251
263
  project.import_users(users, common_params)
252
264
  end
253
265
  when 'sync_domain_client_workspaces'
@@ -280,6 +292,8 @@ module GoodData
280
292
 
281
293
  working_client_ids << client_id.to_s
282
294
  GoodData.logger.info("Project #{project.pid} of client #{client_id} will receive #{users.count} users")
295
+
296
+ GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project.pid}, data_rows=#{users.count}")
283
297
  project.import_users(users, common_params)
284
298
  end
285
299
 
@@ -303,13 +317,18 @@ module GoodData
303
317
  next
304
318
  end
305
319
  GoodData.logger.info("Synchronizing all users in project #{project.pid} of client #{c.client_id}")
320
+
321
+ GoodData.gd_logger.info("Synchronizing all users in project_id=#{project.pid}, client_id=#{c.client_id}")
306
322
  res += project.import_users([], common_params)
307
323
  end
308
324
  end
309
325
 
310
326
  res
311
327
  when 'sync_domain_and_project'
328
+ GoodData.gd_logger.info("Create users in mode=#{mode}, data_rows=#{new_users.count}")
312
329
  domain.create_users(new_users, ignore_failures: ignore_failures)
330
+
331
+ GoodData.gd_logger.info("Import users in mode=#{mode}, data_rows=#{new_users.count}")
313
332
  project.import_users(new_users, common_params)
314
333
  end
315
334
 
@@ -328,38 +347,33 @@ module GoodData
328
347
  end
329
348
 
330
349
  def load_data(params, data_source)
331
- first_name_column = params.first_name_column || 'first_name'
332
- last_name_column = params.last_name_column || 'last_name'
333
- login_column = params.login_column || 'login'
334
- password_column = params.password_column || 'password'
335
- email_column = params.email_column || 'email'
336
- role_column = params.role_column || 'role'
337
- sso_provider_column = params.sso_provider_column || 'sso_provider'
338
- authentication_modes_column = params.authentication_modes_column || 'authentication_modes'
339
- user_groups_column = params.user_groups_column || 'user_groups'
340
- language_column = params.language_column || 'language'
341
- company_column = params.company_column || 'company'
342
- position_column = params.position_column || 'position'
343
- country_column = params.country_column || 'country'
344
- phone_column = params.phone_column || 'phone'
345
- ip_whitelist_column = params.ip_whitelist_column || 'ip_whitelist'
350
+ first_name_column = params.first_name_column&.downcase || 'first_name'
351
+ last_name_column = params.last_name_column&.downcase || 'last_name'
352
+ login_column = params.login_column&.downcase || 'login'
353
+ password_column = params.password_column&.downcase || 'password'
354
+ email_column = params.email_column&.downcase || 'email'
355
+ role_column = params.role_column&.downcase || 'role'
356
+ sso_provider_column = params.sso_provider_column&.downcase || 'sso_provider'
357
+ authentication_modes_column = params.authentication_modes_column&.downcase || 'authentication_modes'
358
+ user_groups_column = params.user_groups_column&.downcase || 'user_groups'
359
+ language_column = params.language_column&.downcase || 'language'
360
+ company_column = params.company_column&.downcase || 'company'
361
+ position_column = params.position_column&.downcase || 'position'
362
+ country_column = params.country_column&.downcase || 'country'
363
+ phone_column = params.phone_column&.downcase || 'phone'
364
+ ip_whitelist_column = params.ip_whitelist_column&.downcase || 'ip_whitelist'
346
365
 
347
366
  sso_provider = params.sso_provider
348
367
  authentication_modes = params.authentication_modes || []
349
368
 
350
- dwh = params.ads_client
351
- if dwh
352
- data = dwh.execute_select(params.input_source.query)
353
- else
354
- tmp = without_check(PARAMS, params) do
355
- File.open(data_source.realize(params), 'r:UTF-8')
356
- end
369
+ tmp = without_check(PARAMS, params) do
370
+ File.open(data_source.realize(params), 'r:UTF-8')
371
+ end
357
372
 
358
- begin
359
- data = read_csv_file(tmp)
360
- rescue Exception => e # rubocop:disable RescueException
361
- fail "There was an error during loading users from csv file. Message: #{e.message}. Error: #{e}"
362
- end
373
+ begin
374
+ data = read_csv_file(tmp)
375
+ rescue Exception => e # rubocop:disable RescueException
376
+ fail "There was an error during loading users from csv file. Message: #{e.message}. Error: #{e}"
363
377
  end
364
378
 
365
379
  data.map do |row|
@@ -379,12 +393,18 @@ module GoodData
379
393
  ip_whitelist = row[ip_whitelist_column] || row[ip_whitelist_column.to_sym]
380
394
  ip_whitelist = ip_whitelist.split(',').map(&:strip) if ip_whitelist
381
395
 
396
+ user_login = row[login_column] || row[login_column.to_sym]
397
+ user_login = user_login.strip unless user_login.nil?
398
+
399
+ user_email = row[email_column] || row[login_column] || row[email_column.to_sym] || row[login_column.to_sym]
400
+ user_email = user_email.strip unless user_email.nil?
401
+
382
402
  {
383
403
  :first_name => row[first_name_column] || row[first_name_column.to_sym],
384
404
  :last_name => row[last_name_column] || row[last_name_column.to_sym],
385
- :login => row[login_column] || row[login_column.to_sym],
405
+ :login => user_login,
386
406
  :password => row[password_column] || row[password_column.to_sym],
387
- :email => row[email_column] || row[login_column] || row[email_column.to_sym] || row[login_column.to_sym],
407
+ :email => user_email,
388
408
  :role => row[role_column] || row[role_column.to_sym],
389
409
  :sso_provider => sso_provider || row[sso_provider_column] || row[sso_provider_column.to_sym],
390
410
  :authentication_modes => modes,
@@ -405,7 +425,7 @@ module GoodData
405
425
  res = []
406
426
  row_count = 0
407
427
 
408
- CSV.foreach(path, :headers => true) do |row|
428
+ CSV.foreach(path, :headers => true, :header_converters => :downcase, :encoding => 'utf-8') do |row|
409
429
  if block_given?
410
430
  data = yield row
411
431
  else
@@ -39,6 +39,7 @@ module GoodData
39
39
  class << self
40
40
  def call(params)
41
41
  client = params.gdc_gd_client
42
+ GoodData.gd_logger.info("Update release table: use_nfs=#{params.ads_client.nil?}")
42
43
 
43
44
  domain_name = params.organization || params.domain
44
45
  fail "Either organisation or domain has to be specified in params" unless domain_name
@@ -48,6 +49,7 @@ module GoodData
48
49
  segment_id = segment_in.segment_id
49
50
 
50
51
  placeholders = {
52
+ data_product_id: segment_in[:data_product_id],
51
53
  segment_id: segment_in[:segment_id],
52
54
  master_project_id: segment_in[:master_pid],
53
55
  version: segment_in[:version],
@@ -83,7 +85,11 @@ module GoodData
83
85
 
84
86
  params.ads_client.execute(query)
85
87
  else
86
- GoodData::LCM2::Helpers.update_latest_master_to_nfs(domain_id, placeholders[:segment_id], placeholders[:master_project_id], placeholders[:version])
88
+ data_product_id = placeholders[:data_product_id]
89
+ segment_id = placeholders[:segment_id]
90
+ master_pid = placeholders[:master_project_id]
91
+ version = placeholders[:version]
92
+ GoodData::LCM2::Helpers.update_latest_master_to_nfs(domain_id, data_product_id, segment_id, master_pid, version)
87
93
  end
88
94
  end
89
95
  end
@@ -0,0 +1,16 @@
1
+ # Copyright (c) 2010-2019 GoodData Corporation. All rights reserved.
2
+ # This source code is licensed under the BSD-style license found in the
3
+ # LICENSE file in the root directory of this source tree.
4
+
5
+ module GoodData
6
+ class LcmExecutionError < RuntimeError
7
+ DEFAULT_MSG = 'Error during lcm execution'
8
+
9
+ attr_reader :summary_error
10
+
11
+ def initialize(summary_error, message = DEFAULT_MSG)
12
+ super(message)
13
+ @summary_error = summary_error
14
+ end
15
+ end
16
+ end
@@ -8,7 +8,7 @@ module GoodData
8
8
  module LCM2
9
9
  class Helpers
10
10
  DEFAULT_TABLE_NAME = 'LCM_RELEASE'
11
- DEFAULT_NFS_DIRECTORY = 'release-tables'
11
+ DEFAULT_NFS_DIRECTORY = '/release-tables'
12
12
 
13
13
  class << self
14
14
  def latest_master_project_from_ads(release_table_name, ads_client, segment_id)
@@ -25,22 +25,30 @@ module GoodData
25
25
  sorted.last
26
26
  end
27
27
 
28
- def latest_master_project_from_nfs(domain_id, segment_id)
29
- data = GoodData::Helpers::Csv.read_as_hash(path_to_release_table_file(domain_id, segment_id))
30
- data.sort_by { |master| master[:version] }
28
+ def latest_master_project_from_nfs(domain_id, data_product_id, segment_id)
29
+ file_path = path_to_release_table_file(domain_id, data_product_id, segment_id)
30
+ data = GoodData::Helpers::Csv.read_as_hash(file_path)
31
+ latest_master_project = data.sort_by { |master| master[:version] }
31
32
  .reverse.first
33
+
34
+ version_info = latest_master_project ? "master_pid=#{latest_master_project[:master_project_id]} version=#{latest_master_project[:version]}" : ""
35
+ GoodData.gd_logger.info "Getting latest master project: file=#{file_path} domain=#{domain_id} data_product=#{data_product_id} segment=#{segment_id} #{version_info}"
36
+ latest_master_project
32
37
  end
33
38
 
34
- def update_latest_master_to_nfs(domain_id, segment_id, master_pid, version)
39
+ def update_latest_master_to_nfs(domain_id, data_product_id, segment_id, master_pid, version)
40
+ file_path = path_to_release_table_file(domain_id, data_product_id, segment_id)
41
+ GoodData.gd_logger.info "Updating release table: file=#{file_path} domain=#{domain_id} data_product=#{data_product_id} segment=#{segment_id} master_pid=#{master_pid} version=#{version}" # rubocop:disable Metrics/LineLength
35
42
  GoodData::Helpers::Csv.ammend_line(
36
- path_to_release_table_file(domain_id, segment_id),
43
+ file_path,
37
44
  master_project_id: master_pid,
38
45
  version: version
39
46
  )
40
47
  end
41
48
 
42
- def path_to_release_table_file(domain_id, segment_id)
43
- [DEFAULT_NFS_DIRECTORY, domain_id, segment_id + '.csv'].join('/')
49
+ def path_to_release_table_file(domain_id, data_prod_id, segment_id)
50
+ nsf_directory = ENV['RELEASE_TABLE_NFS_DIRECTORY'] || DEFAULT_NFS_DIRECTORY
51
+ [nsf_directory, domain_id, data_prod_id + '-' + segment_id + '.csv'].join('/')
44
52
  end
45
53
  end
46
54
  end
@@ -18,6 +18,7 @@ require 'active_support/core_ext/hash/compact'
18
18
  require_relative 'actions/actions'
19
19
  require_relative 'dsl/dsl'
20
20
  require_relative 'helpers/helpers'
21
+ require_relative 'exceptions/lcm_execution_error'
21
22
 
22
23
  using TrueExtensions
23
24
  using FalseExtensions
@@ -105,6 +106,14 @@ module GoodData
105
106
  UpdateReleaseTable
106
107
  ],
107
108
 
109
+ release_set_master_project: [
110
+ EnsureReleaseTable,
111
+ CollectDataProduct,
112
+ SegmentsFilter,
113
+ SetMasterProject,
114
+ UpdateReleaseTable
115
+ ],
116
+
108
117
  provision: [
109
118
  EnsureReleaseTable,
110
119
  CollectDataProduct,
@@ -129,6 +138,7 @@ module GoodData
129
138
  EnsureTechnicalUsersDomain,
130
139
  EnsureTechnicalUsersProject,
131
140
  SynchronizeLdm,
141
+ MigrateGdcDateDimension,
132
142
  SynchronizeClients,
133
143
  SynchronizeComputedAttributes,
134
144
  CollectDymanicScheduleParams,
@@ -270,8 +280,14 @@ module GoodData
270
280
 
271
281
  GoodData.gd_logger.brick = mode
272
282
 
283
+ final_mode = if params.set_master_project && mode == 'release'
284
+ 'release_set_master_project'
285
+ else
286
+ mode
287
+ end
288
+
273
289
  # Get actions for mode specified
274
- actions = get_mode_actions(mode)
290
+ actions = get_mode_actions(final_mode)
275
291
 
276
292
  if params.actions
277
293
  actions = params.actions.map do |action|
@@ -304,6 +320,12 @@ module GoodData
304
320
  skip_actions.include?(action.name.split('::').last)
305
321
  end
306
322
 
323
+ sync_mode = params.fetch(:sync_mode, nil)
324
+ if mode == 'users' && %w[add_to_organization remove_from_organization].include?(sync_mode)
325
+ actions = actions.reject do |action|
326
+ %w[CollectDataProduct CollectSegments].include?(action.name.split('::').last)
327
+ end
328
+ end
307
329
  check_unused_params(actions, params)
308
330
  print_action_names(mode, actions)
309
331
 
@@ -357,10 +379,11 @@ module GoodData
357
379
 
358
380
  if errors.any?
359
381
  error_message = JSON.pretty_generate(errors)
360
- GoodData.logger.error(error_message)
361
-
362
- # Fail whole execution if there is any failed action
363
- fail(error_message) if strict_mode
382
+ if strict_mode
383
+ raise GoodData::LcmExecutionError.new(errors[0][:err], error_message)
384
+ else
385
+ GoodData.logger.error(error_message)
386
+ end
364
387
  end
365
388
 
366
389
  result
@@ -222,24 +222,26 @@ module GoodData
222
222
  domain = client.domain(domain)
223
223
  if id == :all
224
224
  GoodData.logger.warn("Retrieving all users from domain #{domain.name}")
225
- Enumerator.new do |y|
226
- page_limit = opts[:page_limit] || 1000
227
- offset = opts[:offset] || 0
228
- loop do
229
- begin
230
- tmp = client(opts).get("#{domain.uri}/users", params: { offset: offset, limit: page_limit })
231
- end
232
-
233
- tmp['accountSettings']['items'].each do |user_data|
234
- user = client.create(GoodData::Profile, user_data)
235
- y << user if user
236
- end
237
- break if tmp['accountSettings']['items'].count < page_limit
238
- offset += page_limit
225
+ all_users = []
226
+ page_limit = opts[:page_limit] || 1000
227
+ offset = opts[:offset] || 0
228
+ loop do
229
+ begin
230
+ tmp = client(opts).get("#{domain.uri}/users", params: { offset: offset, limit: page_limit })
239
231
  end
232
+
233
+ tmp['accountSettings']['items'].each do |user_data|
234
+ user = client.create(GoodData::Profile, user_data)
235
+ all_users << user if user
236
+ end
237
+ break if tmp['accountSettings']['items'].count < page_limit
238
+
239
+ offset += page_limit
240
240
  end
241
+
242
+ all_users
241
243
  else
242
- find_user_by_login(domain, id)
244
+ find_user_by_login(domain, id, opts)
243
245
  end
244
246
  end
245
247
 
@@ -5,7 +5,6 @@
5
5
  # LICENSE file in the root directory of this source tree.
6
6
 
7
7
  require_relative '../rest/resource'
8
- require_relative '../extensions/hash'
9
8
 
10
9
  module GoodData
11
10
  class Execution < Rest::Resource
@@ -5,7 +5,6 @@
5
5
  # LICENSE file in the root directory of this source tree.
6
6
 
7
7
  require_relative '../rest/resource'
8
- require_relative '../extensions/hash'
9
8
 
10
9
  module GoodData
11
10
  class ExecutionDetail < Rest::Resource
@@ -105,6 +105,7 @@ module GoodData
105
105
  d[:title] = date_dim['dateDimension']['title']
106
106
  d[:urn] = date_dim['dateDimension']['urn']
107
107
  d[:identifier_prefix] = date_dim['dateDimension']['identifierPrefix']
108
+ d[:identifier] = date_dim['dateDimension']['identifier'] if date_dim['dateDimension']['identifier']
108
109
  d[:columns] = parse_bridges(date_dim)
109
110
  end
110
111
  end
@@ -118,11 +118,13 @@ module GoodData
118
118
  GoodData.logger.info("Deploying #{path}") if verbose
119
119
 
120
120
  deployed_path = Process.upload_package(path, files_to_exclude, client: client, project: project)
121
+ data_sources = options[:data_sources] || []
121
122
  data = {
122
123
  :process => {
123
124
  :name => deploy_name,
124
125
  :path => "/uploads/#{File.basename(deployed_path)}",
125
- :type => type
126
+ :type => type,
127
+ :dataSources => data_sources
126
128
  }
127
129
  }
128
130
 
@@ -171,10 +173,12 @@ module GoodData
171
173
  verbose = options[:verbose] || false
172
174
  GoodData.logger.info("Deploying #{path}") if verbose
173
175
 
176
+ data_sources = options[:data_sources] || []
174
177
  data = {
175
178
  process: {
176
179
  name: deploy_name,
177
180
  path: path,
181
+ dataSources: data_sources,
178
182
  type: 'RUBY'
179
183
  }
180
184
  }
@@ -185,7 +189,7 @@ module GoodData
185
189
  def deploy_component(data, options = { client: GoodData.client, project: GoodData.project })
186
190
  client, project = GoodData.get_client_and_project(options)
187
191
  data = { process: data } unless data[:process]
188
- data[:process] = GoodData::Helpers.symbolize_keys(data[:process]).select { |k| %i[type name component].include? k }
192
+ data[:process] = GoodData::Helpers.symbolize_keys(data[:process]).select { |k| %i[type name component dataSources].include? k }
189
193
  data[:process][:component] = GoodData::Helpers.symbolize_keys(data[:process][:component]).select { |k| %i[name version configLocation config].include? k }
190
194
 
191
195
  save(data, options)
@@ -266,7 +270,7 @@ module GoodData
266
270
  # @option options [String] :name Readable name of the process
267
271
  # @option options [Boolean] :verbose (false) Switch on verbose mode for detailed logging
268
272
  def deploy(path, options = {})
269
- Process.deploy(path, { client: client, process_id: process_id, :project => project, :name => name, :type => type }.merge(options))
273
+ Process.deploy(path, { client: client, process_id: process_id, :project => project, :name => name, :type => type, :data_sources => data_sources }.merge(options))
270
274
  end
271
275
 
272
276
  # Downloads the process from S3 in a zipped form.
@@ -326,6 +330,10 @@ module GoodData
326
330
  process['component']
327
331
  end
328
332
 
333
+ def data_sources
334
+ process['dataSources']
335
+ end
336
+
329
337
  # Determines whether the process is an ADDv2 component.
330
338
  # @return [Bool] True if the process is an ADDv2 component.
331
339
  def add_v2_component?