gooddata 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/.gdc-ii-config.yaml +42 -1
  3. data/.github/workflows/build.yml +14 -13
  4. data/.github/workflows/pre-merge.yml +13 -13
  5. data/.pronto.yml +1 -0
  6. data/.rubocop.yml +2 -14
  7. data/CHANGELOG.md +9 -0
  8. data/Dockerfile +13 -7
  9. data/Dockerfile.jruby +5 -5
  10. data/Dockerfile.ruby +5 -7
  11. data/Gemfile +4 -2
  12. data/README.md +5 -4
  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/mysql/pom.xml +6 -1
  18. data/ci/redshift/pom.xml +3 -4
  19. data/docker-compose.lcm.yml +42 -1
  20. data/docker-compose.yml +42 -0
  21. data/gooddata.gemspec +21 -22
  22. data/lcm.rake +9 -0
  23. data/lib/gooddata/bricks/base_pipeline.rb +26 -0
  24. data/lib/gooddata/bricks/brick.rb +0 -1
  25. data/lib/gooddata/bricks/middleware/execution_result_middleware.rb +3 -3
  26. data/lib/gooddata/bricks/pipeline.rb +2 -14
  27. data/lib/gooddata/cloud_resources/mysql/mysql_client.rb +18 -8
  28. data/lib/gooddata/cloud_resources/redshift/drivers/.gitkeepme +0 -0
  29. data/lib/gooddata/cloud_resources/redshift/redshift_client.rb +0 -2
  30. data/lib/gooddata/cloud_resources/snowflake/snowflake_client.rb +1 -1
  31. data/lib/gooddata/lcm/actions/base_action.rb +157 -0
  32. data/lib/gooddata/lcm/actions/collect_data_product.rb +2 -1
  33. data/lib/gooddata/lcm/actions/collect_projects_warning_status.rb +53 -0
  34. data/lib/gooddata/lcm/actions/collect_segment_clients.rb +14 -0
  35. data/lib/gooddata/lcm/actions/initialize_continue_on_error_option.rb +87 -0
  36. data/lib/gooddata/lcm/actions/migrate_gdc_date_dimension.rb +28 -2
  37. data/lib/gooddata/lcm/actions/provision_clients.rb +34 -5
  38. data/lib/gooddata/lcm/actions/synchronize_cas.rb +24 -4
  39. data/lib/gooddata/lcm/actions/synchronize_clients.rb +56 -4
  40. data/lib/gooddata/lcm/actions/synchronize_dataset_mappings.rb +28 -3
  41. data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +48 -11
  42. data/lib/gooddata/lcm/actions/synchronize_kd_dashboard_permission.rb +103 -0
  43. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +60 -15
  44. data/lib/gooddata/lcm/actions/synchronize_ldm_layout.rb +98 -0
  45. data/lib/gooddata/lcm/actions/synchronize_pp_dashboard_permission.rb +108 -0
  46. data/lib/gooddata/lcm/actions/synchronize_schedules.rb +31 -1
  47. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +14 -9
  48. data/lib/gooddata/lcm/actions/synchronize_user_groups.rb +30 -4
  49. data/lib/gooddata/lcm/actions/synchronize_users.rb +11 -10
  50. data/lib/gooddata/lcm/actions/update_metric_formats.rb +21 -4
  51. data/lib/gooddata/lcm/exceptions/lcm_execution_warning.rb +15 -0
  52. data/lib/gooddata/lcm/helpers/check_helper.rb +19 -0
  53. data/lib/gooddata/lcm/lcm2.rb +45 -4
  54. data/lib/gooddata/lcm/user_bricks_helper.rb +9 -0
  55. data/lib/gooddata/mixins/inspector.rb +1 -1
  56. data/lib/gooddata/models/ldm_layout.rb +38 -0
  57. data/lib/gooddata/models/project.rb +197 -22
  58. data/lib/gooddata/models/project_creator.rb +83 -6
  59. data/lib/gooddata/models/segment.rb +2 -1
  60. data/lib/gooddata/models/user_filters/user_filter_builder.rb +104 -15
  61. data/lib/gooddata/rest/connection.rb +5 -3
  62. data/lib/gooddata/rest/phmap.rb +1 -0
  63. data/lib/gooddata.rb +1 -0
  64. data/lib/gooddata_brick_base.rb +35 -0
  65. data/sonar-project.properties +6 -0
  66. metadata +64 -59
  67. data/lib/gooddata/cloud_resources/redshift/drivers/log4j.properties +0 -15
@@ -39,6 +39,9 @@ module GoodData
39
39
  opts = { client: GoodData.connection }.merge(opts)
40
40
  dry_run = opts[:dry_run]
41
41
  replacements = opts['maql_replacements'] || opts[:maql_replacements] || {}
42
+ update_preference = opts[:update_preference]
43
+ exist_fallback_to_hard_sync_config = !update_preference.nil? && !update_preference[:fallback_to_hard_sync].nil?
44
+ include_maql_fallback_hard_sync = exist_fallback_to_hard_sync_config && GoodData::Helpers.to_boolean(update_preference[:fallback_to_hard_sync])
42
45
 
