gooddata 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. checksums.yaml +13 -5
  2. data/.rubocop.yml +23 -0
  3. data/.travis.yml +9 -4
  4. data/CLI.md +439 -0
  5. data/Gemfile +0 -1
  6. data/README.md +2 -2
  7. data/Rakefile +60 -8
  8. data/doc/templates/default/module/setup.rb +1 -1
  9. data/examples.rb +2 -0
  10. data/gooddata +2 -0
  11. data/gooddata.gemspec +12 -8
  12. data/lib/gooddata.rb +0 -2
  13. data/lib/gooddata/bricks/base_downloader.rb +52 -47
  14. data/lib/gooddata/bricks/brick.rb +20 -31
  15. data/lib/gooddata/bricks/bricks.rb +1 -1
  16. data/lib/gooddata/bricks/middleware/base_middleware.rb +9 -7
  17. data/lib/gooddata/bricks/middleware/bench_middleware.rb +12 -10
  18. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +28 -28
  19. data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +20 -16
  20. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +21 -19
  21. data/lib/gooddata/bricks/middleware/logger_middleware.rb +10 -8
  22. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -34
  23. data/lib/gooddata/bricks/middleware/stdout_middleware.rb +11 -9
  24. data/lib/gooddata/bricks/middleware/twitter_middleware.rb +14 -12
  25. data/lib/gooddata/bricks/pipeline.rb +28 -0
  26. data/lib/gooddata/bricks/utils.rb +10 -8
  27. data/lib/gooddata/cli/cli.rb +1 -6
  28. data/lib/gooddata/cli/commands/auth_cmd.rb +1 -1
  29. data/lib/gooddata/cli/commands/console_cmd.rb +7 -5
  30. data/lib/gooddata/cli/commands/domain_cmd.rb +45 -0
  31. data/lib/gooddata/cli/commands/process_cmd.rb +42 -5
  32. data/lib/gooddata/cli/commands/project_cmd.rb +96 -36
  33. data/lib/gooddata/cli/commands/projects_cmd.rb +21 -0
  34. data/lib/gooddata/cli/commands/role_cmd.rb +28 -0
  35. data/lib/gooddata/cli/commands/run_ruby_cmd.rb +5 -5
  36. data/lib/gooddata/cli/commands/scaffold_cmd.rb +1 -1
  37. data/lib/gooddata/cli/commands/{profile_cmd.rb → user_cmd.rb} +7 -9
  38. data/lib/gooddata/cli/shared.rb +3 -2
  39. data/lib/gooddata/client.rb +16 -304
  40. data/lib/gooddata/commands/api.rb +13 -5
  41. data/lib/gooddata/commands/auth.rb +47 -40
  42. data/lib/gooddata/commands/base.rb +4 -2
  43. data/lib/gooddata/commands/commands.rb +1 -1
  44. data/lib/gooddata/commands/datasets.rb +20 -7
  45. data/lib/gooddata/commands/domain.rb +23 -0
  46. data/lib/gooddata/commands/process.rb +23 -117
  47. data/lib/gooddata/commands/project.rb +147 -0
  48. data/lib/gooddata/commands/projects.rb +8 -102
  49. data/lib/gooddata/commands/role.rb +26 -0
  50. data/lib/gooddata/commands/runners.rb +41 -38
  51. data/lib/gooddata/commands/scaffold.rb +46 -43
  52. data/lib/gooddata/commands/user.rb +33 -0
  53. data/lib/gooddata/connection.rb +43 -353
  54. data/lib/gooddata/core/connection.rb +389 -0
  55. data/lib/gooddata/core/core.rb +5 -4
  56. data/lib/gooddata/core/logging.rb +48 -0
  57. data/lib/gooddata/core/nil_logger.rb +13 -0
  58. data/lib/gooddata/core/project.rb +70 -0
  59. data/lib/gooddata/core/rest.rb +120 -0
  60. data/lib/gooddata/core/threaded.rb +14 -0
  61. data/lib/gooddata/core/user.rb +19 -0
  62. data/lib/gooddata/data/data.rb +2 -1
  63. data/lib/gooddata/data/guesser.rb +16 -12
  64. data/lib/gooddata/exceptions/command_failed.rb +1 -1
  65. data/lib/gooddata/exceptions/exceptions.rb +2 -1
  66. data/lib/gooddata/exceptions/no_project_error.rb +11 -0
  67. data/lib/gooddata/exceptions/project_not_found.rb +1 -1
  68. data/lib/gooddata/extensions/big_decimal.rb +6 -2
  69. data/lib/gooddata/extract.rb +10 -8
  70. data/lib/gooddata/goodzilla/goodzilla.rb +61 -59
  71. data/lib/gooddata/helpers.rb +15 -9
  72. data/lib/gooddata/models/account_settings.rb +124 -0
  73. data/lib/gooddata/models/attributes/anchor.rb +37 -0
  74. data/lib/gooddata/models/attributes/attributes.rb +8 -0
  75. data/lib/gooddata/models/attributes/date_attribute.rb +25 -0
  76. data/lib/gooddata/models/attributes/time_attribute.rb +24 -0
  77. data/lib/gooddata/models/columns/attribute.rb +71 -0
  78. data/lib/gooddata/models/columns/columns.rb +8 -0
  79. data/lib/gooddata/models/columns/date_column.rb +63 -0
  80. data/lib/gooddata/models/columns/fact_model.rb +54 -0
  81. data/lib/gooddata/models/columns/label.rb +55 -0
  82. data/lib/gooddata/models/columns/reference.rb +57 -0
  83. data/lib/gooddata/models/dashboard_builder.rb +26 -0
  84. data/lib/gooddata/models/data_result.rb +10 -9
  85. data/lib/gooddata/models/domain.rb +131 -0
  86. data/lib/gooddata/models/empty_result.rb +5 -8
  87. data/lib/gooddata/models/facts/facts.rb +8 -0
  88. data/lib/gooddata/models/facts/time_fact.rb +20 -0
  89. data/lib/gooddata/models/folders/attribute_folder.rb +20 -0
  90. data/lib/gooddata/models/folders/fact_folder.rb +20 -0
  91. data/lib/gooddata/models/folders/folders.rb +8 -0
  92. data/lib/gooddata/models/invitation.rb +78 -0
  93. data/lib/gooddata/models/links.rb +6 -6
  94. data/lib/gooddata/models/md_object.rb +25 -0
  95. data/lib/gooddata/models/metadata.rb +160 -62
  96. data/lib/gooddata/models/metadata/attribute.rb +81 -0
  97. data/lib/gooddata/models/metadata/column.rb +61 -0
  98. data/lib/gooddata/models/{dashboard.rb → metadata/dashboard.rb} +12 -7
  99. data/lib/gooddata/models/{data_set.rb → metadata/data_set.rb} +5 -4
  100. data/lib/gooddata/models/metadata/date_dimension.rb +26 -0
  101. data/lib/gooddata/models/metadata/display_form.rb +61 -0
  102. data/lib/gooddata/models/metadata/fact.rb +36 -0
  103. data/lib/gooddata/models/metadata/folder.rb +24 -0
  104. data/lib/gooddata/models/metadata/metadata.rb +8 -0
  105. data/lib/gooddata/models/metadata/metric.rb +197 -0
  106. data/lib/gooddata/models/metadata/report.rb +115 -0
  107. data/lib/gooddata/models/{report_definition.rb → metadata/report_definition.rb} +16 -10
  108. data/lib/gooddata/models/metadata/schema.rb +227 -0
  109. data/lib/gooddata/models/model.rb +38 -1339
  110. data/lib/gooddata/models/models.rb +5 -2
  111. data/lib/gooddata/models/module_constants.rb +29 -0
  112. data/lib/gooddata/models/process.rb +142 -13
  113. data/lib/gooddata/models/profile.rb +4 -6
  114. data/lib/gooddata/models/project.rb +406 -136
  115. data/lib/gooddata/models/project_blueprint.rb +221 -0
  116. data/lib/gooddata/models/project_builder.rb +136 -0
  117. data/lib/gooddata/models/project_creator.rb +138 -0
  118. data/lib/gooddata/models/project_metadata.rb +11 -10
  119. data/lib/gooddata/models/project_role.rb +92 -0
  120. data/lib/gooddata/models/references/date_reference.rb +44 -0
  121. data/lib/gooddata/models/references/references.rb +8 -0
  122. data/lib/gooddata/models/references/time_reference.rb +13 -0
  123. data/lib/gooddata/models/report_data_result.rb +11 -11
  124. data/lib/gooddata/models/schedule.rb +284 -0
  125. data/lib/gooddata/models/schema_blueprint.rb +158 -0
  126. data/lib/gooddata/models/schema_builder.rb +81 -0
  127. data/lib/gooddata/models/tab_builder.rb +23 -0
  128. data/lib/gooddata/models/user.rb +165 -0
  129. data/lib/gooddata/version.rb +1 -1
  130. data/lib/templates/project/data/devs.csv +1 -1
  131. data/lib/templates/project/data/repos.csv +1 -1
  132. data/lib/templates/project/model/model.rb.erb +7 -11
  133. data/spec/bricks/bricks_spec.rb +2 -0
  134. data/spec/data/test-ci-data.csv +2 -0
  135. data/spec/data/test_project_model_spec.json +7 -27
  136. data/spec/helpers/blueprint_helper.rb +2 -0
  137. data/spec/helpers/cli_helper.rb +2 -0
  138. data/spec/helpers/connection_helper.rb +14 -1
  139. data/spec/helpers/project_helper.rb +16 -0
  140. data/spec/helpers/schema_helper.rb +16 -0
  141. data/spec/integration/command_projects_spec.rb +7 -7
  142. data/spec/integration/create_from_template_spec.rb +2 -2
  143. data/spec/integration/full_project_spec.rb +160 -7
  144. data/spec/integration/partial_md_export_import_spec.rb +3 -3
  145. data/spec/logging_in_logging_out_spec.rb +2 -1
  146. data/spec/spec_helper.rb +26 -4
  147. data/spec/unit/bricks/bricks_spec.rb +15 -7
  148. data/spec/unit/bricks/middleware/bench_middleware_spec.rb +2 -0
  149. data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +2 -0
  150. data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +2 -0
  151. data/spec/unit/bricks/middleware/logger_middleware_spec.rb +2 -0
  152. data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +2 -0
  153. data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +2 -0
  154. data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +2 -0
  155. data/spec/unit/cli/cli_spec.rb +2 -0
  156. data/spec/unit/cli/commands/cmd_api_spec.rb +23 -15
  157. data/spec/unit/cli/commands/cmd_auth_spec.rb +8 -4
  158. data/spec/unit/cli/commands/cmd_domain_spec.rb +82 -0
  159. data/spec/unit/cli/commands/cmd_process_spec.rb +29 -13
  160. data/spec/unit/cli/commands/cmd_project_spec.rb +51 -30
  161. data/spec/unit/cli/commands/cmd_role_spec.rb +44 -0
  162. data/spec/unit/cli/commands/cmd_run_ruby_spec.rb +8 -4
  163. data/spec/unit/cli/commands/cmd_scaffold_spec.rb +48 -11
  164. data/spec/unit/cli/commands/cmd_user_spec.rb +29 -0
  165. data/spec/unit/commands/command_api_spec.rb +1 -1
  166. data/spec/unit/commands/command_auth_spec.rb +100 -18
  167. data/spec/unit/commands/command_dataset_spec.rb +4 -0
  168. data/spec/unit/commands/command_process_spec.rb +9 -4
  169. data/spec/unit/commands/command_projects_spec.rb +10 -6
  170. data/spec/unit/commands/command_scaffold_spec.rb +5 -1
  171. data/spec/unit/commands/command_user_spec.rb +22 -0
  172. data/spec/unit/core/connection_spec.rb +35 -6
  173. data/spec/unit/core/logging_spec.rb +65 -0
  174. data/spec/unit/core/nil_logger_spec.rb +9 -0
  175. data/spec/unit/core/project_spec.rb +51 -0
  176. data/spec/unit/core/rest_spec.rb +33 -0
  177. data/spec/unit/data/guesser_spec.rb +5 -0
  178. data/spec/unit/godzilla/goodzilla_spec.rb +2 -0
  179. data/spec/unit/models/account_settings_spec.rb +28 -0
  180. data/spec/unit/models/anchor_spec.rb +32 -0
  181. data/spec/unit/models/attribute_column_spec.rb +7 -0
  182. data/spec/unit/models/domain_spec.rb +45 -0
  183. data/spec/unit/models/invitation_spec.rb +13 -0
  184. data/spec/unit/models/md_object_spec.rb +47 -0
  185. data/spec/unit/models/metric.rb +92 -0
  186. data/spec/unit/{model → models}/model_spec.rb +9 -7
  187. data/spec/unit/models/project_blueprint_spec.rb +202 -0
  188. data/spec/unit/models/project_creator.rb +73 -0
  189. data/spec/unit/models/project_role_spec.rb +90 -0
  190. data/spec/unit/models/project_spec.rb +143 -0
  191. data/spec/unit/models/schedule_spec.rb +491 -0
  192. data/spec/unit/{model → models}/schema_builder_spec.rb +2 -0
  193. data/spec/unit/{model → models}/tools_spec.rb +13 -7
  194. data/spec/unit/models/user_spec.rb +16 -0
  195. data/test/test_upload.rb +2 -0
  196. metadata +189 -86
  197. data/lib/gooddata/commands/profile.rb +0 -11
  198. data/lib/gooddata/models/attribute.rb +0 -29
  199. data/lib/gooddata/models/display_form.rb +0 -9
  200. data/lib/gooddata/models/fact.rb +0 -19
  201. data/lib/gooddata/models/metric.rb +0 -99
  202. data/lib/gooddata/models/report.rb +0 -89
  203. data/spec/data/blueprint_valid.json +0 -37
  204. data/spec/unit/cli/commands/cmd_profile_spec.rb +0 -16
  205. data/spec/unit/commands/command_profile_spec.rb +0 -18
  206. data/spec/unit/core/core_spec.rb +0 -7
  207. data/spec/unit/model/blueprint_spec.rb +0 -132
  208. data/spec/unit/model/project_blueprint_spec.rb +0 -44
