gooddata 0.6.0.pre8 → 0.6.0.pre9

Sign up to get free protection for your applications and to get access to all the features.
data/bin/gooddata CHANGED
@@ -55,11 +55,11 @@ arg_name 'logger'
55
55
  switch [:l,:logger]
56
56
 
57
57
 
58
- desc 'Describe list here'
58
+ desc 'Work with deployed processes'
59
59
  arg_name 'Describe arguments to list here'
60
60
  command :process do |c|
61
61
 
62
- c.desc 'Use when you need to redeploy a process'
62
+ c.desc 'Use when you need to redeploy a specific process'
63
63
  c.default_value nil
64
64
  c.flag :process_id
65
65
 
@@ -75,6 +75,7 @@ command :process do |c|
75
75
  c.default_value nil
76
76
  c.flag :name
77
77
 
78
+ c.desc "Lists all user's processes deployed on the plaform"
78
79
  c.command :list do |list|
79
80
  list.action do |global_options,options,args|
80
81
  opts = options.merge(global_options)
@@ -83,6 +84,7 @@ command :process do |c|
83
84
  end
84
85
  end
85
86
 
87
+ c.desc "Gives you some basic info about the process"
86
88
  c.command :get do |get|
87
89
  get.action do |global_options,options,args|
88
90
  opts = options.merge(global_options)
@@ -91,6 +93,7 @@ command :process do |c|
91
93
  end
92
94
  end
93
95
 
96
+ c.desc "Deploys provided directory to the server"
94
97
  c.command :deploy do |deploy|
95
98
  deploy.action do |global_options,options,args|
96
99
  opts = options.merge(global_options)
@@ -105,6 +108,7 @@ desc 'Some basic API stuff directly from CLI'
105
108
  arg_name 'info|test|get|delete'
106
109
  command :api do |c|
107
110
 
111
+ c.desc "Info about the API version etc"
108
112
  c.command :info do |info|
109
113
  info.action do |global_options,options,args|
110
114
  opts = options.merge(global_options)
@@ -113,6 +117,7 @@ command :api do |c|
113
117
  end
114
118
  end
115
119
 
120
+ c.desc "GET request on our API"
116
121
  c.command :get do |get|
117
122
  get.action do |global_options,options,args|
118
123
  opts = options.merge(global_options)
@@ -128,6 +133,7 @@ desc 'Describe add here'
128
133
  arg_name 'show'
129
134
  command :profile do |c|
130
135
 
136
+ c.desc "Show your profile"
131
137
  c.command :show do |show|
132
138
  show.action do |global_options,options,args|
133
139
  opts = options.merge(global_options)
@@ -142,6 +148,7 @@ desc 'Scaffold things'
142
148
  arg_name 'show'
143
149
  command :scaffold do |c|
144
150
 
151
+ c.desc "Scaffold a gooddata project blueprint"
145
152
  c.command :project do |project|
146
153
  project.action do |global_options, options, args|
147
154
  name = args.first
@@ -150,6 +157,7 @@ command :scaffold do |c|
150
157
  end
151
158
  end
152
159
 
160
+ c.desc "Scaffold a gooddata ruby brick. This is a piece of code that you can run on our platform"
153
161
  c.command :brick do |brick|
154
162
  # brick.arg_name 'name'
155
163
  brick.action do |global_options, options, args|
@@ -164,6 +172,7 @@ desc 'Manage your projects'
164
172
  arg_name 'project_command'
165
173
  command :project do |c|
166
174
 
175
+ c.desc "Lists user's projects"
167
176
  c.command :list do |list|
168
177
  list.action do |global_options,options,args|
169
178
  opts = options.merge(global_options)
@@ -173,6 +182,7 @@ command :project do |c|
173
182
  end
174
183
  end
175
184
 
185
+ c.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"
176
186
  c.command :jack_in do |jack|
177
187
  jack.action do |global_options,options,args|
178
188
  goodfile_path = GoodData::Helpers.find_goodfile(Pathname('.'))
@@ -202,6 +212,7 @@ command :project do |c|
202
212
  end
203
213
  end
204
214
 
215
+ c.desc "Create a gooddata project"
205
216
  c.command :create do |create|
206
217
  create.action do |global_options,options,args|
207
218
  title = ask "Project name"
@@ -221,6 +232,7 @@ command :project do |c|
221
232
  end
222
233
  end
223
234
 
235
+ c.desc "Delete a project. Be careful this is impossible to revert"
224
236
  c.command :delete do |delete|