43
46
  _, project = GoodData.get_client_and_project(opts)
44
47
 
@@ -48,6 +51,7 @@ module GoodData
48
51
  maql_diff_params = [:includeGrain]
49
52
  maql_diff_params << :excludeFactRule if opts[:exclude_fact_rule]
50
53
  maql_diff_params << :includeDeprecated if opts[:include_deprecated]
54
+ maql_diff_params << :includeMaqlFallbackHardSync if include_maql_fallback_hard_sync
51
55
 
52
56
  maql_diff_time = Benchmark.realtime do
53
57
  response = project.maql_diff(blueprint: bp, params: maql_diff_params)
@@ -62,7 +66,7 @@ module GoodData
62
66
  ca_maql = response['projectModelDiff']['computedAttributesScript'] if response['projectModelDiff']['computedAttributesScript']
63
67
  ca_chunks = ca_maql && ca_maql['maqlDdlChunks']
64
68
 
65
- maqls = pick_correct_chunks(chunks, opts)
69
+ maqls = include_maql_fallback_hard_sync ? pick_correct_chunks_hard_sync(chunks, opts) : pick_correct_chunks(chunks, opts)
66
70
  replaced_maqls = apply_replacements_on_maql(maqls, replacements)
67
71
  apply_maqls(ca_chunks, project, replaced_maqls, opts) unless dry_run
68
72
  [replaced_maqls, ca_maql]
@@ -72,9 +76,11 @@ module GoodData
72
76
  errors = []
73
77
  replaced_maqls.each do |replaced_maql_chunks|
74
78
  begin
79
+ fallback_hard_sync = replaced_maql_chunks['updateScript']['fallbackHardSync'].nil? ? false : replaced_maql_chunks['updateScript']['fallbackHardSync']
75
80
  replaced_maql_chunks['updateScript']['maqlDdlChunks'].each do |chunk|
76
81
  GoodData.logger.debug(chunk)
77
- project.execute_maql(chunk)
82
+ execute_maql_result = project.execute_maql(chunk)
83
+ process_fallback_hard_sync_result(execute_maql_result, project) if fallback_hard_sync
78
84
  end
79
85
  rescue => e
80
86
  GoodData.logger.error("Error occured when executing MAQL, project: \"#{project.title}\" reason: \"#{e.message}\", chunks: #{replaced_maql_chunks.inspect}")
@@ -140,8 +146,8 @@ module GoodData
140
146
  preference = Hash[preference.map { |k, v| [k, GoodData::Helpers.to_boolean(v)] }]
141
147
 
142
148
  # will use new parameters instead of the old ones
143
- if preference.empty? || [:allow_cascade_drops, :keep_data].any? { |k| preference.key?(k) }
144
- if [:cascade_drops, :preserve_data].any? { |k| preference.key?(k) }
149
+ if preference.empty? || %i[allow_cascade_drops keep_data].any? { |k| preference.key?(k) }
150
+ if %i[cascade_drops preserve_data].any? { |k| preference.key?(k) }
145
151
  fail "Please do not mix old parameters (:cascade_drops, :preserve_data) with the new ones (:allow_cascade_drops, :keep_data)."
146
152
  end
147
153
  preference = { allow_cascade_drops: false, keep_data: true }.merge(preference)
@@ -174,8 +180,8 @@ module GoodData
174
180
  results_from_api = GoodData::Helpers.join(
175
181
  rules,
176
182
  stuff,
177
- [:cascade_drops, :preserve_data],
178
- [:cascade_drops, :preserve_data],
183
+ %i[cascade_drops preserve_data],
184
+ %i[cascade_drops preserve_data],
179
185
  inner: true
180
186
  ).sort_by { |l| l[:priority] } || []
181
187
 
@@ -204,6 +210,53 @@ module GoodData
204
210
  end
205
211
  end
206
212
 
