brightpearl-cli 1.1.0

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.
data/lib/core/jira.rb ADDED
@@ -0,0 +1,43 @@
1
+ module Brightpearl
2
+
3
+ class Jira
4
+
5
+ # Initialise credentials
6
+ # @return void
7
+ def initialize
8
+ end
9
+
10
+ # Gets jira number from an argument. Displays error if invalid.
11
+ # @return int
12
+ def get_jira_number_from_arg(argument)
13
+ jira_number = nil
14
+ jira_number_possible = argument
15
+ jira_number_possible.split('-').each do |pjn|
16
+ if validate_jira_number(pjn)
17
+ jira_number = pjn
18
+ break
19
+ end
20
+ end
21
+ if jira_number.nil?
22
+ Brightpearl::Terminal::error('Invalid Jira Number', "The Jira Number must be a 4-5 digit number. You tried to pass: #{Brightpearl::Terminal::format_invalid(argument)}", true)
23
+ end
24
+ jira_number
25
+ end
26
+
27
+ # Validates that string is a number between 1 - 20,0000
28
+ # @return boolean
29
+ def validate_jira_number(value)
30
+ begin
31
+ value = Integer value
32
+ if value < 0 || value > 20000
33
+ return false
34
+ end
35
+ return true
36
+ rescue
37
+ return false
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ end
data/lib/core/mysql.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'mysql'
2
+
3
+ module Brightpearl
4
+
5
+ class MySQL
6
+
7
+ DEFAULT_SCHEMA = 'app'
8
+
9
+ @database_connection = nil
10
+
11
+ @ids_customers = []
12
+ @ids_shipping = []
13
+
14
+ def self.get_database_connection(schema = DEFAULT_SCHEMA)
15
+ if @database_connection == nil
16
+ @database_connection = Mysql.new(
17
+ Brightpearl::Config.param(Brightpearl::Config::VM_IP),
18
+ Brightpearl::Config.param(Brightpearl::Config::VM_MYSQL_USER),
19
+ Brightpearl::Config.param(Brightpearl::Config::VM_MYSQL_PASSWORD),
20
+ schema
21
+ )
22
+ end
23
+ @database_connection
24
+ end
25
+
26
+ def self.get_random_customer_id
27
+ unless @ids_customers.any?
28
+ customers = Brightpearl::MySQL::get_database_connection.query('SELECT customers_id FROM customers ORDER BY customers_id DESC LIMIT 100')
29
+ customers.each_hash do |row|
30
+ @ids_customers << row['customers_id']
31
+ end
32
+ end
33
+ @ids_customers.sample
34
+ end
35
+
36
+ def self.get_random_shipping_id
37
+ unless @ids_shipping.any?
38
+ ship_methods = Brightpearl::MySQL::get_database_connection.query('SELECT ship_method_id FROM ship_methods ORDER BY ship_method_id DESC LIMIT 100')
39
+ ship_methods.each_hash do |row|
40
+ @ids_shipping << row['ship_method_id']
41
+ end
42
+ end
43
+ @ids_shipping.sample
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,389 @@
1
+ require 'highline/import'
2
+ require 'columnist'
3
+
4
+ module Brightpearl
5
+
6
+ class Terminal
7
+
8
+ extend Columnist
9
+
10
+ MSG_INFO = 'info'
11
+ MSG_WARNING = 'warning'
12
+ MSG_ERROR = 'error'
13
+
14
+ # Runs a series of commands in the terminal.
15
+ # @return void
16
+ def self.command(commands, location = nil, verbose = true, verbose_cd = true, capture_real_output = false)
17
+ unless commands.is_a?(Array)
18
+ commands = [commands]
19
+ end
20
+ unless location.nil?
21
+ unless File.directory?(location)
22
+ error('Directory not found.', "Cannot find the following directory: \x1B[38;5;205m#{location}\x1B[0m", true)
23
+ end
24
+ end
25
+ output = []
26
+ if verbose_cd && verbose && commands.any?
27
+ puts "\x1B[42m Executing \x1B[0m \x1B[32m\xe2\x86\x92\x1B[0m #{Brightpearl::Terminal::format_command("cd #{location}")}"
28
+ end
29
+ if commands.any?
30
+ commands.each do |command|
31
+ if verbose
32
+ puts "\x1B[42m Executing \x1B[0m \x1B[32m\xe2\x86\x92\x1B[0m #{Brightpearl::Terminal::format_command("#{command}")}"
33
+ end
34
+ if location.nil?
35
+ if capture_real_output
36
+ output << `#{command}`
37
+ else
38
+ output << system("#{command}")
39
+ end
40
+ else
41
+ if capture_real_output
42
+ output << `cd #{location} && #{command}`
43
+ else
44
+ output << system("cd #{location} && #{command}")
45
+ end
46
+ end
47
+ end
48
+ end
49
+ if capture_real_output
50
+ output.map! { |v| v.gsub('\n', "\n") }
51
+ end
52
+ output
53
+ end
54
+
55
+ # Runs a series of commands in the terminal (and captures the output).
56
+ # @return void
57
+ def self.command_capture(commands, location = nil, verbose = true, verbose_cd = true)
58
+ command(commands, location, verbose, verbose_cd, true)
59
+ end
60
+
61
+ # Outputs messages to the terminal.
62
+ # @return void
63
+ def self.output(message = 'No message', type = MSG_INFO)
64
+ case type
65
+ when MSG_INFO
66
+ puts "\x1B[48;5;2m Executing \x1B[0m \x1B[32m\xe2\x86\x92\x1B[0m \x1B[0m#{message}\x1B[0m"
67
+ when MSG_WARNING
68
+ puts "\x1B[48;5;2m Vigilance \x1B[0m \x1B[33m\xe2\x86\x92\x1B[0m \x1B[0m#{message}\x1B[0m"
69
+ when MSG_ERROR
70
+ puts " \x1B[48;5;2m Failure \x1B[0m \x1B[33m\xe2\x86\x92\x1B[0m \x1B[0m#{message}\x1B[0m"
71
+ else
72
+ raise RuntimeError "'#{type}' is not a valid type."
73
+ end
74
+ end
75
+
76
+ # Displays error and exits script by default.
77
+ # @return void
78
+ def self.abort(title = nil, message = nil, exit_script = true, preceding_blank_line = true)
79
+ if title.nil?
80
+ title = 'Abandon ship!'
81
+ end
82
+ if message.nil?
83
+ message = "You have chosen to \x1B[38;5;9mABORT\x1B[38;5;240m the script."
84
+ end
85
+ Brightpearl::Terminal::error(title, message, exit_script, preceding_blank_line, 'ABORT')
86
+ end
87
+
88
+ # Displays error and exits script by default.
89
+ # @return void
90
+ def self.error(title = nil, message = nil, exit_script = true, preceding_blank_line = true, error_text = 'ERROR')
91
+ if title.nil?
92
+ title = "It seems you're trying to do something silly."
93
+ end
94
+ if preceding_blank_line
95
+ puts
96
+ end
97
+ puts " \x1B[48;5;196m #{error_text.upcase} \x1B[0m \xe2\x86\x92 #{title}"
98
+ puts
99
+ unless message.nil?
100
+ if message.is_a?(Array)
101
+ messages = message
102
+ else
103
+ messages = message.split("\n")
104
+ end
105
+ table(:border => false) do
106
+ messages.each do |line|
107
+ row do
108
+ column('', :align => 'left', :width => 4)
109
+ column("\x1B[38;5;240m#{line}\x1B[0m", :align => 'left', :width => 180)
110
+ end
111
+ end
112
+ end
113
+ puts
114
+ end
115
+ if exit_script
116
+ exit
117
+ end
118
+ end
119
+
120
+ # Displays info message.
121
+ # @return void
122
+ def self.info(title = nil, message = nil, preceding_blank_line = true)
123
+ if title.nil?
124
+ title = 'Whatever you did, worked.'
125
+ end
126
+ if preceding_blank_line
127
+ puts
128
+ end
129
+ puts " \x1B[48;5;27m MESSAGE \x1B[0m \xe2\x86\x92 #{title}"
130
+ puts
131
+ unless message.nil?
132
+ if message.is_a?(Array)
133
+ messages = message
134
+ else
135
+ messages = message.split("\n")
136
+ end
137
+ table(:border => false) do
138
+ messages.each do |line|
139
+ row do
140
+ column('', :align => 'left', :width => 4)
141
+ column("\x1B[38;5;240m#{line}\x1B[0m", :align => 'left', :width => 180)
142
+ end
143
+ end
144
+ end
145
+ puts
146
+ end
147
+ end
148
+
149
+ # Displays success message.
150
+ # @return void
151
+ def self.success(title = nil, message = nil, preceding_blank_line = true)
152
+ if title.nil?
153
+ title = 'Whatever you did, worked.'
154
+ end
155
+ if preceding_blank_line
156
+ puts
157
+ end
158
+ puts " \x1B[48;5;34m SUCCESS \x1B[0m \xe2\x86\x92 #{title}"
159
+ puts
160
+ unless message.nil?
161
+ if message.is_a?(Array)
162
+ messages = message
163
+ else
164
+ messages = message.split("\n")
165
+ end
166
+ table(:border => false) do
167
+ messages.each do |line|
168
+ row do
169
+ column('', :align => 'left', :width => 4)
170
+ column("\x1B[38;5;240m#{line}\x1B[0m", :align => 'left', :width => 180)
171
+ end
172
+ end
173
+ end
174
+ puts
175
+ end
176
+ end
177
+
178
+ # Displays warning message.
179
+ # @return void
180
+ def self.warning(title = nil, message = nil, preceding_blank_line = true)
181
+ if title.nil?
182
+ title = 'Whatever you did, generated a warning.'
183
+ end
184
+ if preceding_blank_line
185
+ puts
186
+ end
187
+ puts " \x1B[48;5;202m WARNING \x1B[0m \xe2\x86\x92 #{title}"
188
+ puts
189
+ unless message.nil?
190
+ if message.is_a?(Array)
191
+ messages = message
192
+ else
193
+ messages = message.split("\n")
194
+ end
195
+ table(:border => false) do
196
+ messages.each do |line|
197
+ row do
198
+ column('', :align => 'left', :width => 4)
199
+ column("\x1B[38;5;240m#{line}\x1B[0m", :align => 'left', :width => 180)
200
+ end
201
+ end
202
+ end
203
+ puts
204
+ end
205
+ end
206
+
207
+ # Returns action text in consistent, uniform manner.
208
+ # @return String
209
+ def self.format_action(action_text)
210
+ "\x1B[38;5;170m#{action_text.upcase}\x1B[0m"
211
+ end
212
+
213
+ # Returns branch name in consistent, uniform manner.
214
+ # @return String
215
+ def self.format_branch(branch_name)
216
+ "\x1B[38;5;40m[#{branch_name}]\x1B[0m"
217
+ end
218
+
219
+ # Returns branch name in consistent, uniform manner.
220
+ # @return String
221
+ def self.format_command(command_name)
222
+ "\x1B[38;5;220m#{command_name}\x1B[0m"
223
+ end
224
+
225
+ # Returns directory name in consistent, uniform manner.
226
+ # @return String
227
+ def self.format_directory(directory_name)
228
+ "\x1B[38;5;48m#{directory_name}\x1B[0m"
229
+ end
230
+
231
+ # Returns branch name in consistent, uniform manner.
232
+ # @return String
233
+ def self.format_flag(flag_letter)
234
+ "\x1B[38;5;117m-#{flag_letter} flag\x1B[0m"
235
+ end
236
+
237
+ # Returns branch name in consistent, uniform manner.
238
+ # @return String
239
+ def self.format_invalid(invalid_string)
240
+ "\x1B[38;5;9m#{invalid_string}\x1B[0m"
241
+ end
242
+
243
+ # Generates 'filler' string.
244
+ # @return String
245
+ def self.fill(length = 0, string = ' ')
246
+ fill_string = ''
247
+ (0..length - 1).each {
248
+ fill_string = "#{fill_string}#{string}"
249
+ }
250
+ fill_string
251
+ end
252
+
253
+ # Gives a prompt where 'y/Y' will return TRUE, 'n/N' will return false, and ANY other key will do nothing.
254
+ # @return void
255
+ def self.prompt_yes_no(title = nil, message = nil, confirmation_message = nil, preceding_blank_line = true)
256
+ if title.nil?
257
+ title = 'Please confirm YES or NO.'
258
+ end
259
+ if confirmation_message.nil?
260
+ confirmation_message = 'Would you like to continue?';
261
+ end
262
+ if preceding_blank_line
263
+ puts
264
+ end
265
+ puts " \x1B[48;5;56m CONFIRM \x1B[0m \xe2\x86\x92 #{title}"
266
+ puts
267
+ unless message.nil?
268
+ if message.is_a?(Array)
269
+ messages = message
270
+ else
271
+ messages = message.split("\n")
272
+ end
273
+ table(:border => false) do
274
+ messages.each do |line|
275
+ row do
276
+ column('', :align => 'left', :width => 4)
277
+ column("\x1B[38;5;240m#{line}\x1B[0m", :align => 'left', :width => 180)
278
+ end
279
+ end
280
+ end
281
+ puts
282
+ end
283
+ response = ''
284
+ until %w[y Y n N x X a A].include? response
285
+ response = ask(" \x1B[38;5;89m#{confirmation_message} \x1B[0m[y/n]\x1B[90m => \x1B[0m")
286
+ end
287
+ case response.downcase
288
+ when 'y'
289
+ puts "\n"
290
+ return true
291
+ when 'n'
292
+ puts "\n"
293
+ return false
294
+ when 'a'
295
+ Brightpearl::Terminal::error('Abandon ship!', ["You have chosen to \x1B[38;5;9mABORT\x1B[38;5;240m the script.", nil, 'Please note that whenever you do this, any scripted tasks which were running', 'will have been interrupted mid-script. This may (or may not) cause problems.'], true)
296
+ when 'x'
297
+ Brightpearl::Terminal::error('Abandon ship!', ["You have chosen to \x1B[38;5;9mABORT\x1B[38;5;240m the script.", nil, 'Please note that whenever you do this, any scripted tasks which were running', 'will have been interrupted mid-script. This may (or may not) cause problems.'], true)
298
+ else
299
+ end
300
+ end
301
+
302
+ # Used to display what is about to happen. Prompts for ENTER key before continuing.
303
+ # @return void
304
+ def self.prompt_enter(text)
305
+ puts
306
+ if text.is_a?(Array)
307
+ text.each do |line|
308
+ puts line
309
+ end
310
+ else
311
+ puts text
312
+ end
313
+ enter_to_continue
314
+ end
315
+
316
+ # Used to confirm what is about to happen. Prompts for [y/n] key before continuing.
317
+ # @return void
318
+ def self.prompt_yes(text)
319
+ puts
320
+ if text.is_a?(Array)
321
+ text.each do |line|
322
+ puts line
323
+ end
324
+ else
325
+ puts text
326
+ end
327
+ yes_to_continue
328
+ end
329
+
330
+ # Shows a prompt waiting for user input.
331
+ # @return string
332
+ def self.prompt_for_input(text)
333
+ response = Readline.readline(text, true)
334
+ exit if %w(quit exit q x).include?(response)
335
+ response
336
+ end
337
+
338
+ # Gives a prompt where ANY KEY will continue executing the script.
339
+ # @return void
340
+ # @deprecated
341
+ def self.any_key_to_continue(text = "\n\x1B[90mPress any key to continue\x1B[0m => ")
342
+ STDOUT.flush
343
+ print "#{text}"
344
+ STDIN.gets
345
+ nil
346
+ end
347
+
348
+ # Gives a prompt where ONLY 'Enter' will continue the script, any other key will abort.
349
+ # @return void
350
+ # @deprecated
351
+ def self.enter_to_continue
352
+ print "\n\x1B[90mPress \x1B[32mENTER\x1B[90m to continue, any other key to abort\x1B[0m => "
353
+ begin
354
+ system('stty raw -echo')
355
+ response = STDIN.getc
356
+ ensure
357
+ system('stty -raw echo')
358
+ end
359
+ if response.chr == "\r"
360
+ puts "\n\n"
361
+ else
362
+ abort("\nScript aborted.\n\n")
363
+ end
364
+ end
365
+
366
+ # Gives a prompt where ONLY 'Y' or 'y' will continue the script, any other key will abort.
367
+ # @return void
368
+ # @deprecated
369
+ def self.yes_to_continue
370
+ puts "\n"
371
+ response = ''
372
+ until %w[y n].include? response
373
+ response = ask("\x1B[90mWould you like to continue? \x1B[0m[y/n]\x1B[90m => \x1B[0m") { |q| q.limit = 1; q.case = :downcase }
374
+ end
375
+ case response
376
+ when 'y'
377
+ puts
378
+ return
379
+ else
380
+ puts
381
+ output('Aborting script', MSG_ERROR)
382
+ puts
383
+ exit
384
+ end
385
+ end
386
+
387
+ end
388
+
389
+ end
data/lib/core/tools.rb ADDED
@@ -0,0 +1,78 @@
1
+ require 'open-uri'
2
+
3
+ module Brightpearl
4
+
5
+ class Tools
6
+
7
+ REPORT_WIDTH = 188
8
+
9
+ # Check for internet access. Dies if not connected.
10
+ # @return boolean|void
11
+ def self.verify_internet_access
12
+ begin
13
+ return true if open('http://www.google.com')
14
+ rescue
15
+ abort('No internet connection. You must be online to run this command.')
16
+ end
17
+ end
18
+
19
+ # Returns time ago in human readable format.
20
+ # @string
21
+ def self.time_passed_since(time_stamp)
22
+ unless time_stamp.is_a?(DateTime)
23
+ raise RuntimeError, "Expected DateTime, got: #{time_stamp.class}"
24
+ end
25
+ seconds_ago = seconds_since(time_stamp.strftime('%Y-%m-%dT%H:%M:%S%z'))
26
+ seconds_ago = seconds_ago.to_i
27
+ case seconds_ago
28
+ when 1..119
29
+ return 'A minute ago'
30
+ when 120..2999
31
+ return "#{(seconds_ago / 60).round} minutes ago"
32
+ when 3000..5399
33
+ return 'About an hour ago'
34
+ when 5399..86399
35
+ return "#{((seconds_ago / 60) / 60).round} hours ago"
36
+ when 86400..169999
37
+ return 'A day ago'
38
+ when 170000..2505599
39
+ return "#{(((seconds_ago / 24) / 60) / 60).round} days ago"
40
+ when 2506000..4000000
41
+ return 'A month ago'
42
+ when 4000001..31535999
43
+ return "#{((((seconds_ago / 30.4368) / 24) / 60) / 60).round} months ago"
44
+ when 31536000..47303999
45
+ return 'A year ago'
46
+ when 47304000..9999999999999
47
+ return "#{((((seconds_ago / 365) / 24) / 60) / 60).round} years ago"
48
+ else
49
+ return "Out of range (#{seconds_ago})"
50
+ end
51
+ end
52
+
53
+ # Returns the number of seconds that have elapsed between a timestamp (0000-00-00T00:00:00+00:00) and now
54
+ # @return integer
55
+ def self.seconds_since(time_stamp)
56
+ time_stamp = DateTime.strptime(time_stamp, '%Y-%m-%dT%H:%M:%S%z')
57
+ time_now = DateTime.now
58
+ ((time_now - time_stamp) * 24 * 60 * 60).to_i
59
+ end
60
+
61
+ # Used to make sure all reports are the same width (for consistency).
62
+ # @return void
63
+ def self.validate_report_width(array)
64
+ unless array.is_a?(Array)
65
+ raise RuntimeError, "Expected Array, got: #{array.class}"
66
+ end
67
+ report_width = 0
68
+ array.each do |pixels|
69
+ report_width = report_width + pixels.to_i
70
+ end
71
+ unless report_width == REPORT_WIDTH
72
+ raise RuntimeError, "Report needs to be #{REPORT_WIDTH} pixels wide, calculated #{report_width} pixels."
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,7 @@
1
+ module Brightpearl
2
+
3
+ class Validate
4
+
5
+ end
6
+
7
+ end
@@ -0,0 +1,83 @@
1
+ module BrightpearlCommand
2
+
3
+ class Build < ::Convoy::ActionCommand::Base
4
+
5
+ def execute
6
+
7
+ @opts = command_options
8
+ @args = arguments
9
+ @service_dir = nil
10
+ opts_validate
11
+ opts_routing
12
+
13
+ end
14
+
15
+ def opts_validate
16
+
17
+ if @args[0].nil?
18
+ Brightpearl::Terminal::error('Must specify service name', "The script cannot build your service because you haven't told it what service to build.", true)
19
+ end
20
+
21
+ service_dir = Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE)
22
+ dir_dev_support = "#{service_dir}/services/dev-support/#{@args[0]}/#{@args[0]}-service"
23
+ dir_functional = "#{service_dir}/services/functional/#{@args[0]}/#{@args[0]}-service"
24
+ dir_infrastructure = "#{service_dir}/services/infrastructure/#{@args[0]}/#{@args[0]}-service"
25
+ dir_integration = "#{service_dir}/services/integration/#{@args[0]}/#{@args[0]}-service"
26
+ dir_lib = "#{service_dir}/services/lib/#{@args[0]}"
27
+
28
+ if File.directory?(dir_dev_support)
29
+ @service_dir = dir_dev_support
30
+ end
31
+ if File.directory?(dir_functional)
32
+ @service_dir = dir_functional
33
+ end
34
+ if File.directory?(dir_infrastructure)
35
+ @service_dir = dir_infrastructure
36
+ end
37
+ if File.directory?(dir_integration)
38
+ @service_dir = dir_integration
39
+ end
40
+ if File.directory?(dir_lib)
41
+ @service_dir = dir_lib
42
+ end
43
+ if @service_dir.nil?
44
+ Brightpearl::Terminal::error('Cannot find service', "The script is unable to find a service called: \x1B[38;5;202m#{@args[0].downcase.capitalize}\x1B[0m\nPlease check your spelling and try again.")
45
+ end
46
+
47
+ end
48
+
49
+ def opts_routing
50
+
51
+ build_service
52
+
53
+ end
54
+
55
+ def build_service
56
+
57
+ commands = [
58
+ # 'git status'
59
+ 'mvn clean install | grep "Building war"',
60
+ # 'mvn deploy'
61
+ ]
62
+ output = Brightpearl::Terminal::command_capture(commands, @service_dir)
63
+
64
+ puts output
65
+
66
+ war_file = output[0].split('war: ')
67
+ war_file = war_file[1].chomp
68
+
69
+ puts war_file
70
+
71
+ if Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_OS) == Brightpearl::Config::MAC
72
+ commands = [
73
+ "scp #{war_file} #{Brightpearl::Config.param(Brightpearl::Config::VM_USER)}@#{Brightpearl::Config.param(Brightpearl::Config::VM_IP)}:/tmp"
74
+ ]
75
+ puts commands
76
+ Brightpearl::Terminal::command(commands)
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end