225
237
  delete.action do |global_options,options,args|
226
238
  id = global_options[:project_id]
@@ -230,6 +242,7 @@ command :project do |c|
230
242
  end
231
243
  end
232
244
 
245
+ c.desc "Clones a project. Useful for testing"
233
246
  c.command :clone do |clone|
234
247
  clone.desc 'Name of the new project'
235
248
  clone.default_value nil
@@ -246,6 +259,7 @@ command :project do |c|
246
259
  end
247
260
  end
248
261
 
262
+ c.desc "Shows basic info about a project"
249
263
  c.command :show do |show|
250
264
  show.action do |global_options,options,args|
251
265
  id = global_options[:project_id]
@@ -256,6 +270,7 @@ command :project do |c|
256
270
  end
257
271
  end
258
272
 
273
+ c.desc "If you are in a gooddata project blueprint it will apply the changes. If you do not provide a project id it will build it from scratch and create a project for you."
259
274
  c.command :build do |show|
260
275
  show.action do |global_options,options,args|
261
276
  goodfile = JSON.parse(File.read(GoodData::Helpers.find_goodfile(Pathname('.'))), :symbolize_names => true)
@@ -279,9 +294,10 @@ command :project do |c|
279
294
 
280
295
  end
281
296
 
282
- desc 'Work with your credentials'
297
+ desc 'Work with your locally stored credentials'
283
298
  command :auth do |c|
284
299
 
300
+ c.desc "Store your credentials to ~/.gooddata so client does not have to ask you every single time"
285
301
  c.command :store do |store|
286
302
  store.action do |global_options,options,args|
287
303
  GoodData::Command::Auth.store
@@ -290,7 +306,7 @@ command :auth do |c|
290
306
 
291
307
  end
292
308
 
293
- desc 'Run ruby bricks'
309
+ desc 'Run ruby bricks either locally or remotely deployed on our server'
294
310
  # arg_name 'show'
295
311
  command :run_ruby do |c|
296
312
 
@@ -313,7 +329,6 @@ command :run_ruby do |c|
313
329
  c.default_value nil
314
330
  c.flag [:n, :name]
315
331
 
316
-
317
332
  c.action do |global_options, options, args|
318
333
  options[:expanded_params] = if (options[:params])
319
334
  JSON.parse(File.read(options[:params]), :symbolize_names => true)
@@ -322,10 +337,10 @@ command :run_ruby do |c|
322
337
  end
323
338
 
324
339
  opts = options.merge(global_options).merge({:type => "RUBY"})
340
+ GoodData.connect(opts)
325
341
  if options[:remote]
326
342
  fail "You have to specify name of the deploy when deploying remotely" if options[:name].nil? || options[:name].empty?
327
343
  require 'gooddata/commands/process'
328
- GoodData.connect(opts)
329
344
  GoodData::Command::Process.run(options[:dir], opts) do
330
345
  puts "would run"
331
346
  end
@@ -25,9 +25,14 @@ module GoodData::SmallGoodZilla
25
25
  end
26
26
 
27
27
  def self.interpolate_ids(*ids)
28
- res = GoodData::MdObject.identifier_to_uri(*ids.flatten)
29
- fail "Not all of the identifiers were resolved" if (Array(res).size != ids.flatten.size)
30
- res
28
+ ids = ids.flatten
29
+ if ids.empty?
30
+ []
31
+ else
32
+ res = GoodData::MdObject.identifier_to_uri(*ids)
33
+ fail "Not all of the identifiers were resolved" if (Array(res).size != ids.size)
34
+ res
35
+ end
31
36
  end
32
37
 
33
38
  def self.interpolate_values(keys, values)
@@ -95,6 +95,15 @@ module GoodData
95
95
  puts "Done loading"
96
96
  end
97
97
 
98
+ def merge_dataset_columns(a_schema_blueprint, b_schema_blueprint)
99
+ d = Marshal.load(Marshal.dump(a_schema_blueprint))
100
+ d[:columns] = d[:columns] + b_schema_blueprint[:columns]
101
+ d[:columns].uniq!
102
+ columns_that_failed_to_merge = d[:columns].group_by {|x| x[:name]}.map {|k, v| [k, v.count]}.find_all {|x| x[1] > 1}
103
+ fail "Columns #{columns_that_failed_to_merge} failed to merge. When merging columns with the same name they have to be identical." unless columns_that_failed_to_merge.empty?
104
+ d
105
+ end
106
+
98
107
  end