@@ -34,19 +34,27 @@ module GoodData
34
34
  # Get resource
35
35
  # @param path Resource path
36
36
  def get(path)
37
- raise(GoodData::CommandFailed, 'Specify the path you want to GET.') if path.nil?
37
+ fail(GoodData::CommandFailed, 'Specify the path you want to GET.') if path.nil?
38
38
  result = GoodData.get path
39
- result rescue puts result
39
+ begin
40
+ result
41
+ rescue
42
+ puts result
43
+ end
40
44
  end
41
45
 
42
46
  # Delete resource
43
47
  # @param path Resource path
44
48
  def delete(path)
45
- raise(GoodData::CommandFailed, 'Specify the path you want to DELETE.') if path.nil?
49
+ fail(GoodData::CommandFailed, 'Specify the path you want to DELETE.') if path.nil?
46
50
  result = GoodData.delete path
47
- result rescue puts result
51
+ begin
52
+ result
53
+ rescue
54
+ puts result
55
+ end
48
56
  end
49
57
  end
50
58
  end
51
59
  end
52
- end
60
+ end
@@ -6,57 +6,64 @@ require 'multi_json'
6
6
  require_relative '../cli/terminal'
7
7
  require_relative '../helpers'
8
8
 
9
- module GoodData::Command
10
- class Auth
11
- class << self
9
+ module GoodData
10
+ module Command
11
+ class Auth
12
+ class << self
13
+ # Get path of .gooddata config
14
+ def credentials_file
15
+ "#{GoodData::Helpers.home_directory}/.gooddata"
16
+ end
12
17
 
