gooddata 2.1.19-java → 2.3.0-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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.gdc-ii-config.yaml +42 -1
  3. data/.github/workflows/build.yml +67 -0
  4. data/.github/workflows/pre-merge.yml +72 -0
  5. data/.pronto.yml +1 -0
  6. data/.rubocop.yml +2 -14
  7. data/CHANGELOG.md +47 -0
  8. data/Dockerfile +27 -14
  9. data/Dockerfile.jruby +5 -15
  10. data/Dockerfile.ruby +5 -7
  11. data/Gemfile +4 -2
  12. data/README.md +6 -6
  13. data/Rakefile +1 -1
  14. data/SDK_VERSION +1 -1
  15. data/VERSION +1 -1
  16. data/bin/run_brick.rb +7 -0
  17. data/ci/mssql/pom.xml +62 -0
  18. data/ci/mysql/pom.xml +62 -0
  19. data/ci/redshift/pom.xml +4 -5
  20. data/docker-compose.lcm.yml +42 -4
  21. data/docker-compose.yml +42 -0
  22. data/gooddata.gemspec +21 -21
  23. data/k8s/charts/lcm-bricks/Chart.yaml +1 -1
  24. data/lcm.rake +11 -8
  25. data/lib/gooddata/bricks/base_pipeline.rb +26 -0
  26. data/lib/gooddata/bricks/brick.rb +0 -1
  27. data/lib/gooddata/bricks/middleware/aws_middleware.rb +35 -9
  28. data/lib/gooddata/bricks/middleware/execution_result_middleware.rb +3 -3
  29. data/lib/gooddata/bricks/pipeline.rb +2 -14
  30. data/lib/gooddata/cloud_resources/blobstorage/blobstorage_client.rb +98 -0
  31. data/lib/gooddata/cloud_resources/mssql/drivers/.gitkeepme +0 -0
  32. data/lib/gooddata/cloud_resources/mssql/mssql_client.rb +122 -0
  33. data/lib/gooddata/cloud_resources/mysql/drivers/.gitkeepme +0 -0
  34. data/lib/gooddata/cloud_resources/mysql/mysql_client.rb +121 -0
  35. data/lib/gooddata/cloud_resources/postgresql/postgresql_client.rb +0 -1
  36. data/lib/gooddata/cloud_resources/redshift/drivers/.gitkeepme +0 -0
  37. data/lib/gooddata/cloud_resources/redshift/redshift_client.rb +0 -2
  38. data/lib/gooddata/cloud_resources/snowflake/snowflake_client.rb +18 -1
  39. data/lib/gooddata/helpers/data_helper.rb +9 -4
  40. data/lib/gooddata/lcm/actions/base_action.rb +157 -0
  41. data/lib/gooddata/lcm/actions/collect_data_product.rb +2 -1
  42. data/lib/gooddata/lcm/actions/collect_meta.rb +3 -1
  43. data/lib/gooddata/lcm/actions/collect_projects_warning_status.rb +53 -0
  44. data/lib/gooddata/lcm/actions/collect_segment_clients.rb +14 -0
  45. data/lib/gooddata/lcm/actions/initialize_continue_on_error_option.rb +87 -0
  46. data/lib/gooddata/lcm/actions/migrate_gdc_date_dimension.rb +31 -4
  47. data/lib/gooddata/lcm/actions/provision_clients.rb +34 -5
  48. data/lib/gooddata/lcm/actions/synchronize_cas.rb +24 -4
  49. data/lib/gooddata/lcm/actions/synchronize_clients.rb +112 -11
  50. data/lib/gooddata/lcm/actions/synchronize_dataset_mappings.rb +89 -0
  51. data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +48 -11
  52. data/lib/gooddata/lcm/actions/synchronize_kd_dashboard_permission.rb +103 -0
  53. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +79 -23
  54. data/lib/gooddata/lcm/actions/synchronize_ldm_layout.rb +98 -0
  55. data/lib/gooddata/lcm/actions/synchronize_pp_dashboard_permission.rb +108 -0
  56. data/lib/gooddata/lcm/actions/synchronize_schedules.rb +31 -1
  57. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +26 -18
  58. data/lib/gooddata/lcm/actions/synchronize_user_groups.rb +30 -4
  59. data/lib/gooddata/lcm/actions/synchronize_users.rb +11 -10
  60. data/lib/gooddata/lcm/actions/update_metric_formats.rb +202 -0
  61. data/lib/gooddata/lcm/data/delete_from_lcm_release.sql.erb +5 -0
  62. data/lib/gooddata/lcm/exceptions/lcm_execution_warning.rb +15 -0
  63. data/lib/gooddata/lcm/helpers/check_helper.rb +19 -0
  64. data/lib/gooddata/lcm/helpers/release_table_helper.rb +42 -8
  65. data/lib/gooddata/lcm/lcm2.rb +50 -4
  66. data/lib/gooddata/lcm/user_bricks_helper.rb +9 -0
  67. data/lib/gooddata/mixins/inspector.rb +1 -1
  68. data/lib/gooddata/mixins/md_object_query.rb +1 -0
  69. data/lib/gooddata/models/data_source.rb +5 -1
  70. data/lib/gooddata/models/dataset_mapping.rb +36 -0
  71. data/lib/gooddata/models/ldm_layout.rb +38 -0
  72. data/lib/gooddata/models/metadata/label.rb +26 -27
  73. data/lib/gooddata/models/project.rb +230 -30
  74. data/lib/gooddata/models/project_creator.rb +83 -6
  75. data/lib/gooddata/models/schedule.rb +13 -1
  76. data/lib/gooddata/models/segment.rb +2 -1
  77. data/lib/gooddata/models/user_filters/user_filter_builder.rb +162 -68
  78. data/lib/gooddata/rest/connection.rb +5 -3
  79. data/lib/gooddata/rest/phmap.rb +2 -0
  80. data/lib/gooddata.rb +1 -0
  81. data/lib/gooddata_brick_base.rb +35 -0
  82. data/sonar-project.properties +6 -0
  83. metadata +96 -65
  84. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +0 -37
  85. data/lib/gooddata/cloud_resources/redshift/drivers/log4j.properties +0 -15