213
+ def pick_correct_chunks_hard_sync(chunks, opts = {})
214
+ preference = GoodData::Helpers.symbolize_keys(opts[:update_preference] || {})
215
+ preference = Hash[preference.map { |k, v| [k, GoodData::Helpers.to_boolean(v)] }]
216
+
217
+ # Old configure using cascade_drops and preserve_data parameters. New configure using allow_cascade_drops and
218
+ # keep_data parameters. Need translate from new configure to old configure before processing
219
+ if preference.empty? || %i[allow_cascade_drops keep_data].any? { |k| preference.key?(k) }
220
+ if %i[cascade_drops preserve_data].any? { |k| preference.key?(k) }
221
+ fail "Please do not mix old parameters (:cascade_drops, :preserve_data) with the new ones (:allow_cascade_drops, :keep_data)."
222
+ end
223
+
224
+ # Default allow_cascade_drops=false and keep_data=true
225
+ preference = { allow_cascade_drops: false, keep_data: true }.merge(preference)
226
+
227
+ new_preference = {}
228
+ new_preference[:cascade_drops] = preference[:allow_cascade_drops]
229
+ new_preference[:preserve_data] = preference[:keep_data]
230
+ preference = new_preference
231
+ end
232
+ preference[:fallback_to_hard_sync] = true
233
+
234
+ # Filter chunk with fallbackHardSync = true
235
+ result = chunks.select do |chunk|
236
+ chunk['updateScript']['maqlDdlChunks'] && !chunk['updateScript']['fallbackHardSync'].nil? && chunk['updateScript']['fallbackHardSync']
237
+ end
238
+
239
+ # The API model/diff only returns one result for MAQL fallback hard synchronize
240
+ result = pick_chunks_hard_sync(result[0], preference) if !result.nil? && !result.empty?
241
+
242
+ if result.nil? || result.empty?
243
+ available_chunks = chunks
244
+ .map do |chunk|
245
+ {
246
+ cascade_drops: chunk['updateScript']['cascadeDrops'],
247
+ preserve_data: chunk['updateScript']['preserveData'],
248
+ fallback_hard_sync: chunk['updateScript']['fallbackHardSync'].nil? ? false : chunk['updateScript']['fallbackHardSync']
249
+ }
250
+ end
251
+ .map(&:to_s)
252
+ .join(', ')
253
+
254
+ fail "Synchronize LDM cannot proceed. Adjust your update_preferences and try again. Available chunks with preference: #{available_chunks}"
255
+ end
256
+
257
+ result
258
+ end
259
+
207
260
  private
208
261
 
209
262
  def apply_replacements_on_maql(maqls, replacements = {})
@@ -215,6 +268,30 @@ module GoodData
215
268
  end
216
269
  end
217
270
  end
271
+
272
+ # Fallback hard synchronize although execute result success but some cases there are errors during executing.
273
+ # In this cases, then export the errors to execution log as warning
274
+ def process_fallback_hard_sync_result(result, project)
275
+ messages = result['wTaskStatus']['messages']
276
+ if !messages.nil? && messages.size.positive?
277
+ warning_message = GoodData::Helpers.interpolate_error_messages(messages)
278
+ log_message = "Project #{project.pid} failed to preserve data, truncated data of some datasets. MAQL diff execution messages: \"#{warning_message}\""
279
+ GoodData.logger.warn(log_message)
280
+ end
281
+ end
282
+
283
+ # In case fallback hard synchronize, then the API model/diff only returns one result with preserve_data is always false and
284
+ # cascade_drops is true or false. So pick chunk for fallback hard synchronize, we will ignore the preserve_data parameter
285
+ # and only check the cascade_drops parameter in preference.
286
+ def pick_chunks_hard_sync(chunk, preference)
287
+ # Make sure default values for cascade_drops
288
+ working_preference = { cascade_drops: false }.merge(preference)
289
+ if working_preference[:cascade_drops] || chunk['updateScript']['cascadeDrops'] == working_preference[:cascade_drops]
290
+ [chunk]
291
+ else
292
+ []
293
+ end
294
+ end
218
295
  end
219
296
  end
220
297
  end
@@ -257,7 +257,8 @@ module GoodData
257
257
  res = client.poll_on_code(res['asyncTask']['links']['poll'])
258
258
  failed_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult failed count), 0)
259
259
  created_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult created count), 0)
260
- return Enumerator.new([]) if (failed_count + created_count).zero?
260
+ return [].to_enum if (failed_count + created_count).zero?
261
+
261
262
  Enumerator.new do |y|
262
263
  uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult links details))
263
264
  loop do
@@ -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
@@ -210,13 +228,23 @@ module GoodData
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")
@@ -499,7 +588,7 @@ module GoodData
499
588
  # @param file [String | Array] File or array of values to be parsed for filters
500
589
  # @param options [Hash] Filter definitions
501
590
  # @return [Array<Hash>]
502
- def self.get_values(file, options)
591
+ def self.get_values(file, options = {})
503
592
  file.is_a?(Array) ? read_array(file, options) : read_file(file, options)
504
593
  end
505
594
 
@@ -584,12 +673,12 @@ module GoodData
584
673
  # Removes MUFs from to_delete unless in user is in users_brick_input
585
674
  # if this does not happen, users that are about to be deleted by users_brick
586
675
  # would have all their filters removed now, which is not desirable
587
- 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)
588
677
  return [] unless users_brick_input && users_brick_input.any?
589
678
  user_profiles = users_brick_input.map do |user|
590
- result = project_users.find { |u| u.login == user.with_indifferent_access['login'] }
679
+ result = user_profile_mapping[user.with_indifferent_access['login']]
591
680
  next unless result
592
- result.profile_url
681
+ result
593
682
  end.compact
594
683
  return [] unless user_profiles.any?
595
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
@@ -83,6 +83,7 @@ module GoodData
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
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}],
86
87
  ['/gdc/md/{id}/variables/item/{id}', %r{/gdc/md/[^\/]+/variables/item/[\d]+}],
87
88
  ['/gdc/md/{id}/validate/task/{id}', %r{/gdc/md/[^\/]+/validate/task/[^\/]+}],
88
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