gooddata 2.1.8-java → 2.1.13-java

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