@@ -19,6 +19,9 @@ using NilExtensions
19
19
 
20
20
  module GoodData
21
21
  module UserFilterBuilder
22
+ @all_domain_users = {}
23
+ @mutex = Mutex.new
24
+
22
25
  # Main Entry function. Gets values and processes them to get filters
23
26
  # that are suitable for other function to process.
24
27
  # Values can be read from file or provided inline as an array.
@@ -48,11 +51,26 @@ module GoodData
48
51
  end
49
52
 
50
53
  def self.read_file(file, options = {})
51
- memo = {}
52
- params = row_based?(options) ? { headers: false } : { headers: true }
54
+ memo = Hash[]
55
+ if row_based?(options)
56
+ read_data_without_header(file, memo, options)
57
+ else
58
+ read_data_with_header(file, memo, options)
59
+ end
60
+ memo
61
+ end
53
62
 
54
- CSV.foreach(file, params.merge(return_headers: false)) do |e|
55
- key, data = process_line(e, options)
63
+ def self.read_data_without_header(file, memo, options)
64
+ CSV.foreach(file, headers: false, return_headers: false) do |row|
65
+ key, data = process_line(row, options)
66
+ memo[key] = [] unless memo.key?(key)
67
+ memo[key].concat(data)
68
+ end
69
+ end
70
+
71
+ def self.read_data_with_header(file, memo, options)
72
+ CSV.foreach(file, headers: true, return_headers: false) do |row|
73
+ key, data = process_line(row, options)
56
74
  memo[key] = [] unless memo.key?(key)
57
75
  memo[key].concat(data)
58
76
  end