13
- # Get path of .gooddata config
14
- def credentials_file
15
- "#{GoodData::Helpers.home_directory}/.gooddata"
16
- end
18
+ # Ask for credentials
19
+ def ask_for_credentials
20
+ puts 'Enter your GoodData credentials.'
21
+ user = GoodData::CLI.terminal.ask('Email')
22
+ password = GoodData::CLI.terminal.ask('Password') { |q| q.echo = 'x' }
23
+ auth_token = GoodData::CLI.terminal.ask('Authorization Token')
17
24
 
18
- # Ask for credentials
19
- def ask_for_credentials
20
- puts 'Enter your GoodData credentials.'
21
- user = GoodData::CLI.terminal.ask('Email')
22
- password = GoodData::CLI.terminal.ask('Password') { |q| q.echo = 'x' }
23
- auth_token = GoodData::CLI.terminal.ask('Authorization Token')
25
+ { :username => user, :password => password, :auth_token => auth_token }
26
+ end
24
27
 
25
- {:username => user, :password => password, :auth_token => auth_token}
26
- end
28
+ # Read credentials
29
+ def read_credentials(credentials_file_path = credentials_file)
30
+ if File.exist?(credentials_file_path)
31
+ config = File.read(credentials_file_path)
32
+ MultiJson.load(config, :symbolize_keys => true)
33
+ else
34
+ {}
35
+ end
36
+ end
27
37
 
