gooddata 0.6.43 → 0.6.44
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +4 -4
- data/lib/gooddata/commands/datasets.rb +2 -2
- data/lib/gooddata/core/logging.rb +1 -1
- data/lib/gooddata/exceptions/maql_execution.rb +16 -0
- data/lib/gooddata/extensions/string.rb +3 -3
- data/lib/gooddata/helpers/global_helpers.rb +3 -3
- data/lib/gooddata/helpers/global_helpers_params.rb +1 -1
- data/lib/gooddata/lcm/lcm.rb +7 -9
- data/lib/gooddata/models/blueprint/blueprint_field.rb +2 -2
- data/lib/gooddata/models/blueprint/dataset_blueprint.rb +1 -1
- data/lib/gooddata/models/domain.rb +1 -1
- data/lib/gooddata/models/membership.rb +2 -2
- data/lib/gooddata/models/metadata.rb +1 -1
- data/lib/gooddata/models/metadata/dashboard.rb +1 -1
- data/lib/gooddata/models/metadata/folder.rb +10 -10
- data/lib/gooddata/models/process.rb +3 -5
- data/lib/gooddata/models/profile.rb +4 -4
- data/lib/gooddata/models/project.rb +17 -7
- data/lib/gooddata/models/project_creator.rb +30 -42
- data/lib/gooddata/models/report_data_result.rb +3 -3
- data/lib/gooddata/rest/client.rb +1 -1
- data/lib/gooddata/rest/connection.rb +85 -132
- data/lib/gooddata/version.rb +1 -1
- data/spec/environment/develop.rb +4 -4
- data/spec/integration/blueprint_updates_spec.rb +1 -1
- data/spec/integration/full_project_spec.rb +10 -7
- data/spec/integration/schedule_spec.rb +0 -2
- data/spec/logging_in_logging_out_spec.rb +2 -2
- data/spec/unit/models/project_creator_spec.rb +46 -98
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13caeda48d2131a8b475b6f40a499a4021781b9d
|
4
|
+
data.tar.gz: 3ae2f5d7baccbebc38f6b67ad36b0b84d534e8af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e8db72abb19850d4586c8f689bedb987ab6c48c8ea03bbce232192d46c0a331f37c9c30847e069446ac9be9479322e5b7eca348d7bee16592db8e8ae142b347
|
7
|
+
data.tar.gz: 12d7328f77bdb39ea6bc950f372dd67b1e0ffc7e6c2c655722cb05532961275814f1c9b92dae324c5eb25fc8820ff9b5922c77e07187da632042dcbc8844d9f4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# GoodData Ruby SDK Changelog
|
2
2
|
|
3
|
+
## 0.6.44
|
4
|
+
- Fixed the tests
|
5
|
+
- The MAQL execution now throws an exception if there is an error
|
6
|
+
- The authentication is made via tokens not cookies
|
7
|
+
|
3
8
|
## 0.6.26
|
4
9
|
- There is first implementation of transfering ETLs
|
5
10
|
- Fixed bug with getting clients from domain
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ The best documentation for the GoodData API can be found using these resources:
|
|
21
21
|
|
22
22
|
## Install
|
23
23
|
|
24
|
-
If you are using bundler
|
24
|
+
If you are using bundler, add
|
25
25
|
|
26
26
|
gem "gooddata"
|
27
27
|
|
@@ -43,13 +43,13 @@ If you are using gems just
|
|
43
43
|
future version unintentionally.
|
44
44
|
* Commit, do not mess with rakefile, version, or history.
|
45
45
|
(if you want to have your own version, that is fine but bump version in a commit by itself we can ignore when we pull)
|
46
|
-
* run `rake test` and make sure all tests
|
47
|
-
* run `rake cop` and make sure you did not
|
46
|
+
* run `rake test` and make sure all tests pass
|
47
|
+
* run `rake cop` and make sure you did not introduce any new coding rules issues
|
48
48
|
* Send us a pull request. Bonus points for topic branches.
|
49
49
|
|
50
50
|
## Credits
|
51
51
|
|
52
|
-
**
|
52
|
+
**Originally started by**
|
53
53
|
|
54
54
|
Pavel Kolesnikov [ <mailto:pavel@gooddata.com> / [@koles](http://twitter.com/koles) ]
|
55
55
|
|
@@ -77,7 +77,7 @@ module GoodData
|
|
77
77
|
|
78
78
|
fail(CommandFailed, "Usage: #{$PROGRAM_NAME} <dataset config>") unless cfg_file
|
79
79
|
config = begin
|
80
|
-
JSON.
|
80
|
+
JSON.parse open(cfg_file)
|
81
81
|
rescue
|
82
82
|
raise(CommandFailed, "Error reading dataset config file '#{cfg_file}'")
|
83
83
|
end
|
@@ -103,7 +103,7 @@ module GoodData
|
|
103
103
|
file, cfg_file = args
|
104
104
|
fail(CommandFailed, "Usage: #{$PROGRAM_NAME} datasets:load <file> <dataset config>") unless cfg_file
|
105
105
|
begin
|
106
|
-
config = JSON.
|
106
|
+
config = JSON.parse open(cfg_file)
|
107
107
|
rescue
|
108
108
|
raise(CommandFailed, "Error reading dataset config file '#{cfg_file}'")
|
109
109
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Copyright (c) 2010-2015 GoodData Corporation. All rights reserved.
|
4
|
+
# This source code is licensed under the BSD-style license found in the
|
5
|
+
# LICENSE file in the root directory of this source tree.
|
6
|
+
|
7
|
+
module GoodData
|
8
|
+
class MaqlExecutionError < RuntimeError
|
9
|
+
attr_accessor :data
|
10
|
+
|
11
|
+
def initialize(message, data)
|
12
|
+
super(message || 'Execution of maql failed')
|
13
|
+
@data = data
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class String
|
2
2
|
def to_b
|
3
3
|
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
4
|
-
return false if self == false ||
|
5
|
-
raise ArgumentError
|
4
|
+
return false if self == false || blank? || self =~ (/(false|f|no|n|0)$/i)
|
5
|
+
raise ArgumentError, "invalid value for Boolean: \"#{self}\""
|
6
6
|
end
|
7
|
-
end
|
7
|
+
end
|
@@ -265,7 +265,7 @@ module GoodData
|
|
265
265
|
# @param [Object] Something
|
266
266
|
# @return [Boolean] Returns true or false if the input is 'true' or true
|
267
267
|
def to_boolean(param)
|
268
|
-
|
268
|
+
param == 'true' || param == true ? true : false
|
269
269
|
end
|
270
270
|
|
271
271
|
# encrypts data with the given key. returns a binary data with the
|
@@ -283,10 +283,10 @@ module GoodData
|
|
283
283
|
Base64.encode64(random_iv + encrypted)
|
284
284
|
end
|
285
285
|
|
286
|
-
def decrypt(
|
286
|
+
def decrypt(database64, key)
|
287
287
|
return '' if key.nil? || key.empty?
|
288
288
|
|
289
|
-
data = Base64.decode64(
|
289
|
+
data = Base64.decode64(database64)
|
290
290
|
|
291
291
|
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
|
292
292
|
cipher.decrypt
|
@@ -26,7 +26,7 @@ module GoodData
|
|
26
26
|
def encode_params(params, data_key)
|
27
27
|
res = {}
|
28
28
|
nested = {}
|
29
|
-
core_types = [FalseClass,
|
29
|
+
core_types = [FalseClass, Integer, Float, NilClass, TrueClass, String]
|
30
30
|
params.each do |k, v|
|
31
31
|
if core_types.include?(v.class)
|
32
32
|
res[k] = v
|
data/lib/gooddata/lcm/lcm.rb
CHANGED
@@ -18,9 +18,9 @@ module GoodData
|
|
18
18
|
next if !filter_on_segment.empty? && !(filter_on_segment.include?(segment.id))
|
19
19
|
p = client.project
|
20
20
|
begin
|
21
|
-
p.create_users(migration_spec[:technical_user].map { |u| {login: u, role: 'admin'} })
|
21
|
+
p.create_users(migration_spec[:technical_user].map { |u| { login: u, role: 'admin' } })
|
22
22
|
rescue RestClient::Exception => e
|
23
|
-
messages << {type: :technical_user_addition, status: 'ERROR', message: e.message}
|
23
|
+
messages << { type: :technical_user_addition, status: 'ERROR', message: e.message }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -91,14 +91,12 @@ module GoodData
|
|
91
91
|
def transfer_label_types(source_project, targets)
|
92
92
|
semaphore = Mutex.new
|
93
93
|
|
94
|
-
synchronized_puts =
|
95
|
-
semaphore.synchronize {
|
96
|
-
puts args
|
97
|
-
}
|
94
|
+
synchronized_puts = proc do |*args|
|
95
|
+
semaphore.synchronize { puts args }
|
98
96
|
end
|
99
97
|
|
100
98
|
# Convert to array
|
101
|
-
targets = [targets] unless targets.
|
99
|
+
targets = [targets] unless targets.is_a?(Array)
|
102
100
|
|
103
101
|
client = source_project.client
|
104
102
|
|
@@ -126,10 +124,10 @@ module GoodData
|
|
126
124
|
# Transfer to target projects
|
127
125
|
targets.peach do |target|
|
128
126
|
transfer.peach do |identifier, type|
|
129
|
-
uri = GoodData::MdObject.identifier_to_uri({project: target, client: client}, identifier)
|
127
|
+
uri = GoodData::MdObject.identifier_to_uri({ project: target, client: client }, identifier)
|
130
128
|
next unless uri
|
131
129
|
|
132
|
-
obj = GoodData::MdObject[uri, {project: target, client: client}]
|
130
|
+
obj = GoodData::MdObject[uri, { project: target, client: client }]
|
133
131
|
|
134
132
|
if obj.content['type'] != type
|
135
133
|
synchronized_puts.call "Updating #{identifier} -> #{type} in #{target.title} - #{target.uri}"
|
@@ -401,7 +401,7 @@ module GoodData
|
|
401
401
|
#
|
402
402
|
# @return [Array] array of errors
|
403
403
|
def validate_some_anchors
|
404
|
-
find_columns_by_type(:anchor).count
|
404
|
+
find_columns_by_type(:anchor).count.zero? ? [{ type: :no_anchor, dataset: id }] : []
|
405
405
|
end
|
406
406
|
|
407
407
|
# Validate if the dataset does not have more than one anchor defined.
|
@@ -391,7 +391,7 @@ module GoodData
|
|
391
391
|
res = client.poll_on_code(res['asyncTask']['links']['poll'])
|
392
392
|
failed_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult failed count), 0)
|
393
393
|
created_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult created count), 0)
|
394
|
-
return Enumerator.new([]) if failed_count + created_count == 0
|
394
|
+
return Enumerator.new([]) if failed_count + created_count == 0 # rubocop:disable Style/NumericPredicate
|
395
395
|
Enumerator.new do |y|
|
396
396
|
uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult links details))
|
397
397
|
loop do
|
@@ -145,7 +145,7 @@ module GoodData
|
|
145
145
|
def deprecated=(flag)
|
146
146
|
if flag == '1' || flag == 1 || flag == true
|
147
147
|
meta['deprecated'] = '1'
|
148
|
-
elsif flag == '0' || flag == 0 || flag == false
|
148
|
+
elsif flag == '0' || flag == 0 || flag == false # rubocop:disable Style/NumericPredicate
|
149
149
|
meta['deprecated'] = '0'
|
150
150
|
else
|
151
151
|
fail 'You have to provide flag as either 1 or "1" or 0 or "0" or true/false'
|
@@ -53,7 +53,7 @@ module GoodData
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def create(dashboard = {}, options = { :client => GoodData.client, :project => GoodData.project })
|
56
|
-
client, project = GoodData.get_client_and_project(options)
|
56
|
+
client, project = GoodData.get_client_and_project(GoodData::Helpers.stringify_keys(options))
|
57
57
|
|
58
58
|
res = client.create(Dashboard, GoodData::Helpers.deep_dup(GoodData::Helpers.deep_stringify_keys(EMPTY_OBJECT)), :project => project)
|
59
59
|
dashboard.each do |k, v|
|
@@ -20,27 +20,27 @@ module GoodData
|
|
20
20
|
# @param options [Hash] the options hash
|
21
21
|
# @option options [Boolean] :full if passed true the subclass can decide to pull in full objects. This is desirable from the usability POV but unfortunately has negative impact on performance so it is not the default
|
22
22
|
# @return [Array<GoodData::MdObject> | Array<Hash>] Return the appropriate metadata objects or their representation
|
23
|
-
def all(options = {:client => GoodData.connection, :project => GoodData.project})
|
23
|
+
def all(options = { :client => GoodData.connection, :project => GoodData.project })
|
24
24
|
query('folder', Folder, options)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def entries
|
29
|
-
(
|
30
|
-
res = case
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
(json['folder']['content']['entries'] || []).pmap do |entry|
|
30
|
+
res = case json['folder']['content']['type'].first
|
31
|
+
when 'fact'
|
32
|
+
GoodData::Fact[entry['link'], :client => client, :project => project]
|
33
|
+
when 'metric'
|
34
|
+
GoodData::Metric[entry['link'], :client => client, :project => project]
|
35
|
+
else
|
36
|
+
GoodData::MdObject[entry['link'], :client => client, :project => project]
|
37
37
|
end
|
38
38
|
res
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
def type
|
43
|
-
|
43
|
+
json['folder']['content']['type'][0]
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -94,7 +94,7 @@ module GoodData
|
|
94
94
|
def deploy(path, options = { :client => GoodData.client, :project => GoodData.project })
|
95
95
|
return deploy_brick(path, options) if path.to_s.start_with?(APP_STORE_URL)
|
96
96
|
|
97
|
-
return deploy_from_appstore(path.to_s, options) if (path.to_s =~
|
97
|
+
return deploy_from_appstore(path.to_s, options) if (path.to_s =~ %r{\${.*}:(.*)\/(.*):\/}) == 0 # rubocop:disable Style/NumericPredicate
|
98
98
|
|
99
99
|
client, project = GoodData.get_client_and_project(options)
|
100
100
|
|
@@ -146,7 +146,7 @@ module GoodData
|
|
146
146
|
if ref
|
147
147
|
`git checkout #{ref}`
|
148
148
|
|
149
|
-
fail 'Wrong branch or tag specified!' if $CHILD_STATUS.to_i
|
149
|
+
fail 'Wrong branch or tag specified!' if $CHILD_STATUS.to_i.nonzero?
|
150
150
|
end
|
151
151
|
|
152
152
|
opts = {
|
@@ -167,7 +167,7 @@ module GoodData
|
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
170
|
-
def deploy_from_appstore(path, options = {:client => GoodData.client, :project => GoodData.project})
|
170
|
+
def deploy_from_appstore(path, options = { :client => GoodData.client, :project => GoodData.project })
|
171
171
|
client, project = GoodData.get_client_and_project(options)
|
172
172
|
|
173
173
|
deploy_name = options[:name]
|
@@ -203,8 +203,6 @@ module GoodData
|
|
203
203
|
puts HighLine.color("Deploy DONE #{path}", HighLine::GREEN) if verbose
|
204
204
|
process
|
205
205
|
end
|
206
|
-
|
207
|
-
# ----------------------------- Private Stuff
|
208
206
|
|
209
207
|
private
|
210
208
|
|
@@ -93,14 +93,14 @@ module GoodData
|
|
93
93
|
res
|
94
94
|
end
|
95
95
|
|
96
|
-
def diff(
|
97
|
-
x = diff_list([
|
96
|
+
def diff(item1, item2)
|
97
|
+
x = diff_list([item1], [item2])
|
98
98
|
return {} if x[:changed].empty?
|
99
99
|
x[:changed].first[:diff]
|
100
100
|
end
|
101
101
|
|
102
|
-
def diff_list(
|
103
|
-
GoodData::Helpers.diff(
|
102
|
+
def diff_list(list1, list2)
|
103
|
+
GoodData::Helpers.diff(list1, list2, key: :login)
|
104
104
|
end
|
105
105
|
|
106
106
|
# Gets user currently logged in
|
@@ -590,7 +590,13 @@ module GoodData
|
|
590
590
|
# @return [Array] Result of executing MAQLs
|
591
591
|
def delete_all_data(options = {})
|
592
592
|
return false unless options[:force]
|
593
|
-
|
593
|
+
begin
|
594
|
+
datasets.pmap(&:delete_data)
|
595
|
+
rescue MaqlExecutionError => e
|
596
|
+
# This is here so that we do not throw out exceptions on synchornizing date dimensions
|
597
|
+
# Currently there is no reliable way how to tell it is a date dimension
|
598
|
+
fail e unless GoodData::Helpers.interpolate_error_messages(e.data['wTaskStatus']['messages']) == ["Internal error [handle_exception, hide_internal]."]
|
599
|
+
end
|
594
600
|
end
|
595
601
|
|
596
602
|
# Deletes dashboards for project
|
@@ -627,9 +633,13 @@ module GoodData
|
|
627
633
|
response = client.post(ldm_uri, manage: { maql: maql })
|
628
634
|
polling_uri = response['entries'].first['link']
|
629
635
|
|
630
|
-
client.poll_on_response(polling_uri, options) do |body|
|
636
|
+
result = client.poll_on_response(polling_uri, options) do |body|
|
631
637
|
body && body['wTaskStatus'] && body['wTaskStatus']['status'] == 'RUNNING'
|
632
638
|
end
|
639
|
+
if result['wTaskStatus']['status'] == 'ERROR'
|
640
|
+
fail MaqlExecutionError.new("Executionof MAQL '#{maql}' failed in project '#{pid}'", result)
|
641
|
+
end
|
642
|
+
result
|
633
643
|
end
|
634
644
|
|
635
645
|
# Helper for getting facts of a project
|
@@ -749,11 +759,11 @@ module GoodData
|
|
749
759
|
alias_method :member, :get_user
|
750
760
|
|
751
761
|
def find_by_tag(tags)
|
752
|
-
tags = tags.split(',').map(&:strip) unless tags.
|
762
|
+
tags = tags.split(',').map(&:strip) unless tags.is_a?(Array)
|
753
763
|
|
754
764
|
objects = tags.map do |tag|
|
755
|
-
url = "/gdc/md/#{
|
756
|
-
res =
|
765
|
+
url = "/gdc/md/#{pid}/tags/#{tag}"
|
766
|
+
res = client.get(url)
|
757
767
|
|
758
768
|
((res || {})['entries'] || []).map do |entry|
|
759
769
|
entry['link']
|
@@ -818,7 +828,7 @@ module GoodData
|
|
818
828
|
puts "Inviting #{email}, role: #{role}"
|
819
829
|
|
820
830
|
role_url = nil
|
821
|
-
if role.index('/gdc/')
|
831
|
+
if role.index('/gdc/').nonzero?
|
822
832
|
tmp = get_role(role)
|
823
833
|
role_url = tmp.uri if tmp
|
824
834
|
else
|
@@ -1491,7 +1501,7 @@ module GoodData
|
|
1491
1501
|
client.post("#{uri}/users", 'users' => payload)
|
1492
1502
|
end
|
1493
1503
|
# this ugly line turns the hash of errors into list of errors with types so we can process them easily
|
1494
|
-
typed_results = results.flat_map { |x| x['projectUsersUpdateResult'].flat_map { |k, v| v.map { |
|
1504
|
+
typed_results = results.flat_map { |x| x['projectUsersUpdateResult'].flat_map { |k, v| v.map { |v2| v2.is_a?(String) ? { type: k.to_sym, user: v2 } : GoodData::Helpers.symbolize_keys(v2).merge(type: k.to_sym) } } }
|
1495
1505
|
# we have to concat errors from role resolution and API result
|
1496
1506
|
typed_results + (users_by_type[:failed] || [])
|
1497
1507
|
end
|
@@ -39,58 +39,36 @@ module GoodData
|
|
39
39
|
def migrate_datasets(spec, opts = {})
|
40
40
|
opts = { client: GoodData.connection }.merge(opts)
|
41
41
|
dry_run = opts[:dry_run]
|
42
|
+
replacements = opts['maql_replacements'] || opts[:maql_replacements] || {}
|
42
43
|
|
43
44
|
client, project = GoodData.get_client_and_project(opts)
|
44
45
|
|
45
46
|
bp = ProjectBlueprint.new(spec)
|
47
|
+
|
46
48
|
uri = "/gdc/projects/#{project.pid}/model/diff?includeGrain=true"
|
47
49
|
result = client.post(uri, bp.to_wire)
|
50
|
+
response = client.poll_on_code(result['asyncTask']['link']['poll'])
|
48
51
|
|
49
|
-
link = result['asyncTask']['link']['poll']
|
50
|
-
response = client.get(link, :process => false)
|
51
|
-
|
52
|
-
while response.code != 200
|
53
|
-
sleep 1
|
54
|
-
GoodData::Rest::Client.retryable(:tries => 3) do
|
55
|
-
sleep 1
|
56
|
-
response = client.get(link, :process => false)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
response = client.get(link)
|
61
|
-
|
62
|
-
errors = []
|
63
52
|
maqls = pick_correct_chunks(response['projectModelDiff']['updateScripts'], opts)
|
64
|
-
|
65
|
-
|
53
|
+
replaced_maqls = apply_replacements_on_maql(maqls, replacements)
|
54
|
+
|
55
|
+
unless dry_run
|
56
|
+
errors = []
|
57
|
+
replaced_maqls.each do |replaced_maql_chunks|
|
66
58
|
begin
|
67
|
-
|
68
|
-
chunks.each do |chunk|
|
69
|
-
# TODO: Hack the MAQL here
|
70
|
-
(opts[:maql_replacements] || opts['maql_replacements'] || {}).each do |k, v|
|
71
|
-
src = Regexp.new(k)
|
72
|
-
dest = v
|
73
|
-
chunk.gsub!(src, dest)
|
74
|
-
end
|
75
|
-
|
76
|
-
puts chunk
|
77
|
-
|
78
|
-
result = project.execute_maql(chunk)
|
79
|
-
if result['wTaskStatus']['status'] == 'ERROR'
|
80
|
-
puts JSON.pretty_generate(result)
|
81
|
-
fail 'Creating dataset failed'
|
82
|
-
end
|
83
|
-
end
|
84
|
-
return chunks
|
59
|
+
replaced_maql_chunks['updateScript']['maqlDdlChunks'].each { |chunk| project.execute_maql(chunk) }
|
85
60
|
rescue => e
|
86
|
-
puts "Error occured when executing MAQL, project: \"#{project.title}\" reason: \"#{e.message}\", chunks: #{
|
61
|
+
puts "Error occured when executing MAQL, project: \"#{project.title}\" reason: \"#{e.message}\", chunks: #{replaced_maql_chunks.inspect}"
|
87
62
|
errors << e
|
88
63
|
next
|
89
64
|
end
|
90
65
|
end
|
91
|
-
|
92
|
-
|
66
|
+
if errors.length == replaced_maqls.length
|
67
|
+
messages = errors.map { |e| GoodData::Helpers.interpolate_error_messages(e.data['wTaskStatus']['messages']) }
|
68
|
+
fail "Unable to migrate LDM, reason(s): \n #{messages.join("\n")}"
|
69
|
+
end
|
93
70
|
end
|
71
|
+
replaced_maqls
|
94
72
|
end
|
95
73
|
|
96
74
|
def migrate_reports(project, spec)
|
@@ -130,7 +108,7 @@ module GoodData
|
|
130
108
|
end
|
131
109
|
|
132
110
|
def pick_correct_chunks(chunks, opts = {})
|
133
|
-
preference = opts[:update_preference]
|
111
|
+
preference = GoodData::Helpers.symbolize_keys(opts[:update_preference] || {})
|
134
112
|
|
135
113
|
# first is cascadeDrops, second is preserveData
|
136
114
|
rules = [
|
@@ -150,14 +128,24 @@ module GoodData
|
|
150
128
|
|
151
129
|
results = GoodData::Helpers.join(rules, stuff, [:cascade_drops, :preserve_data], [:cascade_drops, :preserve_data], inner: true).sort_by { |l| l[:priority] } || []
|
152
130
|
|
153
|
-
|
131
|
+
preference.each do |k, v|
|
154
132
|
results = results.find_all do |result|
|
155
|
-
|
156
|
-
!result.has_key?(sym) || result[sym] == v
|
133
|
+
result[k] == v
|
157
134
|
end
|
158
135
|
end
|
136
|
+
(preference.empty? ? [results.first].compact : results).map { |result| result[:orig] }
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
159
140
|
|
160
|
-
|
141
|
+
def apply_replacements_on_maql(maqls, replacements = {})
|
142
|
+
maqls.map do |maql|
|
143
|
+
GoodData::Helpers.deep_dup(maql).tap do |m|
|
144
|
+
m['updateScript']['maqlDdlChunks'] = m['updateScript']['maqlDdlChunks'].map do |chunk|
|
145
|
+
replacements.reduce(chunk) { |a, (k, v)| a.gsub(Regexp.new(k), v) }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
161
149
|
end
|
162
150
|
end
|
163
151
|
end
|