99
108
 
100
109
  class ProjectBlueprint
@@ -122,6 +131,28 @@ module GoodData
122
131
  @data = init_data
123
132
  end
124
133
 
134
+ def model_validate
135
+ if datasets.count == 1
136
+ []
137
+ else
138
+ x = datasets.reduce([]) {|memo, schema| schema.has_anchor? ? memo << [schema.name, schema.anchor[:name]] : memo }
139
+ refs = datasets.reduce([]) do |memo, dataset|
140
+ memo.concat(dataset.references)
141
+ end
142
+ refs.reduce([]) do |memo, ref|
143
+ x.include?([ref[:dataset], ref[:reference]]) ? memo : memo.concat([ref])
144
+ end
145
+ end
146
+ end
147
+
148
+ def model_valid?
149
+ errors = model_validate
150
+ errors.empty? ? true :false
151
+ end
152
+
153
+ def title
154
+ data[:title]
155
+ end
125
156
  end
126
157
 
127
158
  class SchemaBlueprint
@@ -162,6 +193,34 @@ module GoodData
162
193
  data[:columns]
163
194
  end
164
195
 
196
+ def has_anchor?
197
+ columns.any? {|c| c[:type] == :anchor}
198
+ end
199
+
200
+ def anchor
201
+ find_column_by_type(:anchor, :first)
202
+ end
203
+
204
+ def references
205
+ find_column_by_type(:reference)
206
+ end
207
+
208
+ def find_column_by_type(type, all=:all)
209
+ if all == :all
210
+ columns.find_all {|c| c[:type] == type}
211
+ else
212
+ columns.find {|c| c[:type] == type}
213
+ end
214
+ end
215
+
216
+ def find_column_by_name(type, all=:all)
217
+ if all == :all
218
+ columns.find_all {|c| c[:name] == type}
219
+ else
220
+ columns.find {|c| c[:name] == type}
221
+ end
222
+ end
223
+
165
224
  def to_schema
166
225
  Schema.new(to_hash)
167
226
  end
@@ -177,6 +236,11 @@ module GoodData
177
236
  printer.text columns.map {|c| " #{c[:name]}: #{c[:type]}"}.join("\n")
178
237
  end
179
238
 
239
+ def dup
240
+ deep_copy = Marshal.load(Marshal.dump(data))
241
+ SchemaBlueprint.new(deep_copy)
242
+ end
243
+
180
244
  end
181
245
 
182
246
  class ProjectBuilder
@@ -218,7 +282,15 @@ module GoodData
218
282
  def add_dataset(name, &block)
219
283
  builder = GoodData::Model::SchemaBuilder.new(name)
220
284
  block.call(builder)
221
- @datasets << builder.to_hash
285
+ if @datasets.any? {|item| item[:name] == name}
286
+ ds = @datasets.find {|item| item[:name] == name}
287
+ index = @datasets.index(ds)
288
+ stuff = GoodData::Model.merge_dataset_columns(ds, builder.to_hash)
289
+ @datasets.delete_at(index)
290
+ @datasets.insert(index, stuff)
291
+ else
292
+ @datasets << builder.to_hash
293
+ end
222
294
  end
223
295
 
224
296
  def add_report(title, options={})
@@ -25,13 +25,13 @@ module GoodData
25
25
  def create(options={})
26
26
  if options.is_a?(String)
27
27
  expression = options
28
- extended_notation = true
28
+ extended_notation = false
29
29
  title = nil
30
30
  else
31
31
  title = options[:title]
32
32
  summary = options[:summary]
33
33
  expression = options[:expression] || fail("Metric has to have its expression defined")
34
- extended_notation = options[:extended_notation]
34
+ extended_notation = options[:extended_notation] || false
35
35
  end
36
36
 
37
37
  expression = if extended_notation
@@ -62,12 +62,20 @@ module GoodData
62
62
  end
63
63
 
64
64
  def execute(expression, options={})
65
- m = GoodData::Metric.create({:title => "Temporary metric to be deleted", :expression => expression}.merge(options))
65
+ m = if expression.is_a?(String)
66
+ GoodData::Metric.create({:title => "Temporary metric to be deleted", :expression => expression}.merge(options))
67
+ else
68
+ GoodData::Metric.create({:title => "Temporary metric to be deleted"}.merge(expression))
69
+ end
66
70
  m.execute
67
71
  end
68
72
 
69
73
  def xexecute(expression)