28
- # Read credentials
29
- def read_credentials
30
- if File.exists?(credentials_file) then
31
- config = File.read(credentials_file)
32
- JSON.parser.new(config, :symbolize_names => true).parse
33
- else
34
- {}
38
+ # Writes credentials
39
+ def write_credentials(credentials, credentials_file_path = credentials_file)
40
+ File.open(credentials_file_path, 'w', 0600) do |f|
41
+ f.puts MultiJson.encode(credentials, :pretty => true)
42
+ end
43
+ credentials
35
44
  end
36
- end
37
45
 
38
- # Ask for credentials and store them
39
- def store
40
- credentials = ask_for_credentials
46
+ # Ask for credentials and store them
47
+ def store(credentials_file_path = credentials_file)
48
+ credentials = ask_for_credentials
41
49
 
42
- ovewrite = if File.exist?(credentials_file)
43
- GoodData::CLI.terminal.ask("Overwrite existing stored credentials (y/n)")
44
- else
45
- 'y'
46
- end
50
+ ovewrite = if File.exist?(credentials_file_path)
51
+ GoodData::CLI.terminal.ask('Overwrite existing stored credentials (y/n)')
52
+ else
53
+ 'y'
54
+ end
47
55
 
48
- if ovewrite == 'y'
49
- File.open(credentials_file, 'w', 0600) do |f|
50
- f.puts JSON.pretty_generate(credentials)
56
+ if ovewrite == 'y'
57
+ write_credentials(credentials, credentials_file_path)
58
+ else
59
+ puts 'Aborting...'
51
60
  end
