goodot 0.0.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.
Binary file
@@ -0,0 +1,7 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2016 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
+ $LOAD_PATH.unshift File.dirname(__FILE__)
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2016 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 'gli'
8
+ require 'pathname'
9
+ require 'pp'
10
+
11
+ require_relative 'shared'
12
+ require_relative '../version'
13
+
14
+ module GoodData
15
+ module GoodotCLI
16
+ include GLI::App
17
+ extend self
18
+
19
+ def self.launch(args)
20
+ exit run args
21
+ end
22
+
23
+ subcommand_option_handling :normal
24
+ program_desc 'Toolset for helping with lifecycle management of the project'
25
+ end
26
+ end
27
+
28
+ cmds = File.absolute_path(File.join(File.dirname(__FILE__), 'cmd'))
29
+ Dir.glob(cmds + '/*.rb').each do |file|
30
+ require file
31
+ end
32
+
33
+ GoodData::GoodotCLI.launch(ARGV)
@@ -0,0 +1,7 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2016 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_relative 'app'
@@ -0,0 +1,170 @@
1
+ module GoodData
2
+ module GoodotCLI
3
+ desc 'Manage app'
4
+ command :app do |c|
5
+ c.desc 'Synchronize clients'
6
+ c.command :synchronize do |sync|
7
+ sync.desc 'Segment'
8
+ sync.flag [:s, :segment]
9
+
10
+ sync.action do |global_options, options, _args|
11
+ ok_key = 'OK'
12
+
13
+ domain = global_options[:gd_domain]
14
+ results = if options[:segment]
15
+ segment = domain.segments(options[:segment])
16
+ [segment.synchronize_clients]
17
+ else
18
+ domain.synchronize_clients
19
+ end
20
+ res = results.pmapcat { |r| r.details.items }.group_by { |x| x['status'] }
21
+ if res.key?(ok_key) && res.keys.count == 1
22
+ puts HighLine.color("#{res[ok_key].count} syncs ended up in state #{ok_key}", :green)
23
+ else
24
+ res.except(ok_key).each do |k, v|
25
+ puts "#{v.count} syncs ended up in state #{k}."
26
+ puts 'Printing first 10'
27
+ v.each { |x| puts x['id'] }
28
+ end
29
+ fail HighLine.color("Some synchronizations ended up in different state than #{ok_key}", :red) unless res.except(ok_key).empty?
30
+ end
31
+ end
32
+ end
33
+
34
+ c.desc 'Export association for backup'
35
+ c.command :'export-association' do |export|
36
+ export.desc 'Without project ids'
37
+ export.switch [:'without-project']
38
+ export.default_value false
39
+
40
+ export.desc 'File for output'
41
+ export.flag [:f, :file]
42
+
43
+ export.action do |global_options, options, _args|
44
+ domain = global_options[:gd_domain]
45
+ results = domain.segments.pmapcat { |s| s.clients.map { |cl| [s, cl] } }
46
+ res = results.map do |s, cl|
47
+ {
48
+ segment: s.id,
49
+ id: cl.id
50
+ }.tap do |h|
51
+ h[:project] = cl.project.uri unless options['without-project']
52
+ end
53
+ end
54
+ file = options[:file]
55
+ if file
56
+ File.open(file, 'w') { |f| f << MultiJson.dump(res, pretty: true) }
57
+ else
58
+ puts MultiJson.dump(res, pretty: true)
59
+ end
60
+ end
61
+ end
62
+
63
+ c.desc 'Import association from backup'
64
+ c.command :'import-association' do |export|
65
+ export.desc 'File for output'
66
+ export.flag [:f, :file]
67
+
68
+ export.action do |global_options, options, _args|
69
+ domain = global_options[:gd_domain]
70
+ specification = MultiJson.load(File.read(options[:file]), symbolize_keys: true)
71
+ domain.update_clients(specification, delete_extra: true)
72
+ end
73
+ end
74
+
75
+ c.desc 'Spin up projects'
76
+ c.command :'spin-up-projects' do |spin|
77
+ spin.desc 'Segment'
78
+ spin.flag [:s, :segment]
79
+
80
+ spin.action do |global_options, _options, _args|
81
+ domain = global_options[:gd_domain]
82
+ results = domain.provision_client_projects
83
+ if results.to_a.empty?
84
+ puts HighLine.color('Everything seems to be up to date. Nothing was done!', :green)
85
+ else
86
+ puts HighLine.color("#{results.count} operations were performed", :green)
87
+ puts
88
+ results.group_by(&:status).each do |status, group|
89
+ puts HighLine.color("#{group.count} #{status} operations were performed", :green)
90
+ puts table_with_headers(group, [:id, :project_uri])
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ c.desc 'Add segment'
97
+ c.command :'create-segment' do |seg|
98
+ seg.desc 'Segment'
99
+ seg.flag [:s, :segment]
100
+
101
+ seg.desc 'Master project'
102
+ seg.flag [:p, :project]
103
+
104
+ seg.action do |global_options, options, _args|
105
+ client = global_options[:gd_client]
106
+ domain = global_options[:gd_domain]
107
+ segment_id = options[:segment]
108
+ project_id = options[:project]
109
+ fail 'Segment needs to be provided' unless segment_id
110
+ fail 'Project id needs to be provided' unless project_id
111
+ project = client.projects(project_id)
112
+
113
+ begin
114
+ s = domain.create_segment(segment_id: segment_id, master_project: project)
115
+ puts HighLine.color("Segment #{s.id} created!", :green)
116
+ rescue RuntimeError => e
117
+ raise create_api_error_message(e)
118
+ end
119
+ end
120
+ end
121
+
122
+ c.desc 'Add client'
123
+ c.command :'add-client' do |add|
124
+ add.desc 'Segment'
125
+ add.flag [:s, :segment]
126
+
127
+ add.desc 'Client ID'
128
+ add.flag [:c, :client]
129
+
130
+ add.action do |global_options, options, _args|
131
+ domain = global_options[:gd_domain]
132
+ segment_id = options[:segment]
133
+ client_id = options[:client]
134
+ fail 'Segment needs to be provided' unless segment_id
135
+ fail 'client ID needs to be provided.' unless client_id
136
+
137
+ s = domain.segments(segment_id)
138
+ begin
139
+ c = s.create_client(id: client_id)
140
+ puts HighLine.color("client #{c.id} created!", :green)
141
+ rescue RuntimeError => e
142
+ raise create_api_error_message(e)
143
+ end
144
+ end
145
+ end
146
+
147
+ c.desc 'App stats'
148
+ c.command :stats do |add|
149
+ add.action do |global_options, _options, _args|
150
+ client = global_options[:gd_client]
151
+ domain = global_options[:gd_domain]
152
+
153
+ all_projects = client.projects.to_a
154
+ master_projects = domain.segments.pmap(&:master_project)
155
+ client_projects = domain.segments.pmapcat { |s| s.clients.map(&:project).compact }
156
+
157
+ puts HighLine.color('Projects', :bold)
158
+ puts "This app contains #{all_projects.count} projects"
159
+ puts "Out of those #{master_projects.count} are linked as masters"
160
+ puts "Out of those #{client_projects.count} are linked as clients"
161
+
162
+ unused_projects_pids = (all_projects.map(&:pid) - master_projects.map(&:pid) - client_projects.map(&:pid))
163
+ puts "Additional #{unused_projects_pids.count} projects are in this account"
164
+ puts 'Printing first 10'
165
+ puts table_with_headers(unused_projects_pids.take(10).pmap { |pid| client.projects(pid) }, [:pid, :title])
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2015, Tomas Korcak <korczis@gmail.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require_relative '../shared'
24
+
25
+ module GoodData
26
+ module GoodotCLI
27
+ desc 'Manage clients in your application'
28
+ command :clients do |c|
29
+ c.desc 'List clients'
30
+ c.command :list do |add|
31
+ add.desc 'Filter on particular segment'
32
+ add.default_value :all
33
+ add.flag [:s, :segment]
34
+
35
+ add.action do |global_options, options, _args|
36
+ domain = global_options[:gd_domain]
37
+ segment_id = options[:segment]
38
+ table = Terminal::Table.new do |t|
39
+ t << ['Client Id', 'Segment URI', 'Project URI']
40
+ t << :separator
41
+ Array(domain.segments(segment_id)).pmapcat(&:clients).each { |s| t.add_row([s.client_id, s.segment_uri, s.project_uri]) }
42
+ end
43
+ puts table
44
+ end
45
+ end
46
+
47
+ c.desc 'Remove client'
48
+ c.command :remove do |remove|
49
+ remove.desc 'Client'
50
+ remove.flag [:c, :client]
51
+
52
+ remove.desc 'Delete the project'
53
+ remove.default_value false
54
+ remove.switch [:d, :'delete-project']
55
+
56
+ remove.action do |global_options, options, _args|
57
+ domain = global_options[:gd_domain]
58
+ client_name = options[:client]
59
+ fail 'Client needs to be provided' unless client_name
60
+ client = domain.clients(segment_name)
61
+ project = client.project
62
+ client.delete
63
+ project.delete if options[:d]
64
+ end
65
+ end
66
+
67
+ c.desc 'Reset client. Removes the project from the client.'
68
+ c.command :reset do |reset|
69
+ reset.desc 'Client'
70
+ reset.flag [:c, :client]
71
+
72
+ reset.desc 'Delete the project'
73
+ reset.default_value false
74
+ reset.switch [:d, :'delete-project']
75
+
76
+ reset.action do |global_options, options, _args|
77
+ domain = global_options[:gd_domain]
78
+ client_name = options[:client]
79
+ fail 'Client needs to be provided' unless client_name
80
+ client = domain.clients.find { |cl| cl.id == client_name }
81
+ project = client.project
82
+ client.project = nil
83
+ client.save
84
+ project.delete if options[:d]
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../shared'
2
+
3
+ module GoodData
4
+ module GoodotCLI
5
+ desc 'Jacks you in to work interactively with your project.'
6
+ command ['jack-in', 'jack_in'] do |c|
7
+ c.action do |global_options, _options, _args|
8
+ client = global_options[:gd_client]
9
+ domain = global_options[:gd_domain]
10
+ binding.pry(quiet: true, # rubocop:disable Lint/Debugger
11
+ prompt: [proc do |_target_self, _nest_level, _pry|
12
+ 'app_live_session: '
13
+ end])
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,67 @@
1
+ # # encoding: utf-8
2
+ #
3
+ # # Copyright (c) 2015, Tomas Korcak <korczis@gmail.com>
4
+ # #
5
+ # # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # # of this software and associated documentation files (the "Software"), to deal
7
+ # # in the Software without restriction, including without limitation the rights
8
+ # # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # # copies of the Software, and to permit persons to whom the Software is
10
+ # # furnished to do so, subject to the following conditions:
11
+ # #
12
+ # # The above copyright notice and this permission notice shall be included in
13
+ # # all copies or substantial portions of the Software.
14
+ # #
15
+ # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # # THE SOFTWARE.
22
+
23
+ require_relative '../shared'
24
+
25
+ module GoodData
26
+ module GoodotCLI
27
+ desc 'Manage masters'
28
+ command :masters do |c|
29
+ c.desc 'List masters'
30
+ c.command :list do |add|
31
+ add.action do |global_options, _options, _args|
32
+ domain = global_options[:gd_domain]
33
+ currently_used = domain.segments.pmap { |s| [s, s.master_project] }.compact
34
+
35
+ puts table_with_headers(currently_used,
36
+ [
37
+ proc { |_, p| p && p.pid },
38
+ proc { |_, p| p && p.title },
39
+ proc { |s, _| s.id },
40
+ proc { |_, p| p && p.metadata['GD_LCM_VERSION'] }
41
+ ],
42
+ headers: ['PID', 'Title', 'Segment ID', 'Version'])
43
+ end
44
+ end
45
+
46
+ c.desc 'Clone master of particular segment'
47
+ c.command :clone do |add|
48
+ add.desc 'Segment which master will be cloned'
49
+ add.default_value nil
50
+ add.flag [:s, :segment]
51
+
52
+ add.desc 'Authorization token'
53
+ add.default_value nil
54
+ add.flag [:t, :token]
55
+
56
+ add.action do |global_options, options, _args|
57
+ domain = global_options[:gd_domain]
58
+ fail 'You have to specify segment' unless options[:segment]
59
+ master_project = domain.segments(options[:segment]).master_project
60
+ clone = GoodData::Project.clone_with_etl(master_project, auth_token: options[:token])
61
+ puts "Project \"#{master_project.title}\" (#{master_project.pid}) was cloned."
62
+ puts "\"#{clone.title}\" (#{clone.pid}) was created."
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,81 @@
1
+ module GoodData
2
+ module GoodotCLI
3
+ desc 'Manage segments'
4
+ command :segments do |c|
5
+ c.desc 'List segments'
6
+ c.command :list do |add|
7
+ add.desc 'Format'
8
+ add.default_value :table
9
+ add.flag [:f, :format]
10
+
11
+ add.action do |global_options, options, _args|
12
+ domain = global_options[:gd_domain]
13
+
14
+ segments = domain.segments
15
+ case options[:format].to_sym
16
+ when :table
17
+ puts table_with_headers(segments, [:id, :master_project_id])
18
+ when :json
19
+ output = segments.map do |s|
20
+ {
21
+ name: s.id,
22
+ master_project_id: s.master_project_id
23
+ }
24
+ end
25
+ puts MultiJson.dump(output, pretty: true)
26
+ end
27
+ end
28
+ end
29
+
30
+ c.desc 'Remove segment'
31
+ c.command [:remove, :delete] do |add|
32
+ add.desc 'Segment'
33
+ add.flag [:s, :segment]
34
+
35
+ add.desc 'Delete also the clients in that particular segment'
36
+ add.default_value false
37
+ add.switch [:c, :cascade]
38
+
39
+ add.action do |global_options, options, _args|
40
+ domain = global_options[:gd_domain]
41
+ segment_name = options[:segment]
42
+ fail 'Segment needs to be provided' unless segment_name
43
+ segment = domain.segments(segment_name)
44
+ segment.clients.peach(&:delete) if options[:cascade]
45
+ segment.delete
46
+ end
47
+ end
48
+
49
+ c.desc 'Exchange master on segment.'
50
+ c.command :exchange do |exchange|
51
+ exchange.desc 'Segment'
52
+ exchange.flag [:s, :segment]
53
+
54
+ exchange.desc 'Master project ID'
55
+ exchange.flag [:p, :project]
56
+
57
+ exchange.desc 'Delete the old project'
58
+ exchange.default_value false
59
+ exchange.switch [:d, :delete]
60
+
61
+ exchange.action do |global_options, options, _args|
62
+ client = global_options[:gd_client]
63
+ domain = global_options[:gd_domain]
64
+
65
+ segment_name = options[:segment]
66
+ fail 'Segment needs to be provided' unless segment_name
67
+ segment = domain.segments(segment_name)
68
+
69
+ project_id = options[:project]
70
+ fail 'Project Master id needs to be provided' unless project_id
71
+ old_master = segment.master_project
72
+ new_master_project = client.projects(project_id)
73
+
74
+ segment.master_project = new_master_project
75
+ segment.save
76
+ old_master.delete if options[:delete]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end