gooddata 0.6.25 → 0.6.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Rakefile +1 -1
- data/gooddata.gemspec +1 -1
- data/lib/gooddata/cli/commands/domain_cmd.rb +28 -0
- data/lib/gooddata/cli/commands/project_cmd.rb +8 -0
- data/lib/gooddata/commands/domain.rb +10 -2
- data/lib/gooddata/commands/project.rb +21 -1
- data/lib/gooddata/helpers/global_helpers.rb +12 -2
- data/lib/gooddata/models/client.rb +18 -14
- data/lib/gooddata/models/domain.rb +26 -10
- data/lib/gooddata/models/membership.rb +11 -0
- data/lib/gooddata/models/metadata/dashboard.rb +1 -1
- data/lib/gooddata/models/metadata/label.rb +33 -15
- data/lib/gooddata/models/process.rb +49 -3
- data/lib/gooddata/models/profile.rb +1 -0
- data/lib/gooddata/models/project.rb +145 -1
- data/lib/gooddata/models/schedule.rb +22 -6
- data/lib/gooddata/models/segment.rb +9 -0
- data/lib/gooddata/version.rb +1 -1
- data/spec/environment/develop.rb +3 -3
- data/spec/integration/clients_spec.rb +5 -5
- data/spec/integration/full_process_schedule_spec.rb +27 -0
- data/spec/integration/schedule_spec.rb +35 -36
- data/spec/unit/models/profile_spec.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2127d4270e7e7ca7cb11b464bc50764279bccdf8
|
4
|
+
data.tar.gz: 3422d4671cd05b67654483c2d05528935f5c19c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0de341f4966e2955cc650c06ab6af2ae0d4e14d74a995d165bb9b62c72a1f32391691052d80687be74dc84694d93070114fd99460295b72957bff3614a95b69a
|
7
|
+
data.tar.gz: bdcc154ca1a135aaa194f6f6bca3697c1cbef5deb95e8c38eb3220c2b0d71e15367d727ebdd6a221a3fa729cc88acf19d18ffe106af743601e2fd59bc1a944ba
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# GoodData Ruby SDK Changelog
|
2
2
|
|
3
|
+
## 0.6.26
|
4
|
+
- There is first implementation of transfering ETLs
|
5
|
+
- Fixed bug with getting clients from domain
|
6
|
+
- Temporary workaround for problem on API when it fails with 500 when you are trying to read changes of provision clients when nothing was provisioned
|
7
|
+
- Added option to not delete projects when updating clients in segments
|
8
|
+
|
3
9
|
## 0.6.24
|
4
10
|
- Fixed problem with validElements causing 500
|
5
11
|
|
data/Rakefile
CHANGED
data/gooddata.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.homepage = 'http://github.com/gooddata/gooddata-ruby'
|
28
28
|
s.require_paths = ['lib']
|
29
29
|
|
30
|
-
s.add_development_dependency 'bundler'
|
30
|
+
s.add_development_dependency 'bundler'
|
31
31
|
s.add_development_dependency 'debase', '~> 0.1', '>= 0.1.7' if !ENV['TRAVIS_BUILD'] && RUBY_VERSION >= '2.0.0'
|
32
32
|
s.add_development_dependency 'guard', '~> 2.13', '>= 2.13.0'
|
33
33
|
s.add_development_dependency 'guard-rspec', '~> 4.6', '>= 4.6.4'
|
@@ -0,0 +1,28 @@
|
|
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
|
+
require 'pathname'
|
8
|
+
require 'pp'
|
9
|
+
|
10
|
+
require_relative '../shared'
|
11
|
+
require_relative '../../commands/domain'
|
12
|
+
|
13
|
+
module GoodData
|
14
|
+
module CLI
|
15
|
+
desc 'Manage your domain'
|
16
|
+
arg_name 'domain_command'
|
17
|
+
|
18
|
+
command :domain do |c|
|
19
|
+
c.desc 'Shows users in domain'
|
20
|
+
c.command :users do |users|
|
21
|
+
users.action do |global_options, options, args|
|
22
|
+
opts = options.merge(global_options)
|
23
|
+
GoodData::Command::Domain.list_users(args[0], opts)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -24,6 +24,14 @@ module GoodData
|
|
24
24
|
GoodData::Command::Project.jack_in(opts)
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
c.desc 'Shows users in project'
|
29
|
+
c.command :users do |users|
|
30
|
+
users.action do |global_options, options, _args|
|
31
|
+
opts = options.merge(global_options)
|
32
|
+
GoodData::Command::Project.list_users(opts)
|
33
|
+
end
|
34
|
+
end
|
27
35
|
end
|
28
36
|
|
29
37
|
desc 'If you are in a gooddata project blueprint or if you provide a project id it will start an interactive session inside that project'
|
@@ -23,8 +23,16 @@ module GoodData
|
|
23
23
|
GoodData::Domain.add_user(data.merge(opts))
|
24
24
|
end
|
25
25
|
|
26
|
-
def list_users(
|
27
|
-
GoodData
|
26
|
+
def list_users(domain_name, options = { :client => GoodData.connection })
|
27
|
+
client = GoodData.connect(options)
|
28
|
+
domain = client.domain(domain_name)
|
29
|
+
|
30
|
+
rows = domain.users.to_a.map do |user|
|
31
|
+
[user.email, user.full_name]
|
32
|
+
end
|
33
|
+
|
34
|
+
table = Terminal::Table.new :headings => ['Email', 'Full Name'], :rows => rows
|
35
|
+
puts table
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
@@ -5,6 +5,9 @@
|
|
5
5
|
# LICENSE file in the root directory of this source tree.
|
6
6
|
|
7
7
|
require 'pathname'
|
8
|
+
require 'terminal-table'
|
9
|
+
|
10
|
+
require_relative '../connection'
|
8
11
|
|
9
12
|
module GoodData
|
10
13
|
module Command
|
@@ -146,9 +149,26 @@ module GoodData
|
|
146
149
|
# @param project_id [String | GoodData::Project] Project id or project instance to list the users in
|
147
150
|
# @return [Array <GoodData::Membership>] List of project users
|
148
151
|
def users(project_id, options = { client: GoodData.connection })
|
149
|
-
client = options[:client]
|
152
|
+
client = options[:client] || GoodData.connect(options)
|
150
153
|
client.with_project(project_id, &:users)
|
151
154
|
end
|
155
|
+
|
156
|
+
# Lists users in a project
|
157
|
+
#
|
158
|
+
# @param options [Hash] List of users
|
159
|
+
#
|
160
|
+
# TODO: Review and refactor #users & #list_users
|
161
|
+
def list_users(options = { client: GoodData.connection })
|
162
|
+
client = GoodData.connect(options)
|
163
|
+
project = client.projects(options[:project_id])
|
164
|
+
|
165
|
+
rows = project.users.to_a.map do |user|
|
166
|
+
[user.email, user.full_name, user.role.title, user.user_groups.join(', ')]
|
167
|
+
end
|
168
|
+
|
169
|
+
table = Terminal::Table.new :headings => ['Email', 'Full Name', 'Role', 'Groups'], :rows => rows
|
170
|
+
puts table
|
171
|
+
end
|
152
172
|
end
|
153
173
|
end
|
154
174
|
end
|
@@ -63,10 +63,12 @@ module GoodData
|
|
63
63
|
mapping.pmap { |f, t| [project.objects(f), project.objects(t)] }
|
64
64
|
end
|
65
65
|
|
66
|
-
def get_path(an_object, path = [])
|
66
|
+
def get_path(an_object, path = [], default = nil)
|
67
67
|
return an_object if path.empty?
|
68
|
+
return default if an_object.nil?
|
69
|
+
|
68
70
|
path.reduce(an_object) do |a, e|
|
69
|
-
a && a.key?(e) ? a[e] :
|
71
|
+
a && a.key?(e) ? a[e] : default
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
@@ -258,6 +260,14 @@ module GoodData
|
|
258
260
|
m.times.map { n.times.map { val } }
|
259
261
|
end
|
260
262
|
|
263
|
+
# Turns a boolean or string 'true' into boolean. Useful for bricks.
|
264
|
+
#
|
265
|
+
# @param [Object] Something
|
266
|
+
# @return [Boolean] Returns true or false if the input is 'true' or true
|
267
|
+
def to_boolean(param)
|
268
|
+
(param == 'true' || param == true) ? true : false
|
269
|
+
end
|
270
|
+
|
261
271
|
# encrypts data with the given key. returns a binary data with the
|
262
272
|
# unhashed random iv in the first 16 bytes
|
263
273
|
def encrypt(data, key)
|
@@ -38,23 +38,27 @@ module GoodData
|
|
38
38
|
client = domain.client
|
39
39
|
fail ArgumentError, 'No client specified' if client.nil?
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
41
|
+
if id == :all
|
42
|
+
tenants_uri = domain.segments_uri + "/clients?segment=#{CGI.escape(segment.segment_id)}"
|
43
|
+
Enumerator.new do |y|
|
44
|
+
loop do
|
45
|
+
res = client.get tenants_uri
|
46
|
+
res['clients']['paging']['next']
|
47
|
+
res['clients']['items'].each do |i|
|
48
|
+
p = i['client']['project']
|
49
|
+
tenant = client.create(GoodData::Client, i.merge('domain' => domain))
|
50
|
+
tenant.project = p
|
51
|
+
y << tenant
|
52
|
+
end
|
53
|
+
url = res['clients']['paging']['next']
|
54
|
+
break unless url
|
52
55
|
end
|
53
|
-
url = res['clients']['paging']['next']
|
54
|
-
break unless url
|
55
56
|
end
|
57
|
+
else
|
58
|
+
id = id.respond_to?(:client_id) ? id.client_id : id
|
59
|
+
data = client.get(domain.segments_uri + "/clients/#{CGI.escape(id)}")
|
60
|
+
client.create(GoodData::Client, data.merge('domain' => domain))
|
56
61
|
end
|
57
|
-
id == :all ? e : e.first
|
58
62
|
end
|
59
63
|
|
60
64
|
# Creates new client from parameters passed
|
@@ -186,7 +186,7 @@ module GoodData
|
|
186
186
|
url = "#{domain.uri}/users?login=#{escaped_login}"
|
187
187
|
tmp = c.get url
|
188
188
|
items = tmp['accountSettings']['items'] if tmp['accountSettings']
|
189
|
-
items && items.
|
189
|
+
items && !items.empty? ? c.factory.create(GoodData::Profile, items.first) : nil
|
190
190
|
end
|
191
191
|
|
192
192
|
# Returns list of users for domain specified
|
@@ -274,12 +274,23 @@ module GoodData
|
|
274
274
|
GoodData::Domain.add_user(data, name, { client: client }.merge(opts))
|
275
275
|
end
|
276
276
|
|
277
|
-
|
277
|
+
# Returns all the clients defined in all segments defined in domain. Alternatively
|
278
|
+
# id of a client can be provided in which case it returns just that client
|
279
|
+
# if it exists.
|
280
|
+
#
|
281
|
+
# @param id [String] Id of client that you are looking for
|
282
|
+
# @return [Object] Raw response
|
283
|
+
#
|
284
|
+
def clients(id = :all)
|
278
285
|
clients_uri = "/gdc/domains/#{name}/clients"
|
279
286
|
res = client.get(clients_uri)
|
280
287
|
res_clients = (res['clients'] && res['clients']['items']) || []
|
281
|
-
|
282
|
-
client.create(GoodData::Client, res_client)
|
288
|
+
if id == :all
|
289
|
+
res_clients.map { |res_client| client.create(GoodData::Client, res_client) }
|
290
|
+
else
|
291
|
+
find_result = res_clients.find { |c| c['client']['id'] == id }
|
292
|
+
fail "Client with id #{id} was not found" unless find_result
|
293
|
+
client.create(GoodData::Client, find_result)
|
283
294
|
end
|
284
295
|
end
|
285
296
|
|
@@ -376,13 +387,16 @@ module GoodData
|
|
376
387
|
def provision_client_projects
|
377
388
|
res = client.post(segments_uri + '/provisionClientProjects', nil)
|
378
389
|
res = client.poll_on_code(res['asyncTask']['links']['poll'])
|
379
|
-
klass = Struct.new('ProvisioningResult', :id, :status, :project_uri)
|
390
|
+
klass = Struct.new('ProvisioningResult', :id, :status, :project_uri, :error)
|
391
|
+
failed_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult failed count), 0)
|
392
|
+
created_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult created count), 0)
|
393
|
+
return Enumerator.new([]) if failed_count + created_count == 0
|
380
394
|
Enumerator.new do |y|
|
381
395
|
uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult links details))
|
382
396
|
loop do
|
383
397
|
result = client.get(uri)
|
384
398
|
(GoodData::Helpers.get_path(result, %w(clientProjectProvisioningResultDetails items)) || []).each do |item|
|
385
|
-
y << klass.new(item['id'], item['status'], item['project'])
|
399
|
+
y << klass.new(item['id'], item['status'], item['project'], item['error'])
|
386
400
|
end
|
387
401
|
uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResultDetails paging next))
|
388
402
|
break if uri.nil?
|
@@ -391,14 +405,16 @@ module GoodData
|
|
391
405
|
end
|
392
406
|
|
393
407
|
def update_clients(data, options = {})
|
408
|
+
delete_projects = options[:delete_projects] == false ? false : true
|
394
409
|
payload = data.map do |datum|
|
395
410
|
{
|
396
411
|
:client => {
|
397
412
|
:id => datum[:id],
|
398
|
-
:segment => segments_uri + '/segments/' + datum[:segment]
|
399
|
-
:project => datum[:project]
|
413
|
+
:segment => segments_uri + '/segments/' + datum[:segment]
|
400
414
|
}
|
401
|
-
}
|
415
|
+
}.tap do |h|
|
416
|
+
h[:client][:project] = datum[:project] if datum.key?(:project)
|
417
|
+
end
|
402
418
|
end
|
403
419
|
if options[:delete_extra] == true
|
404
420
|
res = client.post(segments_uri + '/updateClients?deleteExtra=true', updateClients: { items: payload })
|
@@ -408,7 +424,7 @@ module GoodData
|
|
408
424
|
data = GoodData::Helpers.get_path(res, ['updateClientsResponse'])
|
409
425
|
if data
|
410
426
|
result = data.flat_map { |k, v| v.map { |h| GoodData::Helpers.symbolize_keys(h.merge('type' => k)) } }
|
411
|
-
result.select { |r| r[:status] == 'DELETED' }.peach { |r| r[:originalProject] && client.delete(r[:originalProject]) }
|
427
|
+
result.select { |r| r[:status] == 'DELETED' }.peach { |r| r[:originalProject] && client.delete(r[:originalProject]) } if delete_projects
|
412
428
|
result
|
413
429
|
else
|
414
430
|
[]
|
@@ -9,6 +9,7 @@ require 'pmap'
|
|
9
9
|
|
10
10
|
require_relative 'project'
|
11
11
|
require_relative 'project_role'
|
12
|
+
require_relative 'user_group'
|
12
13
|
|
13
14
|
require_relative '../rest/object'
|
14
15
|
|
@@ -162,6 +163,14 @@ module GoodData
|
|
162
163
|
@json['user']['content']['firstname'] = new_first_name
|
163
164
|
end
|
164
165
|
|
166
|
+
# Get full name
|
167
|
+
#
|
168
|
+
# @return String Full Name
|
169
|
+
# NOTE: This can be tricky to implement correctly for i18n
|
170
|
+
def full_name
|
171
|
+
"#{first_name} #{last_name}"
|
172
|
+
end
|
173
|
+
|
165
174
|
# Gets the invitations
|
166
175
|
#
|
167
176
|
# @return [Array<GoodData::Invitation>] List of invitations
|
@@ -289,6 +298,8 @@ module GoodData
|
|
289
298
|
#
|
290
299
|
# @return [Array<GoodData::ProjectRole>] Array of project roles
|
291
300
|
def roles
|
301
|
+
# TODO: Implement getting roles in project and cache them there
|
302
|
+
# See: https://jira.intgdc.com/browse/TMA-112
|
292
303
|
roles_link = GoodData::Helpers.get_path(@json, %w(user links roles))
|
293
304
|
return unless roles_link
|
294
305
|
tmp = client.get roles_link
|
@@ -81,7 +81,7 @@ module GoodData
|
|
81
81
|
tab = options[:tab] || ''
|
82
82
|
|
83
83
|
req_uri = "/gdc/projects/#{project.pid}/clientexport"
|
84
|
-
x = client.post(req_uri, 'clientExport' => { 'url' => "#{client.connection.server_url}/dashboard.html#project=#{
|
84
|
+
x = client.post(req_uri, 'clientExport' => { 'url' => "#{client.connection.server_url}/dashboard.html#project=#{project.uri}&dashboard=#{uri}&tab=#{tab}&export=1", 'name' => title })
|
85
85
|
client.poll_on_code(x['asyncTask']['link']['poll'], options.merge(process: false))
|
86
86
|
end
|
87
87
|
|
@@ -16,8 +16,7 @@ module GoodData
|
|
16
16
|
# @param [String] value value of an label you are looking for
|
17
17
|
# @return [String]
|
18
18
|
def find_value_uri(value)
|
19
|
-
|
20
|
-
results = client.post("#{uri}/validElements?limit=1&offset=0&order=asc&filter=#{escaped_value}", 'validElementsRequest' => {})
|
19
|
+
results = get_valid_elements(filter: value)
|
21
20
|
items = results['validElements']['items']
|
22
21
|
if items.empty?
|
23
22
|
fail(AttributeElementNotFound, value)
|
@@ -41,6 +40,36 @@ module GoodData
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
43
|
+
# Gets valid elements using /validElements? API
|
44
|
+
# @return [Array] Results
|
45
|
+
def get_valid_elements(url_or_params = {}, request_payload = {})
|
46
|
+
final_url = url_or_params
|
47
|
+
|
48
|
+
if url_or_params.is_a?(Hash)
|
49
|
+
default_params = {
|
50
|
+
limit: 1,
|
51
|
+
offset: 0,
|
52
|
+
order: 'asc'
|
53
|
+
}
|
54
|
+
params = default_params.merge(url_or_params).map { |x, v| "#{x}=#{CGI.escape(v.to_s)}" }.reduce { |a, e| "#{a}&#{e}" }
|
55
|
+
final_url = "#{uri}/validElements?#{params}"
|
56
|
+
end
|
57
|
+
|
58
|
+
results = client.post(final_url, 'validElementsRequest' => request_payload)
|
59
|
+
|
60
|
+
# Implementation of polling is based on
|
61
|
+
# https://opengrok.intgdc.com/source/xref/gdc-backend/src/test/java/com/gooddata/service/dao/ValidElementsDaoTest.java
|
62
|
+
status_url = results['uri']
|
63
|
+
if status_url
|
64
|
+
results = client.poll_on_response(status_url) do |body|
|
65
|
+
status = body['taskState'] && body['taskState']['status']
|
66
|
+
status == 'RUNNING' || status == 'PREPARED'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
results
|
71
|
+
end
|
72
|
+
|
44
73
|
# Finds if a label has an attribute element for given value.
|
45
74
|
# @param [String] value value of an label you are looking for
|
46
75
|
# @return [Boolean]
|
@@ -56,22 +85,11 @@ module GoodData
|
|
56
85
|
# @option options [Number] :limit limits the number of values to certain number. Default is 100
|
57
86
|
# @return [Array]
|
58
87
|
def values(options = {})
|
59
|
-
client = client(options)
|
60
88
|
Enumerator.new do |y|
|
61
89
|
offset = options[:offset] || 0
|
62
90
|
page_limit = options[:limit] || 100
|
63
91
|
loop do
|
64
|
-
results =
|
65
|
-
|
66
|
-
# Implementation of polling is based on
|
67
|
-
# https://opengrok.intgdc.com/source/xref/gdc-backend/src/test/java/com/gooddata/service/dao/ValidElementsDaoTest.java
|
68
|
-
status_url = results['uri']
|
69
|
-
if status_url
|
70
|
-
results = client.poll_on_response(status_url) do |body|
|
71
|
-
status = body['taskState']['status']
|
72
|
-
status == 'RUNNING' || status == 'PREPARED'
|
73
|
-
end
|
74
|
-
end
|
92
|
+
results = get_valid_elements(limit: page_limit, offset: offset)
|
75
93
|
|
76
94
|
elements = results['validElements']
|
77
95
|
elements['items'].map do |el|
|
@@ -88,7 +106,7 @@ module GoodData
|
|
88
106
|
end
|
89
107
|
|
90
108
|
def values_count
|
91
|
-
results =
|
109
|
+
results = get_valid_elements
|
92
110
|
count = GoodData::Helpers.get_path(results, %w(validElements paging total))
|
93
111
|
count && count.to_i
|
94
112
|
end
|
@@ -6,6 +6,7 @@
|
|
6
6
|
|
7
7
|
require 'pry'
|
8
8
|
require 'zip'
|
9
|
+
require 'uri'
|
9
10
|
|
10
11
|
require_relative '../helpers/global_helpers'
|
11
12
|
require_relative '../rest/resource'
|
@@ -13,6 +14,8 @@ require_relative '../rest/resource'
|
|
13
14
|
require_relative 'execution_detail'
|
14
15
|
require_relative 'schedule'
|
15
16
|
|
17
|
+
APP_STORE_URL ||= 'https://github.com/gooddata/app_store'
|
18
|
+
|
16
19
|
module GoodData
|
17
20
|
class Process < Rest::Resource
|
18
21
|
attr_reader :data
|
@@ -91,6 +94,8 @@ module GoodData
|
|
91
94
|
def deploy(path, options = { :client => GoodData.client, :project => GoodData.project })
|
92
95
|
client, project = GoodData.get_client_and_project(options)
|
93
96
|
|
97
|
+
return deploy_brick(path, options) if path.to_s.start_with?(APP_STORE_URL)
|
98
|
+
|
94
99
|
path = Pathname(path) || fail('Path is not specified')
|
95
100
|
files_to_exclude = options[:files_to_exclude].nil? ? [] : options[:files_to_exclude].map { |pname| Pathname(pname) }
|
96
101
|
process_id = options[:process_id]
|
@@ -122,6 +127,44 @@ module GoodData
|
|
122
127
|
process
|
123
128
|
end
|
124
129
|
|
130
|
+
def deploy_brick(path, options = { :client => GoodData.client, :project => GoodData.project })
|
131
|
+
client, project = GoodData.get_client_and_project(options)
|
132
|
+
|
133
|
+
brick_uri_parts = URI(path).path.split('/')
|
134
|
+
ref = brick_uri_parts[4]
|
135
|
+
brick_name = brick_uri_parts.last
|
136
|
+
brick_path = brick_uri_parts[5..-1].join('/')
|
137
|
+
|
138
|
+
Dir.mktmpdir do |dir|
|
139
|
+
Dir.chdir(dir) do
|
140
|
+
`git clone #{APP_STORE_URL}`
|
141
|
+
end
|
142
|
+
|
143
|
+
Dir.chdir(File.join(dir, 'app_store')) do
|
144
|
+
if ref
|
145
|
+
`git checkout #{ref}`
|
146
|
+
|
147
|
+
fail 'Wrong branch or tag specified!' if $CHILD_STATUS.to_i != 0
|
148
|
+
end
|
149
|
+
|
150
|
+
opts = {
|
151
|
+
:client => client,
|
152
|
+
:project => project,
|
153
|
+
:name => brick_name,
|
154
|
+
:type => 'RUBY'
|
155
|
+
}
|
156
|
+
|
157
|
+
full_brick_path = File.join(dir, 'app_store', brick_path)
|
158
|
+
|
159
|
+
unless File.exist?(full_brick_path)
|
160
|
+
fail "Invalid brick name specified - '#{brick_name}'"
|
161
|
+
end
|
162
|
+
|
163
|
+
return deploy(full_brick_path, opts)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
125
168
|
# ----------------------------- Private Stuff
|
126
169
|
|
127
170
|
private
|
@@ -145,10 +188,13 @@ module GoodData
|
|
145
188
|
with_zip(opts) do |zipfile|
|
146
189
|
zipfile.add(File.basename(path), path)
|
147
190
|
end
|
148
|
-
|
149
191
|
elsif !path.directory?
|
150
|
-
|
151
|
-
|
192
|
+
# this branch expects a zipped file. Since the filename on webdav is by default
|
193
|
+
# equal to the filename of a local file. I happened often that the name clashed
|
194
|
+
# if ran in parallel. Create a randomized name to mitigate that
|
195
|
+
randomized_filename = (0...16).map { (65 + rand(26)).chr }.join
|
196
|
+
client.upload_to_user_webdav(path, { filename: randomized_filename }.merge(opts))
|
197
|
+
randomized_filename
|
152
198
|
else
|
153
199
|
with_zip(opts) do |zipfile|
|
154
200
|
files_to_upload = Dir[File.join(path, '**', '**')].reject { |f| files_to_exclude.include?(Pathname(path) + f) }
|
@@ -21,6 +21,7 @@ require_relative '../mixins/contributor'
|
|
21
21
|
require_relative '../mixins/rest_resource'
|
22
22
|
require_relative '../mixins/uri_getter'
|
23
23
|
|
24
|
+
require_relative 'membership'
|
24
25
|
require_relative 'process'
|
25
26
|
require_relative 'project_role'
|
26
27
|
require_relative 'blueprint/blueprint'
|
@@ -91,6 +92,17 @@ module GoodData
|
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
95
|
+
# Clones project along with etl and schedules
|
96
|
+
#
|
97
|
+
# @param project [Project] Project to be cloned from
|
98
|
+
# @param [options] Options that are passed into project.clone
|
99
|
+
# @return [GoodData::Project] New cloned project
|
100
|
+
def clone_with_etl(project, options = {})
|
101
|
+
a_clone = project.clone(options)
|
102
|
+
GoodData::Project.transfer_etl(project.client, project, a_clone)
|
103
|
+
a_clone
|
104
|
+
end
|
105
|
+
|
94
106
|
def create_object(data = {})
|
95
107
|
c = client(data)
|
96
108
|
new_data = GoodData::Helpers.deep_dup(EMPTY_OBJECT).tap do |d|
|
@@ -172,6 +184,131 @@ module GoodData
|
|
172
184
|
}
|
173
185
|
}
|
174
186
|
end
|
187
|
+
|
188
|
+
# Clones project along with etl and schedules.
|
189
|
+
#
|
190
|
+
# @param client [GoodData::Rest::Client] GoodData client to be used for connection
|
191
|
+
# @param from_project [GoodData::Project | GoodData::Segment | GoodData:Client | String] Object to be cloned from. Can be either segment in which case we take the master, client in which case we take its project, string in which case we treat is as an project object or directly project
|
192
|
+
def transfer_etl(client, from_project, to_project)
|
193
|
+
from_project = case from_project
|
194
|
+
when GoodData::Client
|
195
|
+
from_project.project
|
196
|
+
when GoodData::Segment
|
197
|
+
from_project.master_project
|
198
|
+
else
|
199
|
+
client.projects(from_project)
|
200
|
+
end
|
201
|
+
|
202
|
+
to_project = case to_project
|
203
|
+
when GoodData::Client
|
204
|
+
to_project.project
|
205
|
+
when GoodData::Segment
|
206
|
+
to_project.master_project
|
207
|
+
else
|
208
|
+
client.projects(to_project)
|
209
|
+
end
|
210
|
+
|
211
|
+
from_project.processes.each do |process|
|
212
|
+
Dir.mktmpdir('etl_transfer') do |dir|
|
213
|
+
dir = Pathname(dir)
|
214
|
+
filename = dir + 'process.zip'
|
215
|
+
File.open(filename, 'w') do |f|
|
216
|
+
f << process.download
|
217
|
+
end
|
218
|
+
to_process = to_project.processes.find { |p| p.name == process.name }
|
219
|
+
to_process ? to_process.deploy(filename, type: process.type, name: process.name) : to_project.deploy_process(filename, type: process.type, name: process.name)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
res = (from_project.processes + to_project.processes).map { |p| [p, p.name, p.type] }
|
223
|
+
res.group_by { |x| [x[1], x[2]] }
|
224
|
+
.select { |_, procs| procs.length == 1 }
|
225
|
+
.flat_map { |_, procs| procs.select { |p| p[0].project.pid == to_project.pid }.map { |p| p[0] } }
|
226
|
+
.peach(&:delete)
|
227
|
+
transfer_schedules(from_project, to_project)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Clones project along with etl and schedules.
|
231
|
+
#
|
232
|
+
# @param client [GoodData::Rest::Client] GoodData client to be used for connection
|
233
|
+
# @param from_project [GoodData::Project | GoodData::Segment | GoodData:Client | String] Object to be cloned from. Can be either segment in which case we take the master, client in which case we take its project, string in which case we treat is as an project object or directly project
|
234
|
+
def transfer_schedules(from_project, to_project)
|
235
|
+
cache = to_project.processes.sort_by(&:name).zip(from_project.processes.sort_by(&:name)).flat_map { |remote, local| local.schedules.map { |schedule| [remote, local, schedule] } }
|
236
|
+
|
237
|
+
remote_schedules = to_project.schedules
|
238
|
+
remote_stuff = remote_schedules.map do |s|
|
239
|
+
v = s.to_hash
|
240
|
+
after_schedule = remote_schedules.find { |s2| s.trigger_id == s2.obj_id }
|
241
|
+
v[:after] = s.trigger_id && after_schedule && after_schedule.name
|
242
|
+
v[:remote_schedule] = s
|
243
|
+
v[:params] = v[:params].except("EXECUTABLE", "PROCESS_ID")
|
244
|
+
v.compact
|
245
|
+
end
|
246
|
+
|
247
|
+
local_schedules = from_project.schedules
|
248
|
+
local_stuff = local_schedules.map do |s|
|
249
|
+
v = s.to_hash
|
250
|
+
after_schedule = local_schedules.find { |s2| s.trigger_id == s2.obj_id }
|
251
|
+
v[:after] = s.trigger_id && after_schedule && after_schedule.name
|
252
|
+
v[:remote_schedule] = s
|
253
|
+
v[:params] = v[:params].except("EXECUTABLE", "PROCESS_ID")
|
254
|
+
v.compact
|
255
|
+
end
|
256
|
+
|
257
|
+
diff = GoodData::Helpers.diff(remote_stuff, local_stuff, key: :name, fields: [:name, :cron, :after, :params, :hidden_params, :reschedule])
|
258
|
+
stack = diff[:added].map { |x| [:added, x] } + diff[:changed].map { |x| [:changed, x] }
|
259
|
+
schedule_cache = remote_schedules.reduce({}) do |a, e|
|
260
|
+
a[e.name] = e
|
261
|
+
a
|
262
|
+
end
|
263
|
+
messages = []
|
264
|
+
loop do
|
265
|
+
break if stack.empty?
|
266
|
+
state, changed_schedule = stack.shift
|
267
|
+
if state == :added
|
268
|
+
schedule_spec = changed_schedule
|
269
|
+
if schedule_spec[:after] && !schedule_cache[schedule_spec[:after]]
|
270
|
+
stack << [state, schedule_spec]
|
271
|
+
next
|
272
|
+
end
|
273
|
+
remote_process, process_spec = cache.find { |_remote, _local, schedule| schedule.name == schedule_spec[:name] }
|
274
|
+
messages << { message: "Creating schedule #{schedule_spec[:name]} for process #{remote_process.name}" }
|
275
|
+
executable = schedule_spec[:executable] || (process_spec["process_type"] == 'ruby' ? 'main.rb' : 'main.grf')
|
276
|
+
params = {
|
277
|
+
params: schedule_spec[:params].merge('PROJECT_ID' => to_project.pid),
|
278
|
+
hidden_params: schedule_spec[:hidden_params],
|
279
|
+
name: schedule_spec[:name],
|
280
|
+
reschedule: schedule_spec[:reschedule]
|
281
|
+
}
|
282
|
+
created_schedule = remote_process.create_schedule(schedule_spec[:cron] || schedule_cache[schedule_spec[:after]], executable, params)
|
283
|
+
schedule_cache[created_schedule.name] = created_schedule
|
284
|
+
else
|
285
|
+
schedule_spec = changed_schedule[:new_obj]
|
286
|
+
if schedule_spec[:after] && !schedule_cache[schedule_spec[:after]]
|
287
|
+
stack << [state, schedule_spec]
|
288
|
+
next
|
289
|
+
end
|
290
|
+
remote_process, process_spec = cache.find { |i| i[2].name == schedule_spec[:name] }
|
291
|
+
schedule = changed_schedule[:old_obj][:remote_schedule]
|
292
|
+
messages << { message: "Updating schedule #{schedule_spec[:name]} for process #{remote_process.name}" }
|
293
|
+
schedule.params = (schedule_spec[:params] || {})
|
294
|
+
schedule.cron = schedule_spec[:cron] if schedule_spec[:cron]
|
295
|
+
schedule.after = schedule_cache[schedule_spec[:after]] if schedule_spec[:after]
|
296
|
+
schedule.hidden_params = schedule_spec[:hidden_params] || {}
|
297
|
+
schedule.executable = schedule_spec[:executable] || (process_spec["process_type"] == 'ruby' ? 'main.rb' : 'main.grf')
|
298
|
+
schedule.reschedule = schedule_spec[:reschedule]
|
299
|
+
schedule.name = schedule_spec[:name]
|
300
|
+
schedule.save
|
301
|
+
schedule_cache[schedule.name] = schedule
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
diff[:removed].each do |removed_schedule|
|
306
|
+
messages << { message: "Removing schedule #{removed_schedule[:name]}" }
|
307
|
+
removed_schedule[:remote_schedule].delete
|
308
|
+
end
|
309
|
+
messages
|
310
|
+
# messages.map {|m| m.merge({custom_project_id: custom_project_id})}
|
311
|
+
end
|
175
312
|
end
|
176
313
|
|
177
314
|
def add_dashboard(dashboard)
|
@@ -846,13 +983,20 @@ module GoodData
|
|
846
983
|
if projects.is_a?(Array)
|
847
984
|
projects.each_slice(batch_size).flat_map do |batch|
|
848
985
|
batch.pmap do |proj|
|
849
|
-
target_project = client.projects(proj)
|
850
986
|
begin
|
987
|
+
target_project = client.projects(proj)
|
851
988
|
target_project.objects_import(token, options)
|
852
989
|
{
|
853
990
|
project: target_project,
|
854
991
|
result: true
|
855
992
|
}
|
993
|
+
rescue RestClient::Exception => e
|
994
|
+
{
|
995
|
+
project: proj,
|
996
|
+
exception: e,
|
997
|
+
result: false,
|
998
|
+
reason: GoodData::Helpers.interpolate_error_message(MultiJson.load(e.response))
|
999
|
+
}
|
856
1000
|
rescue GoodData::ObjectsImportError => e
|
857
1001
|
{
|
858
1002
|
project: target_project,
|
@@ -122,9 +122,26 @@ module GoodData
|
|
122
122
|
saved? ? client.delete(uri) : nil
|
123
123
|
end
|
124
124
|
|
125
|
+
# Is schedule enabled?
|
126
|
+
#
|
127
|
+
# @return [GoodData::Schedule]
|
128
|
+
def disable
|
129
|
+
@json['schedule']['state'] = 'DISABLED'
|
130
|
+
@dirty = true
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
125
134
|
# Is schedule enabled?
|
126
135
|
#
|
127
136
|
# @return [Boolean]
|
137
|
+
def disable!
|
138
|
+
disable
|
139
|
+
save
|
140
|
+
end
|
141
|
+
|
142
|
+
# Is schedule disabled?
|
143
|
+
#
|
144
|
+
# @return [Boolean]
|
128
145
|
def disabled?
|
129
146
|
state == 'DISABLED'
|
130
147
|
end
|
@@ -136,7 +153,7 @@ module GoodData
|
|
136
153
|
!disabled?
|
137
154
|
end
|
138
155
|
|
139
|
-
#
|
156
|
+
# Enables the schedule
|
140
157
|
#
|
141
158
|
# @return [GoodData::Schedule]
|
142
159
|
def enable
|
@@ -145,13 +162,12 @@ module GoodData
|
|
145
162
|
self
|
146
163
|
end
|
147
164
|
|
148
|
-
#
|
165
|
+
# Enables and saves the schedule
|
149
166
|
#
|
150
167
|
# @return [GoodData::Schedule]
|
151
|
-
def
|
152
|
-
|
153
|
-
|
154
|
-
self
|
168
|
+
def enable!
|
169
|
+
enable
|
170
|
+
save
|
155
171
|
end
|
156
172
|
|
157
173
|
# Executes schedule
|
@@ -116,6 +116,15 @@ module GoodData
|
|
116
116
|
# Master project id getter for the Segment.
|
117
117
|
#
|
118
118
|
# @return [String] Project uri
|
119
|
+
def master_project_id
|
120
|
+
GoodData::Helpers.last_uri_part(master_project_uri)
|
121
|
+
end
|
122
|
+
|
123
|
+
alias_method :master_id, :master_project_id
|
124
|
+
|
125
|
+
# Master project uri getter for the Segment.
|
126
|
+
#
|
127
|
+
# @return [String] Project uri
|
119
128
|
def master_project_uri
|
120
129
|
data['masterProject']
|
121
130
|
end
|
data/lib/gooddata/version.rb
CHANGED
data/spec/environment/develop.rb
CHANGED
@@ -13,19 +13,19 @@ module GoodData
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module ProcessHelper
|
16
|
-
set_const :PROCESS_ID, '
|
16
|
+
set_const :PROCESS_ID, '93027bc3-c731-4788-a179-d83bd04aae35'
|
17
17
|
set_const :DEPLOY_NAME, 'graph/graph.grf'
|
18
18
|
end
|
19
19
|
|
20
20
|
module ProjectHelper
|
21
|
-
set_const :PROJECT_ID, '
|
21
|
+
set_const :PROJECT_ID, 'yz7e0iwh7gdih02dssf47rw4e096t7nb'
|
22
22
|
set_const :PROJECT_URL, "/gdc/projects/#{PROJECT_ID}"
|
23
23
|
set_const :PROJECT_TITLE, 'GoodTravis'
|
24
24
|
set_const :PROJECT_SUMMARY, 'No summary'
|
25
25
|
end
|
26
26
|
|
27
27
|
module ScheduleHelper
|
28
|
-
set_const :SCHEDULE_ID, '
|
28
|
+
set_const :SCHEDULE_ID, '571024efe4b025350e321b85'
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -38,7 +38,7 @@ describe GoodData::Client do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'Returns specific tenant when schedule ID passed' do
|
41
|
-
client = @segment.clients(@segment_client
|
41
|
+
client = @segment.clients(@segment_client)
|
42
42
|
expect(client).to be_an_instance_of(GoodData::Client)
|
43
43
|
expect(client.uri).to eq @segment_client.uri
|
44
44
|
end
|
@@ -58,7 +58,7 @@ describe GoodData::Client do
|
|
58
58
|
|
59
59
|
it 'Deletes particular client' do
|
60
60
|
expect(@segment.clients.count).to eq 1
|
61
|
-
s = @segment.clients(@segment_client
|
61
|
+
s = @segment.clients(@segment_client)
|
62
62
|
s.delete
|
63
63
|
expect(@segment.clients.count).to eq 0
|
64
64
|
@segment_client = nil
|
@@ -78,7 +78,7 @@ describe GoodData::Client do
|
|
78
78
|
|
79
79
|
it 'Deletes particular client. Project is cleaned up as well' do
|
80
80
|
expect(@segment.clients.count).to eq 1
|
81
|
-
s = @segment.clients(@segment_client
|
81
|
+
s = @segment.clients(@segment_client)
|
82
82
|
s.delete
|
83
83
|
expect(@segment.clients.count).to eq 0
|
84
84
|
expect(@client_project.reload!.state).to eq :deleted
|
@@ -86,7 +86,7 @@ describe GoodData::Client do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
after(:all) do
|
89
|
-
@segment_client && segment_client.delete
|
89
|
+
@segment_client && @segment_client.delete
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -102,7 +102,7 @@ describe GoodData::Client do
|
|
102
102
|
other_client_project = @client.create_project(title: "client_#{@client_id} other project", auth_token: TOKEN)
|
103
103
|
@segment_client.project = other_client_project
|
104
104
|
@segment_client.save
|
105
|
-
expect(@segment.clients(
|
105
|
+
expect(@segment.clients(@segment_client).project_uri).to eq other_client_project.uri
|
106
106
|
ensure
|
107
107
|
other_client_project && other_client_project.delete
|
108
108
|
end
|
@@ -268,4 +268,31 @@ describe "Full process and schedule exercise", :constraint => 'slow' do
|
|
268
268
|
process1 && process1.delete
|
269
269
|
end
|
270
270
|
end
|
271
|
+
|
272
|
+
it 'should be able to deploy from app_store' do
|
273
|
+
begin
|
274
|
+
process = @project.deploy_process('https://github.com/gooddata/app_store/tree/sfdc_downloader_brick-v0.0.4/apps/ads_integrator_brick')
|
275
|
+
expect(process.class).to eql(GoodData::Process)
|
276
|
+
ensure
|
277
|
+
process.delete
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
it 'should be able to clone with etl' do
|
283
|
+
begin
|
284
|
+
# Deploy two schedules
|
285
|
+
process = @project.processes.first
|
286
|
+
schedule_first = process.create_schedule('0 15 27 7 *', process.executables.first)
|
287
|
+
schedule_second = process.create_schedule('0 15 27 8 *', process.executables.first)
|
288
|
+
cloned_project = GoodData::Project.clone_with_etl(@project)
|
289
|
+
a = @project.processes.flat_map {|p| p.schedules.map {|s| [p.name, s.name]}}
|
290
|
+
b = cloned_project.processes.flat_map {|p| p.schedules.map {|s| [p.name, s.name]}}
|
291
|
+
expect(a).to eq b
|
292
|
+
ensure
|
293
|
+
cloned_project && cloned_project.delete
|
294
|
+
schedule_first && schedule_first.delete
|
295
|
+
schedule_second && schedule_second.delete
|
296
|
+
end
|
297
|
+
end
|
271
298
|
end
|
@@ -24,7 +24,6 @@ describe GoodData::Schedule do
|
|
24
24
|
@client = ConnectionHelper.create_default_connection
|
25
25
|
|
26
26
|
@project = ProjectHelper.get_default_project(:client => @client)
|
27
|
-
@project_executable = 'graph/graph.grf'
|
28
27
|
@test_cron = '0 15 27 7 *'
|
29
28
|
@test_data = {
|
30
29
|
:timezone => 'UTC',
|
@@ -87,7 +86,7 @@ describe GoodData::Schedule do
|
|
87
86
|
describe '#create' do
|
88
87
|
it 'Creates new schedule if mandatory params passed' do
|
89
88
|
begin
|
90
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
89
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
91
90
|
expect(schedule).to be_truthy
|
92
91
|
ensure
|
93
92
|
schedule && schedule.delete
|
@@ -96,7 +95,7 @@ describe GoodData::Schedule do
|
|
96
95
|
|
97
96
|
it 'Creates new schedule if mandatory params passed and optional params are present' do
|
98
97
|
begin
|
99
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
98
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
100
99
|
expect(schedule).to be_truthy
|
101
100
|
ensure
|
102
101
|
schedule && schedule.delete
|
@@ -107,7 +106,7 @@ describe GoodData::Schedule do
|
|
107
106
|
schedule = nil
|
108
107
|
begin
|
109
108
|
expect {
|
110
|
-
schedule = @project.create_schedule(nil, @test_cron,
|
109
|
+
schedule = @project.create_schedule(nil, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
111
110
|
}.to raise_error 'Process ID has to be provided'
|
112
111
|
ensure
|
113
112
|
schedule && schedule.delete
|
@@ -131,7 +130,7 @@ describe GoodData::Schedule do
|
|
131
130
|
schedule = nil
|
132
131
|
begin
|
133
132
|
expect {
|
134
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, nil,
|
133
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, nil, ProcessHelper::DEPLOY_NAME, data)
|
135
134
|
}.to raise_error 'Trigger schedule has to be provided'
|
136
135
|
ensure
|
137
136
|
schedule && schedule.delete
|
@@ -140,7 +139,7 @@ describe GoodData::Schedule do
|
|
140
139
|
|
141
140
|
it 'Throws exception when no timezone specified' do
|
142
141
|
data = GoodData::Helpers.deep_dup(@test_data)
|
143
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
142
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, data)
|
144
143
|
schedule.timezone = nil
|
145
144
|
begin
|
146
145
|
expect {
|
@@ -155,7 +154,7 @@ describe GoodData::Schedule do
|
|
155
154
|
schedule = nil
|
156
155
|
data = GoodData::Helpers.deep_dup(@test_data)
|
157
156
|
begin
|
158
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
157
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, data)
|
159
158
|
schedule.type = nil
|
160
159
|
expect {
|
161
160
|
schedule.save
|
@@ -169,7 +168,7 @@ describe GoodData::Schedule do
|
|
169
168
|
describe '#cron' do
|
170
169
|
it 'Should return cron as string' do
|
171
170
|
begin
|
172
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
171
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
173
172
|
res = schedule.cron
|
174
173
|
res.should_not be_nil
|
175
174
|
res.should_not be_empty
|
@@ -186,7 +185,7 @@ describe GoodData::Schedule do
|
|
186
185
|
test_cron = '2 2 2 2 *'
|
187
186
|
|
188
187
|
begin
|
189
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
188
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
190
189
|
schedule.cron = test_cron
|
191
190
|
expect(schedule.cron).to eq(test_cron)
|
192
191
|
expect(schedule.dirty).to eq(true)
|
@@ -199,7 +198,7 @@ describe GoodData::Schedule do
|
|
199
198
|
describe '#executable' do
|
200
199
|
it 'Should return executable as string' do
|
201
200
|
begin
|
202
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
201
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
203
202
|
res = schedule.executable
|
204
203
|
res.should_not be_nil
|
205
204
|
res.should_not be_empty
|
@@ -215,7 +214,7 @@ describe GoodData::Schedule do
|
|
215
214
|
test_executable = 'this/is/test.grf'
|
216
215
|
|
217
216
|
begin
|
218
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
217
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
219
218
|
schedule.executable = test_executable
|
220
219
|
expect(schedule.executable).to eq(test_executable)
|
221
220
|
expect(schedule.dirty).to eq(true)
|
@@ -260,7 +259,7 @@ describe GoodData::Schedule do
|
|
260
259
|
describe '#execution_url' do
|
261
260
|
it 'Should return execution URL as string' do
|
262
261
|
begin
|
263
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
262
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
264
263
|
res = schedule.execution_url
|
265
264
|
res.should_not be_nil
|
266
265
|
res.should_not be_empty
|
@@ -274,7 +273,7 @@ describe GoodData::Schedule do
|
|
274
273
|
describe '#type' do
|
275
274
|
it 'Should return execution type as string' do
|
276
275
|
begin
|
277
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
276
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
278
277
|
res = schedule.type
|
279
278
|
res.should_not be_nil
|
280
279
|
res.should be_a_kind_of(String)
|
@@ -287,7 +286,7 @@ describe GoodData::Schedule do
|
|
287
286
|
describe '#hidden_params' do
|
288
287
|
it 'Should return execution hidden_params as hash' do
|
289
288
|
begin
|
290
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
289
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
291
290
|
res = schedule.hidden_params
|
292
291
|
res.should_not be_nil
|
293
292
|
res.should be_a_kind_of(Hash)
|
@@ -300,7 +299,7 @@ describe GoodData::Schedule do
|
|
300
299
|
describe '#hidden_params=' do
|
301
300
|
it 'Assigns the hidden params and marks the object dirty' do
|
302
301
|
begin
|
303
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
302
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
304
303
|
old_params = schedule.hidden_params
|
305
304
|
|
306
305
|
test_params = {
|
@@ -319,7 +318,7 @@ describe GoodData::Schedule do
|
|
319
318
|
describe '#set_hidden_parameter' do
|
320
319
|
it 'Assigns the hidden parameter and marks the object dirty' do
|
321
320
|
begin
|
322
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
321
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
323
322
|
old_params = schedule.hidden_params
|
324
323
|
|
325
324
|
test_parameter = {'test_parameter' => 'just_testing' }
|
@@ -335,7 +334,7 @@ describe GoodData::Schedule do
|
|
335
334
|
describe '#set_parameter' do
|
336
335
|
it 'Assigns the hidden parameter and marks the object dirty' do
|
337
336
|
begin
|
338
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
337
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
339
338
|
old_params = schedule.params
|
340
339
|
|
341
340
|
test_parameter = {'test_parameter' => 'just_testing' }
|
@@ -352,7 +351,7 @@ describe GoodData::Schedule do
|
|
352
351
|
describe '#params' do
|
353
352
|
it 'Should return execution params as hash' do
|
354
353
|
begin
|
355
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
354
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
356
355
|
res = schedule.params
|
357
356
|
res.should_not be_nil
|
358
357
|
res.should_not be_empty
|
@@ -366,7 +365,7 @@ describe GoodData::Schedule do
|
|
366
365
|
describe '#params=' do
|
367
366
|
it 'Assigns the params and marks the object dirty' do
|
368
367
|
begin
|
369
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
368
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
370
369
|
old_params = schedule.params
|
371
370
|
|
372
371
|
test_params = {
|
@@ -387,7 +386,7 @@ describe GoodData::Schedule do
|
|
387
386
|
describe '#process_id' do
|
388
387
|
it 'Should return process id as string' do
|
389
388
|
begin
|
390
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
389
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
391
390
|
res = schedule.process_id
|
392
391
|
res.should_not be_nil
|
393
392
|
res.should_not be_empty
|
@@ -403,7 +402,7 @@ describe GoodData::Schedule do
|
|
403
402
|
test_process_id = '1-2-3-4'
|
404
403
|
|
405
404
|
begin
|
406
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
405
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
407
406
|
schedule.process_id = test_process_id
|
408
407
|
expect(schedule.process_id).to eq(test_process_id)
|
409
408
|
expect(schedule.dirty).to eq(true)
|
@@ -416,7 +415,7 @@ describe GoodData::Schedule do
|
|
416
415
|
describe '#save' do
|
417
416
|
it 'Should save a schedule' do
|
418
417
|
begin
|
419
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
418
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
420
419
|
expect(@project.schedules(schedule.uri)).to eq schedule
|
421
420
|
expect(@project.schedules).to include(schedule)
|
422
421
|
ensure
|
@@ -428,7 +427,7 @@ describe GoodData::Schedule do
|
|
428
427
|
describe '#state' do
|
429
428
|
it 'Should return execution state as string' do
|
430
429
|
begin
|
431
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
430
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
432
431
|
res = schedule.state
|
433
432
|
res.should_not be_nil
|
434
433
|
res.should_not be_empty
|
@@ -442,7 +441,7 @@ describe GoodData::Schedule do
|
|
442
441
|
describe '#type' do
|
443
442
|
it 'Should return execution type as string' do
|
444
443
|
begin
|
445
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
444
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
446
445
|
res = schedule.type
|
447
446
|
res.should_not be_nil
|
448
447
|
res.should_not be_empty
|
@@ -458,7 +457,7 @@ describe GoodData::Schedule do
|
|
458
457
|
test_type = 'TEST'
|
459
458
|
|
460
459
|
begin
|
461
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
460
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
462
461
|
schedule.type = test_type
|
463
462
|
expect(schedule.type).to eq(test_type)
|
464
463
|
expect(schedule.dirty).to eq(true)
|
@@ -471,7 +470,7 @@ describe GoodData::Schedule do
|
|
471
470
|
describe '#timezone' do
|
472
471
|
it 'Should return timezone as string' do
|
473
472
|
begin
|
474
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
473
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
475
474
|
res = schedule.timezone
|
476
475
|
res.should_not be_nil
|
477
476
|
res.should_not be_empty
|
@@ -487,7 +486,7 @@ describe GoodData::Schedule do
|
|
487
486
|
test_timezone = 'PST'
|
488
487
|
|
489
488
|
begin
|
490
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
489
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data)
|
491
490
|
schedule.timezone = test_timezone
|
492
491
|
expect(schedule.timezone).to eq(test_timezone)
|
493
492
|
expect(schedule.dirty).to eq(true)
|
@@ -500,7 +499,7 @@ describe GoodData::Schedule do
|
|
500
499
|
describe '#reschedule' do
|
501
500
|
it 'Should return reschedule as integer' do
|
502
501
|
begin
|
503
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
502
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
504
503
|
res = schedule.reschedule
|
505
504
|
res.should_not be_nil
|
506
505
|
res.should be_a_kind_of(Integer)
|
@@ -515,7 +514,7 @@ describe GoodData::Schedule do
|
|
515
514
|
test_reschedule = 45
|
516
515
|
|
517
516
|
begin
|
518
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
517
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
519
518
|
schedule.reschedule = test_reschedule
|
520
519
|
expect(schedule.reschedule).to eq(test_reschedule)
|
521
520
|
expect(schedule.dirty).to eq(true)
|
@@ -528,7 +527,7 @@ describe GoodData::Schedule do
|
|
528
527
|
describe '#executions' do
|
529
528
|
it 'Returns executions' do
|
530
529
|
begin
|
531
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
530
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
532
531
|
expect(schedule.executions.to_a).to be_empty
|
533
532
|
schedule.execute
|
534
533
|
ensure
|
@@ -540,7 +539,7 @@ describe GoodData::Schedule do
|
|
540
539
|
describe '#name' do
|
541
540
|
it 'should be able to get name of the schedule.' do
|
542
541
|
begin
|
543
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
542
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
544
543
|
expect(schedule.name).to eq 'graph.grf'
|
545
544
|
ensure
|
546
545
|
schedule && schedule.delete
|
@@ -549,7 +548,7 @@ describe GoodData::Schedule do
|
|
549
548
|
|
550
549
|
it 'should be able to return your name if specified during creation.' do
|
551
550
|
begin
|
552
|
-
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron,
|
551
|
+
schedule = @project.create_schedule(ProcessHelper::PROCESS_ID, @test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param.merge(name: 'My schedule name'))
|
553
552
|
expect(schedule.name).to eq 'My schedule name'
|
554
553
|
ensure
|
555
554
|
schedule && schedule.delete
|
@@ -561,7 +560,7 @@ describe GoodData::Schedule do
|
|
561
560
|
it 'should be able to set trigger_id of the schedule.' do
|
562
561
|
begin
|
563
562
|
process = @project.processes(ProcessHelper::PROCESS_ID)
|
564
|
-
schedule = process.create_schedule(@test_cron,
|
563
|
+
schedule = process.create_schedule(@test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
565
564
|
expect(schedule.dirty).to be_falsey
|
566
565
|
schedule.trigger_id = 'some_other_id'
|
567
566
|
expect(schedule.dirty).to be_truthy
|
@@ -575,7 +574,7 @@ describe GoodData::Schedule do
|
|
575
574
|
it 'should be able to set trigger_id of the schedule.' do
|
576
575
|
begin
|
577
576
|
process = @project.processes(ProcessHelper::PROCESS_ID)
|
578
|
-
schedule = process.create_schedule(@test_cron,
|
577
|
+
schedule = process.create_schedule(@test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
579
578
|
expect(schedule.dirty).to be_falsey
|
580
579
|
schedule.trigger_id = 'some_other_id'
|
581
580
|
expect(schedule.dirty).to be_truthy
|
@@ -589,7 +588,7 @@ describe GoodData::Schedule do
|
|
589
588
|
it 'should be able to set name of the schedule.' do
|
590
589
|
begin
|
591
590
|
process = @project.processes(ProcessHelper::PROCESS_ID)
|
592
|
-
schedule = process.create_schedule(@test_cron,
|
591
|
+
schedule = process.create_schedule(@test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param)
|
593
592
|
expect(schedule.name).to eq 'graph.grf'
|
594
593
|
schedule.name = 'MY NAME'
|
595
594
|
schedule.save
|
@@ -605,7 +604,7 @@ describe GoodData::Schedule do
|
|
605
604
|
it 'should preserve the hidden parmeters.' do
|
606
605
|
begin
|
607
606
|
process = @project.processes(ProcessHelper::PROCESS_ID)
|
608
|
-
schedule = process.create_schedule(@test_cron,
|
607
|
+
schedule = process.create_schedule(@test_cron, ProcessHelper::DEPLOY_NAME, @test_data_with_optional_param.merge({hidden_params: {
|
609
608
|
"a" => {
|
610
609
|
"b" => "c"
|
611
610
|
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gooddata
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Kolesnikov
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2016-
|
14
|
+
date: 2016-04-15 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -19,14 +19,14 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: debase
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -670,6 +670,7 @@ files:
|
|
670
670
|
- lib/gooddata/bricks/utils.rb
|
671
671
|
- lib/gooddata/cli/cli.rb
|
672
672
|
- lib/gooddata/cli/commands/auth_cmd.rb
|
673
|
+
- lib/gooddata/cli/commands/domain_cmd.rb
|
673
674
|
- lib/gooddata/cli/commands/project_cmd.rb
|
674
675
|
- lib/gooddata/cli/hooks.rb
|
675
676
|
- lib/gooddata/cli/shared.rb
|