52
- else
53
- puts 'Aborting...'
54
61
  end
55
- end
56
62
 
57
- # Delete stored credentials
58
- def unstore
59
- FileUtils.rm_f(credentials_file)
63
+ # Delete stored credentials
64
+ def unstore(credentials_file_path = credentials_file)
65
+ FileUtils.rm_f(credentials_file_path)
66
+ end
60
67
  end
61
68
  end
62
69
  end
@@ -1,6 +1,8 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module GoodData::Command
4
- class Base
3
+ module GoodData
4
+ module Command
5
+ class Base
6
+ end
5
7
  end
6
8
  end
@@ -4,4 +4,4 @@ require 'pathname'
4
4
  base = Pathname(__FILE__).dirname.expand_path
5
5
  Dir.glob(base + '*.rb').each do |file|
6
6
  require file
7
- end
7
+ end
@@ -65,9 +65,18 @@ module GoodData
65
65
  # TODO: Review following connect replacement/reimplementation
66
66
  # connect
67
67
  with_project do |project_id|
68
- cfg_file = args.shift rescue nil
69
- raise(CommandFailed, "Usage: #{$0} <dataset config>") unless cfg_file
70
- config = JSON.load open(cfg_file) rescue raise(CommandFailed, "Error reading dataset config file '#{cfg_file}'")
68
+ begin
69
+ cfg_file = args.shift
70
+ rescue
71
+ raise(CommandFailed, 'Invalid arguments')
72
+ end
73
+
74
+ fail(CommandFailed, "Usage: #{$PROGRAM_NAME} <dataset config>") unless cfg_file
75
+ config = begin
76
+ JSON.load open(cfg_file)
77
+ rescue
78
+ raise(CommandFailed, "Error reading dataset config file '#{cfg_file}'")
79
+ end
71
80
  objects = Project[project_id].add_dataset config['title'], config['columns']
72
81
  puts "Dataset #{config['title']} added to the project, #{objects['uris'].length} metadata objects affected"
73
82
  end
@@ -88,8 +97,12 @@ module GoodData
88
97
  # connect
89
98
  with_project do |project_id|
90
99
  file, cfg_file = args
91
- raise(CommandFailed, "Usage: #{$0} datasets:load <file> <dataset config>") unless cfg_file
92
- config = JSON.load open(cfg_file) rescue raise(CommandFailed, "Error reading dataset config file '#{cfg_file}'")
100
+ fail(CommandFailed, "Usage: #{$PROGRAM_NAME} datasets:load <file> <dataset config>") unless cfg_file
101
+ begin
102
+ config = JSON.load open(cfg_file)
103
+ rescue
104
+ raise(CommandFailed, "Error reading dataset config file '#{cfg_file}'")
105
+ end
93
106
  schema = Model::Schema.new config
94
107
  Project[project_id].upload file, schema
95
108
  end