70
- execute(expression, {:extended_notation => true})
74
+ if expression.is_a?(String)
75
+ execute({:expression => expression, :extended_notation => true})
76
+ else
77
+ execute(expression.merge({:extended_notation => true}))
78
+ end
71
79
  end
72
80
 
73
81
  end
@@ -1,3 +1,3 @@
1
1
  module GoodData
2
- VERSION = "0.6.0.pre8"
2
+ VERSION = "0.6.0.pre9"
3
3
  end
@@ -0,0 +1,92 @@
1
+ require 'gooddata/model'
2
+ require 'pry'
3
+
4
+ describe GoodData::Model::ProjectBlueprint do
5
+
6
+ before(:each) do
7
+ @valid_blueprint = blueprint = GoodData::Model::ProjectBlueprint.new(
8
+ {
9
+ :title => "x",
10
+ :datasets => [
11
+ {
12
+ :name=>"payments",
13
+ :columns => [
14
+ {:type=>:attribute, :name=>"id"},
15
+ {:type=>:fact, :name=>"amount"},
16
+ {:type=>:reference, :name=>"user_id", :dataset => "users", :reference => "user_id"},
17
+ ]
18
+ },
19
+ {
20
+ :name=>"users",
21
+ :columns => [
22
+ {:type=>:anchor, :name=>"user_id"},
23
+ {:type=>:fact, :name=>"amount"}]
24
+ }
25
+ ]})
26
+
27
+ @invalid_blueprint = blueprint = GoodData::Model::ProjectBlueprint.new(
28
+ {
29
+ :title => "x",
30
+ :datasets => [
31
+ {
32
+ :name=>"payments",
33
+ :columns => [
34
+ {:type=>:attribute, :name=>"id"},
35
+ {:type=>:fact, :name=>"amount"},
36
+ {:type=>:reference, :name=>"user_id", :dataset => "users", :reference => "user_id"},
37
+ ]
38
+ },
39
+ {
40
+ :name=>"users",
41
+ :columns => [
42
+ {:type=>:attribute, :name=>"user_id"},
43
+ {:type=>:fact, :name=>"amount"}]
44
+ }
45
+ ]})
46
+
47
+ end
48
+
49
+ it "valid blueprint should be marked as valid" do
50
+ @valid_blueprint.model_valid?.should == true
51
+ end
52
+
53
+ it "valid blueprint should give you empty array of errors" do
54
+ expect(@valid_blueprint.model_validate).to be_empty
55
+ end
56
+
57
+ it "invalid blueprint should be marked as invalid" do
58
+ @invalid_blueprint.model_valid?.should == false
59
+ end
60
+
61
+ it "invalid blueprint should give you list of violating references" do
62
+ errors = @invalid_blueprint.model_validate
63
+ errors.size.should == 1
64
+ errors.first.should == {:type=>:reference,
65
+ :name=>"user_id",
66
+ :dataset=>"users",
67
+ :reference=>"user_id"}
68
+ end
69
+
70
+ it "references return empty array if there is no reference" do
71
+ refs = @valid_blueprint.get_dataset("users").references
72
+ expect(refs).to be_empty
73
+ end
74
+
75
+ it "should be able to get dataset by name" do
76
+ ds = @valid_blueprint.get_dataset("users")
77
+ ds.name.should == "users"
78
+ end
79
+
80
+ it "should tell you it has anchor when it does" do
81
+ ds = @valid_blueprint.get_dataset("users")
82
+ ds.has_anchor?.should == true
83
+ end
84
+
85
+ it "should tell you it does not have anchor when it does not" do
86
+ ds = @invalid_blueprint.get_dataset("users")
87
+ ds.has_anchor?.should == false
88
+ end
89
+
90
+
91
+
92
+ end
@@ -51,4 +51,21 @@ describe "Spin a project", :constraint => 'slow' do
51
51
  k.should include("manifest_devs")
52
52
  end
53
53
  end
54
+
55
+ it "should be able to interpolate metric based on" do
56
+ GoodData.with_project(@project) do |p|
57
+ res = GoodData::Metric.xexecute "SELECT SUM(![fact.commits.lines_changed])"
58
+ res.should == 9
59
+
60
+ res = GoodData::Metric.xexecute({:expression => "SELECT SUM(![fact.commits.lines_changed])"})
61
+ res.should == 9
62
+
63
+ res = GoodData::Metric.execute({:expression => "SELECT SUM(![fact.commits.lines_changed])", :extended_notation => true})
64
+ res.should == 9
65
+
66
+ res = GoodData::Metric.execute("SELECT SUM(![fact.commits.lines_changed])", :extended_notation => true)
67
+ res.should == 9
68
+ end
69
+ end
70
+
54
71
  end