@@ -203,20 +221,30 @@ module GoodData
203
221
  # so it precaches the values and still be able to function for larger ones even
204
222
  # though that would mean tons of requests
205
223
  def self.get_small_labels(labels_cache)
206
- labels_cache.values.select { |label| label && label.values_count && label.values_count < 100_000 }
224
+ labels_cache.values.select { |label| label &.values_count &. < 100_000 }
207
225
  end
208
226
 
209
227
  # Creates a MAQL expression(s) based on the filter defintion.
210
228
  # Takes the filter definition looks up any necessary values and provides API executable MAQL
211
229
  # @param labels_cache e.g. { 'label_uri': label_object }
212
230
  # @param lookups_cache e.g. { 'label_uri': { "jirka@gooddata.com": 'value_uri' }}
213
- def self.create_expression(filter, labels_cache, lookups_cache, attr_cache, options = {})
231
+ # rubocop:disable Metrics/ParameterLists
232
+ def self.create_expression(filter, labels_cache, lookups_cache, attr_cache, options = {}, login)
214
233
  values = filter[:values]
215
234
  # Do not create MUF for label when all its values is NULL (https://jira.intgdc.com/browse/TMA-1361)
216
235
  non_null_values = values.select { |value| !value.nil? && value.downcase != 'null' }
217
236
  return ['TRUE', []] if non_null_values.empty?
218
237
 
219
238
  label = labels_cache[filter[:label]]
239
+ if label.nil?
240
+ err_message = "Unable to apply filter values: #{values} since the project: #{options[:project].pid} doesn't have label: #{filter[:label]} for login: #{login}"
241
+ if options[:ignore_missing_values]
242
+ GoodData.logger.warn(err_message)
243
+ return ['TRUE', []]
244
+ else
245
+ fail err_message
246
+ end
247
+ end
220
248
  errors = []
221
249
 
222
250
  element_uris_by_values = Hash[values.map do |v|
@@ -262,6 +290,7 @@ module GoodData
262
290
  end
263
291
  [expression, errors]
264
292
  end
293
+ # rubocop:enable Metrics/ParameterLists
265
294
 
266
295
  # Encapuslates the creation of filter
267
296
  def self.create_user_filter(expression, related)
@@ -273,6 +302,66 @@ module GoodData
273
302
  }
274
303
  end
275
304
 
305
+ def self.create_user_profile_mapping(filters, project_users, options = {})
306
+ domain = options[:domain]
307
+ found_list = {}
308
+ missing_list = []
309
+
310
+ # Get the list of user login from filters
311
+ login_list = filters.flat_map do |filter|
312
+ filter[:login]
313
+ end
314
+
315
+ # Then find user login in the users_brick_input
316
+ users_brick_input = options[:users_brick_input]
317
+ if users_brick_input&.any?
318
+ users_brick_input.map do |user|
319
+ login_list << user.with_indifferent_access['login']
320
+ end
321
+ end
322
+
323
+ login_list.uniq.flat_map do |login|
324
+ user = project_users.find { |u| u.login == login }
325
+ if user
326
+ found_list[login] = user.profile_url
327
+ else
328
+ missing_list << login
329
+ end
330
+ end
331
+ # rubocop:disable Metrics/BlockNesting
332
+ unless missing_list.empty? || domain.nil?
333
+ if missing_list.size < 100
334
+ missing_list.each do |login|
335
+ user = domain.find_user_by_login(login)
336
+ found_list[login] = user.links['self'] if user
337
+ end
338
+ else
339
+ if @all_domain_users[domain.name].nil?
340
+ @mutex.lock
341
+ if @all_domain_users[domain.name].nil?
342
+ domain_users = domain.users
343
+ @all_domain_users[domain.name] = domain_users
344
+ GoodData.logger.info("action=lcm_get_domain_users domain=#{domain.name} number_users=#{domain_users.size} number_missing_users=#{missing_list.size} use_cache=false")
345
+ else
346
+ domain_users = @all_domain_users[domain.name]
347
+ GoodData.logger.info("action=lcm_get_domain_users domain=##{domain.name} number_users=#{domain_users.size} number_missing_users=#{missing_list.size} use_cache=true")
348
+ end
349
+ @mutex.unlock
350
+ else
351
+ domain_users = @all_domain_users[domain.name]
352
+ GoodData.logger.info("action=lcm_get_domain_users domain=##{domain.name} number_users=#{domain_users.size} number_missing_users=#{missing_list.size} use_cache=true")
353
+ end
354
+
355
+ missing_list.each do |login|
356
+ user = domain_users.find { |u| u.login == login }
357
+ found_list[login] = user.links['self'] if user
358
+ end
359
+ end
360
+ end
361
+ # rubocop:enable Metrics/BlockNesting
362
+ found_list
363
+ end
364
+
276
365
  # Resolves and creates maql statements from filter definitions.