@@ -100,7 +113,7 @@ module GoodData
100
113
  def with_project
101
114
  unless @project_id
102
115
  @project_id = extract_option('--project')
103
- raise CommandFailed.new('Project not specified, use the --project switch') unless @project_id
116
+ fail(CommandFailed, 'Project not specified, use the --project switch') unless @project_id
104
117
  end
105
118
  yield @project_id
106
119
  end
@@ -124,7 +137,7 @@ module GoodData
124
137
  def create_dataset
125
138
  file = extract_option('--file-csv')
126
139
  return Extract::CsvFile.new(file) if file
127
- raise CommandFailed.new('Unknown data set. Please specify a data set using --file-csv option (more supported data sources to come!)')
140
+ fail(CommandFailed, 'Unknown data set. Please specify a data set using --file-csv option (more supported data sources to come!)')
128
141
  end
129
142
  end
130
143
  end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../exceptions/command_failed'
4
+ require_relative '../models/domain'
5
+
6
+ module GoodData
7
+ module Command
8
+ # Low level access to GoodData API
9
+ class Domain
10
+ attr_reader :name
11
+
12
+ class << self
13
+ def add_user(domain, login, password)
14
+ GoodData::Domain.add_user(domain, login, password)
15
+ end
16
+
17
+ def list_users(domain)
18
+ GoodData::Domain.users(domain)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,16 +1,20 @@
1
1
  # encoding: UTF-8
2
2
 
3
+ require 'pathname'
4
+
5
+ require_relative '../core/core'
6
+
3
7
  module GoodData
4
8
  module Command
5
9
  class Process
6
10
  class << self
7
- def list(options={})
11
+ def list(options = {})
8
12
  GoodData.with_project(options[:project_id]) do
9
- processes = GoodData::Process[:all]
13
+ GoodData::Process[:all]
10
14
  end
11
15
  end
12
16
 
13
- def get(options={})
17
+ def get(options = {})
14
18
  id = options[:process_id]
15
19
  fail 'Unspecified process id' if id.nil?
16
20
 
@@ -19,137 +23,39 @@ module GoodData
19
23
  end
20
24
  end
21
25
 
22
- def deploy(dir, options={})
23
- verbose = options[:verbose] || false
26
+ def delete(process_id, options = {})
24
27
  GoodData.with_project(options[:project_id]) do
25
- params = options[:params].nil? ? [] : [options[:params]]
26
- deploy_graph(dir, options.merge({:files_to_exclude => params}))
28
+ process = GoodData::Process[process_id]
29
+ process.delete
27
30
  end
28
31
  end
29
32
 
30
- def with_deploy(dir, options={}, &block)
31
- verbose = options[:verbose] || false
32
- GoodData.with_project(options[:project_id]) do |project|
33
+ # TODO: check files_to_exclude param. Does it do anything? It should check that in case of using CLI, it makes sure the files are not deployed
34
+ def deploy(dir, options = {})
35
+ GoodData.with_project(options[:project_id]) do
33
36
  params = options[:params].nil? ? [] : [options[:params]]
34
- if block
35
- begin
36
- res = deploy_graph(dir, options.merge({:files_to_exclude => params}))
37
- block.call(res)
38
- ensure
39
- self_link = res && res['process']['links']['self']
40
- GoodData.delete(self_link)
41
- end
42
- else
43
- deploy_graph(dir, options.merge({:files_to_exclude => params}))
44
- end
37
+ GoodData::Process.deploy(dir, options.merge(:files_to_exclude => params))
45
38
  end
46
39
  end
47
40
 
48
- def execute_process(link, dir, options={})
49
- dir = Pathname(dir)
50
- type = :ruby
51
- if type == :ruby
52
- result = GoodData.post(link, {
53
- :execution => {
54
- :graph => ('./main.rb').to_s,
55
- :params => options[:expanded_params]
56
- }
57
- })
58
- begin
59
- GoodData.poll(result, 'executionTask')
60
- rescue RestClient::RequestFailed => e
61
-
62
- ensure
63
- result = GoodData.get(result['executionTask']['links']['detail'])
64
- if result['executionDetail']['status'] == 'ERROR'
65
- fail "Runing process failed. You can look at a log here #{result["executionDetail"]["logFileName"]}"
66
- end
67
- end
68
- result
69
- else
70
- result = GoodData.post(link, {
71
- :execution => {
72
- :graph => dir + 'graphs/main.grf',
73
- :params => {}
74
- }
75
- })
76
- begin
77
- GoodData.poll(result, 'executionTask')
78
- rescue RestClient::RequestFailed => e
79
-
80
- ensure
81
- result = GoodData.get(result['executionTask']['links']['detail'])
82
- if result['executionDetail']['status'] == 'ERROR'
83
- fail "Runing process failed. You can look at a log here #{result["executionDetail"]["logFileName"]}"
84
- end
85
- end
86
- result
41
+ def execute_process(process_id, executable, options = {})
42
+ GoodData.with_project(options[:project_id]) do
43
+ process = GoodData::Process[process_id]
44
+ process.execute_process(executable, options)
87
45
  end