@@ -0,0 +1,89 @@
1
+ require 'gooddata/model'
2
+ require 'pry'
3
+
4
+ describe GoodData::Model::ProjectBlueprint do
5
+
6
+ before(:each) do
7
+ @base_blueprint = blueprint = GoodData::Model::ProjectBlueprint.new(
8
+ {
9
+ :title => "x",
10
+ :datasets => [
11
+ {
12
+ :name=>"payments",
13
+ :columns => [
14
+ {:type=>:attribute, :name=>"id"},
15
+ {:type=>:fact, :name=>"amount"},
16
+ {:type=>:reference, :name=>"user_id", :dataset => "users", :reference => "user_id"},
17
+ ]
18
+ },
19
+ {
20
+ :name=>"users",
21
+ :columns => [
22
+ {:type=>:anchor, :name=>"user_id"},
23
+ {:type=>:fact, :name=>"amount"}]
24
+ }
25
+ ]})
26
+
27
+ @additional_blueprint = GoodData::Model::ProjectBlueprint.new(
28
+ {
29
+ :title => "x",
30
+ :datasets => [
31
+ {
32
+ :name=>"users",
33
+ :columns => [
34
+ {:type=>:attribute, :name=>"region"}
35
+ ]
36
+ }
37
+ ]})
38
+
39
+ @blueprint_with_duplicate = GoodData::Model::ProjectBlueprint.new(
40
+ {
41
+ :title => "x",
42
+ :datasets => [
43
+ {
44
+ :name=>"users",
45
+ :columns => [
46
+ {:type=>:fact, :name=>"amount"}
47
+ ]
48
+ }
49
+ ]})
50
+
51
+ @conflicting_blueprint = GoodData::Model::ProjectBlueprint.new(
52
+ {
53
+ :title => "x",
54
+ :datasets => [
55
+ {
56
+ :name=>"users",
57
+ :columns => [
58
+ {:type=>:attribute, :name=>"amount"}
59
+ ]
60
+ }
61
+ ]})
62
+ end
63
+
64
+ it "should be possible to merge Schema blueprints" do
65
+ first_dataset = @base_blueprint.get_dataset("users").to_hash
66
+ additional_blueprint = @additional_blueprint.get_dataset("users").to_hash
67
+ stuff = GoodData::Model.merge_dataset_columns(first_dataset, additional_blueprint)
68
+ stuff[:columns].include?({:type=>:attribute, :name=>"region"}).should == true
69
+ stuff[:columns].include?({:type=>:fact, :name=>"amount"}).should == true
70
+ end
71
+
72
+ it "should pass when merging 2 columns with the same name if all attributes are identical" do
73
+ first_dataset = @base_blueprint.get_dataset("users").to_hash
74
+ additional_blueprint = @blueprint_with_duplicate.get_dataset("users").to_hash
75
+ stuff = GoodData::Model.merge_dataset_columns(first_dataset, additional_blueprint)
76
+
77
+ stuff[:columns].count.should == 2
78
+ stuff[:columns].include?({:type=>:fact, :name=>"amount"}).should == true
79
+ stuff[:columns].include?({:type=>:anchor, :name=>"user_id"}).should == true
80
+ end
81
+
82
+ it "should pass when merging 2 columns with the same name if all attributes are identical" do
83
+ first_dataset = @base_blueprint.get_dataset("users").to_hash
84
+ additional_blueprint = @conflicting_blueprint.get_dataset("users").to_hash
85
+
86
+ expect{GoodData::Model.merge_dataset_columns(first_dataset, additional_blueprint)}.to raise_error
87
+ end
88
+
89
+ end
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.0.pre8
4
+ version: 0.6.0.pre9
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -321,8 +321,10 @@ files:
321
321
  - lib/templates/project/data/devs.csv
322
322
  - lib/templates/project/data/repos.csv
323
323
  - lib/templates/project/model/model.rb.erb
324
+ - spec/blueprint_spec.rb
324
325
  - spec/full_project_spec.rb
325
326
  - spec/goodzilla_spec.rb
327
+ - spec/merging_blueprints_spec.rb
326
328
  - spec/model_dsl_spec.rb
327
329
  - spec/test_project_model_spec.json
328
330
  - test/test_commands.rb