277
366
  # This method does not perform any modifications on API but
278
367
  # collects all the information that is needed to do so.
@@ -283,7 +372,7 @@ module GoodData
283
372
  #
284
373
  # @param filters [Array<Hash>] Filters definition
285
374
  # @return [Array] first is list of MAQL statements
286
- def self.maqlify_filters(filters, project_users, options = {})
375
+ def self.maqlify_filters(filters, user_profile_mapping, options = {})
287
376
  fail_early = options[:fail_early] == false ? false : true
288
377
  users_cache = options[:users_cache]
289
378
  labels_cache = create_label_cache(filters, options)
@@ -291,11 +380,10 @@ module GoodData
291
380
  lookups_cache = create_lookups_cache(small_labels)
292
381
  attrs_cache = create_attrs_cache(filters, options)
293
382
  create_filter_proc = proc do |login, f|
294
- expression, errors = create_expression(f, labels_cache, lookups_cache, attrs_cache, options)
383
+ expression, errors = create_expression(f, labels_cache, lookups_cache, attrs_cache, options, login)
295
384
  safe_login = login.downcase
296
385
  profiles_uri = if options[:type] == :muf
297
- project_user = project_users.find { |u| u.login == safe_login }
298
- project_user.nil? ? ('/gdc/account/profile/' + safe_login) : project_user.profile_url
386
+ user_profile_mapping[safe_login].nil? ? ('/gdc/account/profile/' + safe_login) : user_profile_mapping[safe_login]
299
387
  elsif options[:type] == :variable
300
388
  (users_cache[login] && users_cache[login].uri)
301
389
  else
@@ -393,7 +481,8 @@ module GoodData
393
481
 
394
482
  project_users = project.users
395
483
  filters = normalize_filters(user_filters)
396
- user_filters, errors = maqlify_filters(filters, project_users, options.merge(users_must_exist: users_must_exist, type: :muf))
484
+ user_profile_mapping = create_user_profile_mapping(filters, project_users, options)
485
+ user_filters, errors = maqlify_filters(filters, user_profile_mapping, options.merge(users_must_exist: users_must_exist, type: :muf))
397
486
  if !ignore_missing_values && !errors.empty?
398
487
  errors = errors.map do |e|
399
488
  e.merge(pid: project.pid)
@@ -404,7 +493,7 @@ module GoodData
404
493
  filters = user_filters.map { |data| client.create(MandatoryUserFilter, data, project: project) }
405
494
  to_create, to_delete = resolve_user_filters(filters, project.data_permissions)
406
495
 
407
- to_delete = sanitize_filters_to_delete(to_delete, options[:users_brick_input], project_users) unless options[:no_sanitize]
496
+ to_delete = sanitize_filters_to_delete(to_delete, options[:users_brick_input], user_profile_mapping) unless options[:no_sanitize]
408
497
 
409
498
  if options[:do_not_touch_filters_that_are_not_mentioned]
410
499
  GoodData.logger.warn("Data permissions computed: #{to_create.count} to create")