88
46
  end
89
47
 
90
- def run(dir, options={})
91
- email = options[:email]
48
+ def run(dir, executable, options = {})
92
49
  verbose = options[:v]
93
50
  dir = Pathname(dir)
94
51
  name = options[:name] || "Temporary deploy[#{dir}][#{options[:project_name]}]"
95
52
 
96
- with_deploy(dir, options.merge(:name => name)) do |deploy_response|
97
- puts HighLine::color('Executing', HighLine::BOLD) if verbose
98
- result = execute_process(deploy_response['process']['links']['executions'], dir, options)
99
- end
100
- end
101
-
102
- private
103
-
104
- def deploy_graph(dir, options={})
105
- dir = Pathname(dir) || fail('Directory is not specified')
106
- fail "\"#{dir}\" is not a directory" unless dir.directory?
107
- files_to_exclude = options[:files_to_exclude].map { |p| Pathname(p) }
108
-
109
- project_id = options[:project_id] || fail('Project Id has to be specified')
110
-
111
- type = options[:type] || 'GRAPH'
112
- deploy_name = options[:name]
113
- verbose = options[:verbose] || false
114
-
115
- puts HighLine::color("Deploying #{dir}", HighLine::BOLD) if verbose
116
- res = nil
117
-
118
- Tempfile.open('deploy-graph-archive') do |temp|
119
- Zip::OutputStream.open(temp.path) do |zio|
120
- FileUtils::cd(dir) do
121
-
122
- files_to_pack = Dir.glob('./**/*').reject { |f| files_to_exclude.include?(Pathname(dir) + f) }
123
- files_to_pack.each do |item|
124
- puts "including #{item}" if verbose
125
- unless File.directory?(item)
126
- zio.put_next_entry(item)
127
- zio.print IO.read(item)
128
- end
129
- end
130
- end
131
- end
132
-
133
- GoodData.upload_to_user_webdav(temp.path)
134
- process_id = options[:process]
135
-
136
- data = {
137
- :process => {
138
- :name => deploy_name,
139
- :path => "/uploads/#{File.basename(temp.path)}",
140
- :type => type
141
- }
142
- }
143
- res = if process_id.nil?
144
- GoodData.post("/gdc/projects/#{GoodData.project.pid}/dataload/processes", data)
145
- else
146
- GoodData.put("/gdc/projects/#{GoodData.project.pid}/dataload/processes/#{process_id}", data)
147
- end
53
+ GoodData::Process.with_deploy(dir, options.merge(:name => name)) do |process|
54
+ puts HighLine.color('Executing', HighLine::BOLD) if verbose
55
+ process.execute(executable, options)
148
56
  end
149
- puts HighLine::color("Deploy DONE #{dir}", HighLine::GREEN) if verbose
150
- res
151
57
  end
152
58
  end
153
59
  end
154
60
  end
155
- end
61
+ end
@@ -0,0 +1,147 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'pathname'
4
+
5
+ module GoodData
6
+ module Command
7
+ class Project
8
+ class << self
9
+ # Create new project based on options supplied
10
+ def create(options = {})
11
+ title = options[:title]
12
+ summary = options[:summary]
13
+ template = options[:template]
14
+ token = options[:token]
15
+
16
+ GoodData::Project.create(:title => title, :summary => summary, :template => template, :auth_token => token)
17
+ end
18
+
19
+ # Show existing project
20
+ def show(id)
21
+ GoodData::Project[id]
22
+ end
23
+
24
+ def invite(project_id, email, role, msg = GoodData::Project::DEFAULT_INVITE_MESSAGE)
25
+ msg = GoodData::Project::DEFAULT_INVITE_MESSAGE if msg.nil? || msg.empty?
26
+
27
+ project = GoodData::Project[project_id]
28
+ fail "Invalid project id '#{project_id}' specified" if project.nil?
29
+
30
+ project.invite(email, role, msg)
31
+ end
32
+
33
+ # Clone existing project
34
+ def clone(project_id, options)
35
+ with_data = options[:data] || true
36
+ with_users = options[:users] || false
37
+ export = {
38
+ :exportProject => {
39
+ :exportUsers => with_users ? 1 : 0,
40
+ :exportData => with_data ? 1 : 0
41
+ }
42
+ }
43
+
44
+ result = GoodData.post("/gdc/md/#{project_id}/maintenance/export", export)
45
+ export_token = result['exportArtifact']['token']
46
+ status_url = result['exportArtifact']['status']['uri']
47
+
48
+ state = GoodData.get(status_url)['taskState']['status']
49
+ while state == 'RUNNING'
50
+ sleep 5
51
+ result = GoodData.get(status_url)
52
+ state = result['taskState']['status']
53
+ end
54
+
55
+ old_project = GoodData::Project[project_id]
56
+ project_uri = create(options.merge(:title => "Clone of #{old_project.title}"))
57
+ new_project = GoodData::Project[project_uri]
58
+
59
+ import = {
60
+ :importProject => {
61
+ :token => export_token
62
+ }
63
+ }
64
+ result = GoodData.post("/gdc/md/#{new_project.obj_id}/maintenance/import", import)
65
+ status_url = result['uri']
66
+ state = GoodData.get(status_url)['taskState']['status']
67
+ while state == 'RUNNING'
68
+ sleep 5
69
+ result = GoodData.get(status_url)
70
+ state = result['taskState']['status']
71
+ end
72
+ true
73
+ end
74
+
75
+ # Delete existing project
76
+ def delete(project_id)
77
+ p = GoodData::Project[project_id]
78
+ p.delete
79
+ end
80
+
81
+ # Get Spec and ID (of project)
82
+ def get_spec_and_project_id(base_path)
83
+ goodfile_path = GoodData::Helpers.find_goodfile(Pathname(base_path))
84
+ fail 'Goodfile could not be located in any parent directory. Please make sure you are inside a gooddata project folder.' if goodfile_path.nil?
85
+ goodfile = JSON.parse(File.read(goodfile_path), :symbolize_names => true)
86
+ spec_path = goodfile[:model] || fail('You need to specify the path of the build spec')
87
+ fail "Model path provided in Goodfile \"#{spec_path}\" does not exist" unless File.exist?(spec_path) && !File.directory?(spec_path)
88
+
89
+ spec_path = Pathname(spec_path)
90
+
91
+ content = File.read(spec_path)
92
+ spec = if spec_path.extname == '.rb'
93
+ eval(content)
94
+ elsif spec_path.extname == '.json'
95
+ JSON.parse(spec_path, :symbolize_names => true)
96
+ end
97
+ [spec, goodfile[:project_id]]
98
+ end
99
+
100
+ def list_users(pid)
101
+ users = []
102
+ finished = false
103
+ offset = 0
104
+ # Limit set to 1000 to be safe
105
+ limit = 1000
106
+ until finished
107
+ result = GoodData.get('/gdc/projects/#{pid}/users?offset=#{offset}&limit=#{limit}')
108
+ result['users'].map do |u|
109
+ as = u['user']
110
+ users.push(
111
+ :login => as['content']['email'],
112
+ :uri => as['links']['self'],
113
+ :first_name => as['content']['firstname'],
114
+ :last_name => as['content']['lastname'],
115
+ :role => as['content']['userRoles'].first,
116
+ :status => as['content']['status']
117
+ )
118
+ end
119
+ if result['users'].count == limit
120
+ offset += limit
121
+ else
122
+ finished = true
123
+ end
124
+ end
125
+ users
126
+ end
127
+
128
+ # Update project
129
+ def update(options = {})
130
+ project = options[:project]
131
+ GoodData::Model::ProjectCreator.migrate(:spec => options[:spec], :project => project)
132
+ end
133
+
134
+ # Build project
135
+ def build(options = {})
136
+ GoodData::Model::ProjectCreator.migrate(:spec => options[:spec], :token => options[:token])
137
+ end
138
+
139
+ def validate(project_id)
140
+ GoodData.with_project(project_id) do |p|
141
+ p.validate
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end