@@ -421,68 +510,73 @@ module GoodData
421
510
  results: create_results + delete_results }
422
511
  end
423
512
 
424
- create_results = to_create.each_slice(100).flat_map do |batch|
425
- batch.pmapcat do |related_uri, group|
426
- group.each(&:save)
427
- res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
428
- items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
429
-
430
- payload = {
431
- 'userFilters' => {
432
- 'items' => [{
433
- 'user' => related_uri,
434
- 'userFilters' => items.concat(group.map(&:uri))
435
- }]
513
+ if to_create.empty?
514
+ create_results = []
515
+ else
516
+ create_results = to_create.each_slice(100).flat_map do |batch|
517
+ batch.pmapcat do |related_uri, group|
518
+ group.each(&:save)
519
+ res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
520
+ items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
521
+
522
+ payload = {
523
+ 'userFilters' => {
524
+ 'items' => [{
525
+ 'user' => related_uri,
526
+ 'userFilters' => items.concat(group.map(&:uri))
527
+ }]
528
+ }
436
529
  }
437
- }
438
- res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
530
+ res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
439
531
 
440
- # turn the errors from hashes into array of hashes
441
- update_result = res['userFiltersUpdateResult'].flat_map do |k, v|
442
- v.map { |r| { status: k.to_sym, user: r, type: :create } }
443
- end
532
+ # turn the errors from hashes into array of hashes
533
+ update_result = res['userFiltersUpdateResult'].flat_map do |k, v|
534
+ v.map { |r| { status: k.to_sym, user: r, type: :create } }
535
+ end
444
536
 
445
- update_result.map do |result|
446
- result[:status] == :failed ? result.merge(GoodData::Helpers.symbolize_keys(result[:user])) : result
537
+ update_result.map do |result|
538
+ result[:status] == :failed ? result.merge(GoodData::Helpers.symbolize_keys(result[:user])) : result
539
+ end
447
540
  end
448
541
  end
542
+ project_log_formatter.log_user_filter_results(create_results, to_create)
543
+ create_errors = create_results.select { |r| r[:status] == :failed }
544
+ fail "Creating MUFs resulted in errors: #{create_errors}" if create_errors.any?
449
545
  end
450
546
 
451
- project_log_formatter.log_user_filter_results(create_results, to_create)
452
- create_errors = create_results.select { |r| r[:status] == :failed }
453
- fail "Creating MUFs resulted in errors: #{create_errors}" if create_errors.any?
454
-
455
- delete_results = unless options[:do_not_touch_filters_that_are_not_mentioned]
456
- to_delete.each_slice(100).flat_map do |batch|
457
- batch.flat_map do |related_uri, group|
458
- results = []
459
- if related_uri
460
- res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
461
- items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
462
- payload = {
463
- 'userFilters' => {
464
- 'items' => [
465
- {
466
- 'user' => related_uri,
467
- 'userFilters' => items - group.map(&:uri)
468
- }
469
- ]
470
- }
471
- }
472
- res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
473
- results.concat(res['userFiltersUpdateResult']
547
+ if to_delete.empty?
548
+ delete_results = []
549
+ elsif !options[:do_not_touch_filters_that_are_not_mentioned]
550
+ delete_results = to_delete.each_slice(100).flat_map do |batch|
551
+ batch.flat_map do |related_uri, group|
552
+ results = []
553
+ if related_uri
554
+ res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
555
+ items = res['userFilters']['items'].empty? ? [] : res['userFilters']['items'].first['userFilters']
556
+ payload = {
557
+ 'userFilters' => {
558
+ 'items' => [
559
+ {
560
+ 'user' => related_uri,
561
+ 'userFilters' => items - group.map(&:uri)
562
+ }
563
+ ]
564
+ }
565
+ }
566
+ res = client.post("/gdc/md/#{project.pid}/userfilters", payload)
567
+ results.concat(res['userFiltersUpdateResult']
474
568
  .flat_map { |k, v| v.map { |r| { status: k.to_sym, user: r, type: :delete } } }
475
569
  .map { |result| result[:status] == :failed ? result.merge(GoodData::Helpers.symbolize_keys(result[:user])) : result })
476
- end
477
- group.peach(&:delete)
478
- results
479
- end
480
- end
481
- end
570
+ end
571
+ group.peach(&:delete)
572
+ results
573
+ end
482
574
 
483
- project_log_formatter.log_user_filter_results(delete_results, to_delete)
484
- delete_errors = delete_results.select { |r| r[:status] == :failed } if delete_results
485
- fail "Deleting MUFs resulted in errors: #{delete_errors}" if delete_errors && delete_errors.any?
575
+ project_log_formatter.log_user_filter_results(delete_results, to_delete)
576
+ delete_errors = delete_results.select { |r| r[:status] == :failed } if delete_results
577
+ fail "Deleting MUFs resulted in errors: #{delete_errors}" if delete_errors&.any?
578
+ end
579
+ end
486
580
 
487
581
  { created: to_create, deleted: to_delete, results: create_results + (delete_results || []) }
488
582
  end
@@ -494,7 +588,7 @@ module GoodData
494
588
  # @param file [String | Array] File or array of values to be parsed for filters
495
589
  # @param options [Hash] Filter definitions
496
590
  # @return [Array<Hash>]
497
- def self.get_values(file, options)
591
+ def self.get_values(file, options = {})
498
592
  file.is_a?(Array) ? read_array(file, options) : read_file(file, options)
499
593
  end
500
594
 
@@ -579,12 +673,12 @@ module GoodData
579
673
  # Removes MUFs from to_delete unless in user is in users_brick_input
580
674
  # if this does not happen, users that are about to be deleted by users_brick
581
675
  # would have all their filters removed now, which is not desirable
582
- def self.sanitize_filters_to_delete(to_delete, users_brick_input, project_users)
676
+ def self.sanitize_filters_to_delete(to_delete, users_brick_input, user_profile_mapping)
583
677
  return [] unless users_brick_input && users_brick_input.any?
584
678
  user_profiles = users_brick_input.map do |user|
585
- result = project_users.find { |u| u.login == user.with_indifferent_access['login'] }
679
+ result = user_profile_mapping[user.with_indifferent_access['login']]
586
680
  next unless result
587
- result.profile_url
681
+ result
588
682
  end.compact
589
683
  return [] unless user_profiles.any?
590
684
  to_delete.reject do |_, value|
@@ -68,6 +68,8 @@ module GoodData
68
68
  RETRY_TIME_COEFFICIENT = 1.5
69
69
  RETRYABLE_ERRORS << Net::ReadTimeout if Net.const_defined?(:ReadTimeout)
70
70
 
71
+ RETRYABLE_ERRORS << OpenSSL::SSL::SSLErrorWaitReadable if OpenSSL::SSL.const_defined?(:SSLErrorWaitReadable)
72
+
71
73
  class << self
72
74
  def construct_login_payload(username, password)
73
75
  res = {
@@ -304,12 +306,12 @@ module GoodData
304
306
  end
305
307
 
306
308
  def refresh_token(_options = {})
307
- begin # rubocop:disable RedundantBegin
309
+ begin # rubocop:disable Style/RedundantBegin
308
310
  # avoid infinite loop GET fails with 401
309
311
  response = get(TOKEN_PATH, :x_gdc_authsst => sst_token, :dont_reauth => true)
310
312
  # Remove when TT sent in headers. Currently we need to parse from body
311
313
  merge_headers!(:x_gdc_authtt => GoodData::Helpers.get_path(response, %w(userToken token)))
312
- rescue Exception => e # rubocop:disable RescueException
314
+ rescue Exception => e # rubocop:disable Style/RescueException
313
315
  raise e
314
316
  end
315
317
  end
@@ -688,7 +690,7 @@ ERR
688
690
  execution_id = request_id
689
691
 
690
692
  GoodData.gd_logger.update_store(domain, method, duration, endpoint)
691
- GoodData.gd_logger.add Logger::INFO, { endpoint: endpoint, duration: duration, domain: domain,
693
+ GoodData.gd_logger.add Logger::DEBUG, { endpoint: endpoint, duration: duration, domain: domain,
692
694
  execution_id: execution_id, time_stamp: time_stamp }, "rest_call"
693
695
  end
694
696
  end
@@ -82,6 +82,8 @@ module GoodData
82
82
 
83
83
  ['/gdc/internal/projects/{id}/objects/setPermissions', %r{/gdc/internal/projects/[^\/]+/objects/setPermissions}],
84
84
  ['/gdc/internal/projects/{id}/roles', %r{/gdc/internal/projects/[^\/]+/roles}],
85
+ ['/gdc/dataload/projects/{id}/modelMapping/datasets/bulk/upsert', %r{/gdc/dataload/projects/[^\/]+/modelMapping/datasets/bulk/upsert}],
86
+ ['/gdc/dataload/internal/projects/{id}/ldmLayout', %r{/gdc/dataload/internal/projects/[^\/]+/ldmLayout}],
85
87
  ['/gdc/md/{id}/variables/item/{id}', %r{/gdc/md/[^\/]+/variables/item/[\d]+}],
86
88
  ['/gdc/md/{id}/validate/task/{id}', %r{/gdc/md/[^\/]+/validate/task/[^\/]+}],
87
89
  ['/gdc/md/{id}/using2/{id}/{id}', %r{/gdc/md/[^\/]+/using2/[\d]+/[\d]+}],
data/lib/gooddata.rb CHANGED
@@ -37,5 +37,6 @@ require 'backports/2.1.0/array/to_h'
37
37
 
38
38
  # Helpers
39
39
  require 'gooddata/helpers/global_helpers'
40
+ require 'gooddata/lcm/helpers/check_helper'
40
41
 
41
42
  require 'active_support/core_ext/hash/compact' unless RUBY_VERSION >= '2.5'
@@ -0,0 +1,35 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ #
4
+ # Copyright (c) 2010-2022 GoodData Corporation. All rights reserved.
5
+ # This source code is licensed under the BSD-style license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ require 'pmap'
9
+ $pmap_default_thread_count = 20 # rubocop:disable GlobalVars
10
+
11
+ # GoodData Module
12
+ module GoodData
13
+ end
14
+
15
+ # Modules
16
+ require_relative 'gooddata/core/core'
17
+ require_relative 'gooddata/models/models'
18
+ require_relative 'gooddata/exceptions/exceptions'
19
+ require_relative 'gooddata/helpers/helpers'
20
+
21
+ # Files
22
+ require_relative 'gooddata/bricks/utils'
23
+ require_relative 'gooddata/bricks/brick'
24
+ require_relative 'gooddata/bricks/base_pipeline'
25
+ require_relative 'gooddata/bricks/middleware/base_middleware'
26
+ require_relative 'gooddata/bricks/middleware/bench_middleware'
27
+ require_relative 'gooddata/bricks/middleware/logger_middleware'
28
+ require_relative 'gooddata/bricks/middleware/decode_params_middleware'
29
+ require_relative 'gooddata/bricks/middleware/aws_middleware'
30
+ require_relative 'gooddata/bricks/middleware/dwh_middleware'
31
+ require_relative 'gooddata/bricks/middleware/bench_middleware'
32
+
33
+ # CSV Downloader
34
+ require_relative 'gooddata/core/logging'
35
+ require_relative 'gooddata/connection'
@@ -0,0 +1,6 @@
1
+ sonar.projectKey=gooddata-ruby
2
+ sonar.organization=gooddata-github
3
+ # Config scan necessary files/folder only
4
+ sonar.sources=bin,lib
5
+ sonar.tests=spec
6
+ sonar.exclusions=**/lib/templates/project/*.erb