brightpearl-cli 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/core/git.rb ADDED
@@ -0,0 +1,771 @@
1
+ require 'columnist'
2
+ require 'date'
3
+ require 'highline'
4
+
5
+ module Brightpearl
6
+
7
+ class Git
8
+
9
+ include Columnist
10
+
11
+ DELIMITER = '*|*'
12
+
13
+ SORT_DATE = 'date'
14
+ SORT_REFNAME = 'refname'
15
+
16
+ LOCAL = 'local'
17
+ REMOTE = 'remote'
18
+ CODE = 'code'
19
+ DB = 'db'
20
+
21
+ MERGED_PREFIX = 'MERGED-'
22
+ MDASH = '━'
23
+
24
+ MASTER = 'master'
25
+ REFNAME = 'refname'
26
+ OBJECT_TYPE = 'objecttype'
27
+ OBJECT_SIZE = 'objectsize'
28
+ OBJECT_NAME = 'objectname'
29
+ TREE = 'tree'
30
+ NUM_PARENT = 'numparent'
31
+ COMMITTER_NAME = 'committername'
32
+ COMMITTER_EMAIL = 'committeremail'
33
+ COMMITTER_DATE = 'committerdate'
34
+ SUBJECT = 'subject'
35
+ UPSTREAM = 'upstream'
36
+
37
+ BRANCH_NAME = 'branch_name'
38
+ BRANCH_LOCATION = 'branch_location'
39
+ BRANCH_EXISTS = 'branch_exists'
40
+ BRANCH_EXISTS_LOCALLY = 'branch_exists_locally'
41
+ BRANCH_IS_CURRENT = 'branch_is_current'
42
+ BRANCH_IS_UP_TO_DATE = 'branch_is_up_to_date'
43
+ BRANCH_HAS_STASH = 'branch_has_stash'
44
+ BRANCH_HAS_UPSTREAM = 'branch_has_upstream'
45
+
46
+ def initialize
47
+
48
+ @origin_updated_code = false
49
+ @origin_updated_db = false
50
+ @branch_upstream_data = false
51
+ @branches_as_array = {
52
+ :local_code => nil,
53
+ :local_db => nil,
54
+ :local_both => nil,
55
+ :remote_code => nil,
56
+ :remote_db => nil,
57
+ :remote_both => nil
58
+ }
59
+ @branches_as_array_all = false
60
+
61
+ end
62
+
63
+ # Gets detailed info about local branches as Array.
64
+ # @return Array
65
+ def get_local_branches(sort = SORT_REFNAME, repo_dir = nil)
66
+ repos = []
67
+ repos_to_return = []
68
+ validate_sort(sort)
69
+ if repo_dir.nil?
70
+ repo_loop.each do |repo_dir_inner|
71
+ repos << repo_dir_inner
72
+ end
73
+ else
74
+ validate_repo_dir(repo_dir)
75
+ repos << repo_dir
76
+ end
77
+ repos.each do |repo_dir_inner|
78
+ unless File.directory?(repo_dir_inner)
79
+ Brightpearl::Terminal::error('Directory not found', "Directory doesn't exist: #{Brightpearl::Terminal::format_directory(repo_dir_inner)}", true)
80
+ end
81
+ raw_terminal_output = `
82
+ cd #{repo_dir_inner} &&
83
+ git for-each-ref refs/heads/ --format='%(#{REFNAME})#{DELIMITER}%(#{OBJECT_TYPE})#{DELIMITER}%(#{OBJECT_SIZE})#{DELIMITER}%(#{OBJECT_NAME})#{DELIMITER}%(tree)#{DELIMITER}%(#{NUM_PARENT})#{DELIMITER}%(#{COMMITTER_NAME})#{DELIMITER}%(#{COMMITTER_EMAIL})#{DELIMITER}%(#{COMMITTER_DATE})#{DELIMITER}%(#{SUBJECT})#{DELIMITER}%(#{UPSTREAM})#{DELIMITER}' | sed 's/refs\\/heads\\///g'
84
+ `
85
+ branches = {}
86
+ branch_count = 0
87
+ raw_terminal_output.split("\n").each do |line|
88
+ line_split = line.split(DELIMITER)
89
+ data = {}
90
+ data[:"#{REFNAME}"] = line_split[0]
91
+ data[:"#{OBJECT_TYPE}"] = line_split[1]
92
+ data[:"#{OBJECT_SIZE}"] = line_split[2]
93
+ data[:"#{OBJECT_NAME}"] = line_split[3]
94
+ data[:"#{TREE}"] = line_split[4]
95
+ data[:"#{NUM_PARENT}"] = line_split[5]
96
+ data[:"#{COMMITTER_NAME}"] = line_split[6]
97
+ data[:"#{COMMITTER_EMAIL}"] = line_split[7][1..-2]
98
+ data[:"#{COMMITTER_DATE}"] = DateTime.parse(line_split[8])
99
+ data[:"#{SUBJECT}"] = line_split[9]
100
+ data[:"#{UPSTREAM}"] = line_split[10]
101
+ case sort
102
+ when SORT_REFNAME
103
+ branches[data[:"#{REFNAME}"]] = data
104
+ when SORT_DATE
105
+ branches["#{data[:"#{COMMITTER_DATE}"].strftime('%Y-%m-%d-%H-%I-%S')}-#{branch_count}"] = data
106
+ branch_count = branch_count + 1
107
+ else
108
+ Brightpearl::Terminal::error('Sort not supported', "The following sorting option is not yet supported: #{sort}", true)
109
+ end
110
+ end
111
+ branch_keys = branches.keys
112
+ case sort
113
+ when SORT_REFNAME
114
+ branch_keys.sort_by!(&:downcase)
115
+ when SORT_DATE
116
+ branch_keys.sort_by! { |value| value }
117
+ branch_keys = branch_keys.reverse
118
+ else
119
+ Brightpearl::Terminal::error('Sort not supported', "The following sorting option is not yet supported: #{sort}", true)
120
+ end
121
+ branch_data = []
122
+ branch_keys.each do |key|
123
+ branch_data << branches["#{key}"]
124
+ end
125
+ repos_to_return << branch_data
126
+ end
127
+ if repo_dir.nil?
128
+ return repos_to_return[0], repos_to_return[1]
129
+ else
130
+ repos_to_return[0]
131
+ end
132
+ end
133
+
134
+ # Gets detailed info about remote branches as Array.
135
+ # @return Array
136
+ def get_remote_branches(sort = SORT_REFNAME, repo_dir = nil)
137
+ repos = []
138
+ repos_to_return = []
139
+ validate_sort(sort)
140
+ if repo_dir.nil?
141
+ repo_loop.each do |repo_dir_inner|
142
+ repos << repo_dir_inner
143
+ end
144
+ else
145
+ validate_repo_dir(repo_dir)
146
+ repos << repo_dir
147
+ end
148
+ repos.each do |repo_dir_inner|
149
+ unless File.directory?(repo_dir_inner)
150
+ Brightpearl::Terminal::error('Directory not found', "Directory doesn't exist: #{Brightpearl::Terminal::format_directory(repo_dir)}", true)
151
+ end
152
+ update_origin(repo_dir_inner)
153
+ raw_terminal_output = `
154
+ cd #{repo_dir_inner} &&
155
+ for branch in \`git branch -r | grep -v HEAD\`; do echo \`git show --format="%cn#{DELIMITER}%ce#{DELIMITER}%cd#{DELIMITER}%s#{DELIMITER}" $branch | head -n 1\` $branch; done | sort -r | sed 's/origin\\///g'
156
+ `
157
+ branches = {}
158
+ branch_count = 0
159
+ raw_terminal_output.split("\n").each do |line|
160
+ line_split = line.split(DELIMITER)
161
+ data = {}
162
+ data[:"#{COMMITTER_NAME}"] = line_split[0]
163
+ data[:"#{COMMITTER_EMAIL}"] = line_split[1]
164
+ data[:"#{COMMITTER_DATE}"] = DateTime.parse(line_split[2])
165
+ data[:"#{SUBJECT}"] = line_split[3]
166
+ data[:"#{REFNAME}"] = line_split[4].to_s.strip
167
+ case sort
168
+ when SORT_REFNAME
169
+ branches[data[:"#{REFNAME}"]] = data
170
+ when SORT_DATE
171
+ branches["#{data[:"#{COMMITTER_DATE}"].strftime('%Y-%m-%d-%H-%I-%S')}-#{branch_count}"] = data
172
+ branch_count = branch_count + 1
173
+ else
174
+ Brightpearl::Terminal::error('Sort not supported', "The following sorting option is not yet supported: #{sort}", true)
175
+ end
176
+ end
177
+ branch_keys = branches.keys
178
+ case sort
179
+ when SORT_REFNAME
180
+ branch_keys.sort_by!(&:downcase)
181
+ when SORT_DATE
182
+ branch_keys.sort_by! { |value| value }
183
+ branch_keys = branch_keys.reverse
184
+ else
185
+ Brightpearl::Terminal::error('Sort not supported', "The following sorting option is not yet supported: #{sort}", true)
186
+ end
187
+ branch_data = []
188
+ branch_keys.each do |key|
189
+ branch_data << branches["#{key}"]
190
+ end
191
+ repos_to_return << branch_data
192
+ end
193
+ if repo_dir.nil?
194
+ return repos_to_return[0], repos_to_return[1]
195
+ else
196
+ repos_to_return[0]
197
+ end
198
+ end
199
+
200
+ # Gets branch names as array.
201
+ # @return Array
202
+ def get_branches_as_array(local_remote = LOCAL, repo_dir = nil)
203
+ validate_local_remote(local_remote)
204
+
205
+ # Check if result is already cached.
206
+ if repo_dir.nil?
207
+ if local_remote == LOCAL
208
+ return @branches_as_array[:local_both] if @branches_as_array[:local_both] != nil
209
+ else
210
+ return @branches_as_array[:remote_both] if @branches_as_array[:remote_both] != nil
211
+ end
212
+ else
213
+ if repo_dir == Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE)
214
+ if local_remote == LOCAL
215
+ return @branches_as_array[:local_code] if @branches_as_array[:local_code] != nil
216
+ else
217
+ return @branches_as_array[:remote_code] if @branches_as_array[:remote_code] != nil
218
+ end
219
+ else
220
+ if local_remote == LOCAL
221
+ return @branches_as_array[:local_db] if @branches_as_array[:local_db] != nil
222
+ else
223
+ return @branches_as_array[:remote_db] if @branches_as_array[:remote_db] != nil
224
+ end
225
+ end
226
+ end
227
+
228
+ case local_remote
229
+ when LOCAL
230
+ if repo_dir.nil?
231
+ brightpearl_code, brightpearl_db = get_local_branches
232
+ repos_branches = [brightpearl_code, brightpearl_db]
233
+ else
234
+ branches = get_local_branches(SORT_REFNAME, repo_dir)
235
+ repos_branches = [branches]
236
+ end
237
+ else
238
+ if repo_dir.nil?
239
+ brightpearl_code, brightpearl_db = get_remote_branches
240
+ repos_branches = [brightpearl_code, brightpearl_db]
241
+ else
242
+ branches = get_remote_branches(SORT_REFNAME, repo_dir)
243
+ repos_branches = [branches]
244
+ end
245
+ end
246
+ repos_to_return = []
247
+ repos_branches.each do |repo_data|
248
+ branch_names = []
249
+ repo_data.each do |branch_data|
250
+ branch_names << branch_data[:"#{REFNAME}"]
251
+ end
252
+ repos_to_return << branch_names
253
+ end
254
+ if repo_dir.nil?
255
+ if local_remote == LOCAL
256
+ return @branches_as_array[:local_both] = repos_to_return[0], repos_to_return[1]
257
+ else
258
+ return @branches_as_array[:remote_both] = repos_to_return[0], repos_to_return[1]
259
+ end
260
+ else
261
+ if repo_dir == Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE)
262
+ if local_remote == LOCAL
263
+ return @branches_as_array[:local_code] = repos_to_return[0]
264
+ else
265
+ return @branches_as_array[:remote_code] = repos_to_return[0]
266
+ end
267
+ else
268
+ if local_remote == LOCAL
269
+ return @branches_as_array[:local_db] = repos_to_return[0]
270
+ else
271
+ return @branches_as_array[:remote_db] = repos_to_return[0]
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ # Gets EVERY SINGLE BRANCH that exists -- local & remote, code & db -- and puts them in a single, unique, array.
278
+ # @return Array
279
+ def get_all_branches_as_array
280
+ unless @branches_as_array_all
281
+ local_branches = get_branches_as_array(Brightpearl::Git::LOCAL)
282
+ remote_branches = get_branches_as_array(Brightpearl::Git::REMOTE)
283
+ @branches_as_array_all = local_branches[0].concat(local_branches[1]).concat(remote_branches[0]).concat(remote_branches[1])
284
+ @branches_as_array_all.uniq!
285
+ @branches_as_array_all.sort_by! { |m| m.downcase }
286
+ end
287
+ @branches_as_array_all
288
+ end
289
+
290
+ # Outputs list of branches to terminal.
291
+ # @return void
292
+ def show_branches(sort = SORT_REFNAME, local_remote = LOCAL)
293
+ # todo
294
+ puts
295
+ puts "\x1B[31mTODO!\x1B[0m Must do something with 'terminal_width' parameter."
296
+ puts
297
+ validate_sort(sort)
298
+ validate_local_remote(local_remote)
299
+ # terminal_width = HighLine::SystemExtensions.terminal_size
300
+ # terminal_width = terminal_width[0]
301
+ case local_remote
302
+ when LOCAL
303
+ brightpearl_code, brightpearl_db = get_local_branches(sort)
304
+ else
305
+ brightpearl_code, brightpearl_db = get_remote_branches(sort)
306
+ end
307
+ current_code_branch = current_branch_for_repo(Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE))
308
+ current_db_branch = current_branch_for_repo(Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_DB))
309
+ column_width = [2, 20, 23, 15, 34, 1, 34, 15, 23, 20, 1]
310
+ Brightpearl::Tools::validate_report_width(column_width)
311
+ puts "\n"
312
+ table(:border => false) do
313
+ row do
314
+ column('', :align => 'right', :bold => 'true', :width => column_width[0])
315
+ column('Last Activity', :align => 'right', :bold => 'true', :width => column_width[1])
316
+ column('Developer', :align => 'right', :bold => 'true', :width => column_width[2])
317
+ column('Last Commit', :align => 'right', :bold => 'true', :width => column_width[3])
318
+ column('BRIGHTPEARL-CODE', :align => 'right', :bold => 'true', :width => column_width[4], :color => 32)
319
+ column('|', :align => 'center', :bold => 'true', :width => column_width[5])
320
+ column('BRIGHTPEARL-DB', :align => 'left', :bold => 'true', :width => column_width[6], :color => 160)
321
+ column('Last Commit', :align => 'left', :bold => 'true', :width => column_width[7])
322
+ column('Developer', :align => 'left', :bold => 'true', :width => column_width[8])
323
+ column('Last Activity', :align => 'left', :bold => 'true', :width => column_width[9])
324
+ column('', :align => 'left', :bold => 'true', :width => column_width[10])
325
+ end
326
+ show_branches_divider(column_width)
327
+ db_branches_shown = []
328
+ brightpearl_code.each do |code_branch|
329
+ db_branch = show_branches_get_db_branch(brightpearl_db, code_branch)
330
+ if db_branch[:"#{REFNAME}"] != MDASH
331
+ db_branches_shown << db_branch[:"#{REFNAME}"]
332
+ # branch_data = branch_data(code_branch[:"#{REFNAME}"])
333
+ else
334
+ # branch_data = branch_data(code_branch[:"#{REFNAME}"], CODE)
335
+ end
336
+ code_time_adjusted = code_branch[:"#{COMMITTER_DATE}"] - (1 / 24.0)
337
+ row do
338
+ code_accent, code_color, code_star, db_accent, db_color, db_star = show_branches_get_colors(code_branch, current_code_branch, current_db_branch, db_branch)
339
+ column("#{code_star}", :color => code_color)
340
+ column(Brightpearl::Tools::time_passed_since(code_time_adjusted), :color => code_color)
341
+ column(code_branch[:"#{COMMITTER_NAME}"], :color => code_color)
342
+ column(code_branch[:"#{COMMITTER_DATE}"].strftime('%d %^b %H:%M'), :color => code_color)
343
+ column(code_branch[:"#{REFNAME}"], :color => code_accent)
344
+ column('|')
345
+ column(db_branch[:"#{REFNAME}"], :color => db_accent)
346
+ column((db_branch[:"#{COMMITTER_DATE}"] == nil) ? MDASH : db_branch[:"#{COMMITTER_DATE}"].strftime('%d %^b %H:%M'), :color => db_color)
347
+ column(db_branch[:"#{COMMITTER_NAME}"], :color => db_color)
348
+ column((db_branch[:"#{COMMITTER_DATE}"] == nil) ? MDASH : Brightpearl::Tools::time_passed_since(db_branch[:"#{COMMITTER_DATE}"] - (1 / 24.0)), :color => db_color)
349
+ column("#{db_star}", :color => db_color)
350
+ end
351
+ end
352
+ brightpearl_db.each do |db_branch|
353
+ unless db_branches_shown.include? db_branch[:"#{REFNAME}"]
354
+ row do
355
+ code_accent, code_color, code_star, db_accent, db_color, db_star = show_branches_get_colors(nil, current_code_branch, current_db_branch, db_branch)
356
+ column('', :color => code_color)
357
+ column(MDASH, :color => code_color)
358
+ column(MDASH, :color => code_color)
359
+ column(MDASH, :color => code_color)
360
+ column(MDASH, :color => code_accent)
361
+ column('|')
362
+ column(db_branch[:"#{REFNAME}"], :color => db_accent)
363
+ column((db_branch[:"#{COMMITTER_DATE}"] == nil) ? MDASH : db_branch[:"#{COMMITTER_DATE}"].strftime('%d %^b %H:%M'), :color => db_color)
364
+ column(db_branch[:"#{COMMITTER_NAME}"], :color => db_color)
365
+ column((db_branch[:"#{COMMITTER_DATE}"] == nil) ? MDASH : Brightpearl::Tools::time_passed_since(db_branch[:"#{COMMITTER_DATE}"]), :color => db_color)
366
+ column('')
367
+ end
368
+ end
369
+ end
370
+ show_branches_divider(column_width)
371
+ end
372
+ puts "\n"
373
+ end
374
+
375
+ # Sub-method for 'show_branches'. Don't call independently.
376
+ # @return String(s)
377
+ def show_branches_get_colors(code_branch, current_code_branch, current_db_branch, db_branch)
378
+ code_star = nil
379
+ code_color = 240
380
+ code_accent = nil
381
+ db_star = nil
382
+ db_color = 240
383
+ db_accent = nil
384
+ current_branch_color = 46
385
+ unless code_branch.nil?
386
+ if current_code_branch == code_branch[:"#{REFNAME}"]
387
+ code_star = "\xe2\x98\x85"
388
+ code_color = current_branch_color
389
+ code_accent = current_branch_color
390
+ end
391
+ end
392
+ unless db_branch.nil?
393
+ if current_db_branch == db_branch[:"#{REFNAME}"]
394
+ db_star = "\xe2\x98\x85"
395
+ db_color = current_branch_color
396
+ db_accent = current_branch_color
397
+ end
398
+ end
399
+ return code_accent, code_color, code_star, db_accent, db_color, db_star
400
+ end
401
+
402
+ # Sub-method for 'show_branches'. Don't call independently.
403
+ # @return void
404
+ def show_branches_get_db_branch(brightpearl_db, code_branch)
405
+ brightpearl_db.each do |db_branch|
406
+ if db_branch[:"#{REFNAME}"] == code_branch[:"#{REFNAME}"]
407
+ return db_branch
408
+ end
409
+ end
410
+ db_branch = {}
411
+ db_branch[:"#{REFNAME}"] = MDASH
412
+ db_branch[:"#{COMMITTER_NAME}"] = MDASH
413
+ db_branch[:"#{COMMITTER_DATE}"] = nil
414
+ db_branch
415
+ end
416
+
417
+ # Sub-method for 'show_branches'. Don't call independently.
418
+ # @return void
419
+ def show_branches_divider(column_width, color = 'white')
420
+ row do
421
+ column(Brightpearl::Terminal::fill(column_width[0], MDASH), :color => color)
422
+ column(Brightpearl::Terminal::fill(column_width[1], MDASH), :color => color)
423
+ column(Brightpearl::Terminal::fill(column_width[2], MDASH), :color => color)
424
+ column(Brightpearl::Terminal::fill(column_width[3], MDASH), :color => color)
425
+ column(Brightpearl::Terminal::fill(column_width[4], MDASH), :color => color)
426
+ column(Brightpearl::Terminal::fill(column_width[5], MDASH), :color => color)
427
+ column(Brightpearl::Terminal::fill(column_width[6], MDASH), :color => color)
428
+ column(Brightpearl::Terminal::fill(column_width[7], MDASH), :color => color)
429
+ column(Brightpearl::Terminal::fill(column_width[8], MDASH), :color => color)
430
+ column(Brightpearl::Terminal::fill(column_width[9], MDASH), :color => color)
431
+ column(Brightpearl::Terminal::fill(column_width[10], MDASH), :color => color)
432
+ end
433
+ end
434
+
435
+ # Get current branch for repo.
436
+ # @return String
437
+ def current_branch_for_repo(repo_dir)
438
+ validate_repo_dir(repo_dir)
439
+ `cd #{repo_dir} && git symbolic-ref --short -q HEAD`.strip
440
+ end
441
+
442
+ # Updates origin (IE: remote branches)
443
+ # @return void
444
+ def update_origin(repo_dir = nil)
445
+ validate_repo_dir(repo_dir)
446
+ if @origin_updated_code && repo_dir == Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE) ||
447
+ @origin_updated_db && repo_dir == Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_DB) ||
448
+ @origin_updated_code && @origin_updated_db && repo_dir.nil?
449
+ else
450
+ Brightpearl::Terminal::output("Updating origin (#{get_repo_shorthand(repo_dir)})")
451
+ case repo_dir
452
+ when Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE)
453
+ @origin_updated_code = true
454
+ Brightpearl::Terminal::command(['git fetch -p'], Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE))
455
+ when Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_DB)
456
+ @origin_updated_db = true
457
+ Brightpearl::Terminal::command(['git fetch -p'], Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_DB))
458
+ else
459
+ @origin_updated_code = true
460
+ @origin_updated_db = true
461
+ repo_loop.each do |repo_dir_inner|
462
+ Brightpearl::Terminal::command(['git fetch -p'], repo_dir_inner)
463
+ end
464
+ end
465
+ end
466
+ end
467
+
468
+ # Merges master into current branch (for repo) and pushes changes to origin.
469
+ # @deprecated
470
+ # @return void
471
+ def merge_master_into_current_branch(repo_dir, push_to_origin = true)
472
+ current_branch = current_branch_for_repo(repo_dir)
473
+ if current_branch == Brightpearl::Git::MASTER
474
+ return
475
+ end
476
+ commands = Array.new
477
+ commands << 'git checkout master'
478
+ commands << 'git pull'
479
+ if current_branch != Brightpearl::Git::MASTER
480
+ commands << "git checkout #{current_branch}"
481
+ commands << 'git pull'
482
+ commands << 'git merge master'
483
+ end
484
+ if push_to_origin
485
+ commands << 'git push'
486
+ end
487
+ Brightpearl::Terminal::command(commands, repo_dir)
488
+ end
489
+
490
+ # Makes sure that both BP-CODE & BP-DB are on the same branch.
491
+ # @return void
492
+ # @deprecated
493
+ def verify_same_branch
494
+ branch_names = Array.new
495
+ repo_loop.each do |repo_dir|
496
+ branch_names << current_branch_for_repo(repo_dir)
497
+ end
498
+ if branch_names[0] != branch_names[1]
499
+ puts
500
+ puts "\x1B[41m ERROR \x1B[0m Cannot continue because your repos are not on the same branch."
501
+ puts
502
+ puts "\x1B[33m/brightpearl-code\x1B[0m is on: \x1B[32m#{branch_names[0]}\x1B[0m"
503
+ puts "\x1B[33m/brightpearl-db \x1B[0m is on: \x1B[32m#{branch_names[1]}\x1B[0m"
504
+ puts
505
+ puts "Use \x1B[33mbrightpearl checkout\x1B[0m \x1B[32m[branch-name]\x1B[0m to switch both repos to the same branch."
506
+ puts
507
+ exit
508
+ end
509
+ branch_names[0]
510
+ end
511
+
512
+ # Checks if you have staged changes in current repo and if so, prompts to stash them.
513
+ # @return void
514
+ def stash_staged_changes
515
+ repo_loop.each do |repo_dir|
516
+ results = `cd #{repo_dir} && git status | grep 'Changes '`
517
+ results = results.split("\n")
518
+ if results.any?
519
+ Brightpearl::Terminal::command(['git status'], repo_dir)
520
+ current_branch = current_branch_for_repo(repo_dir)
521
+ if Brightpearl::Terminal::prompt_yes_no("Found uncommitted files on branch #{Brightpearl::Terminal::format_branch(current_branch)}", nil, "Would you like to #{Brightpearl::Terminal::format_action('stash')}\x1B[38;5;89m these changes before continuing?")
522
+ Brightpearl::Terminal::command('git stash', repo_dir)
523
+ else
524
+ unless Brightpearl::Terminal::prompt_yes_no('Continue without stashing?', "By selecting #{Brightpearl::Terminal::format_action('Yes')}\x1B[38;5;240m, you're changes will be carried over to the next branch.", nil, false)
525
+ Brightpearl::Terminal::abort(nil, nil, true, false)
526
+ end
527
+ end
528
+ end
529
+ end
530
+ end
531
+
532
+ # Checks if you currently have stashed changes for current branch and if so, prompt to un-stash them.
533
+ # @return void
534
+ def check_for_stash
535
+ repo_loop.each do |repo_dir|
536
+ results = check_for_stash_get_stashes(repo_dir)
537
+ if results.any?
538
+ results_output = Array.new
539
+ results.each do |result|
540
+ results_output << "#{result}"
541
+ end
542
+ stashes_to_skip = 0
543
+ while results.any?
544
+ stash_name = results[0].split(/:/).first
545
+ if Brightpearl::Terminal::prompt_yes_no("Found the following stash on #{Brightpearl::Terminal::format_branch(current_branch_for_repo(repo_dir))}", "#{results[0]}", "Would you like to #{Brightpearl::Terminal::format_action('apply')}\x1B[38;5;89m this stash now?")
546
+ stash_apply_successful = Brightpearl::Terminal::command(["git stash apply #{stash_name}"], repo_dir)
547
+ if stash_apply_successful[0] == true
548
+ Brightpearl::Terminal::command("git stash drop #{stash_name}", repo_dir)
549
+ results = check_for_stash_get_stashes(repo_dir)
550
+ else
551
+ Brightpearl::Terminal::error("Stash could not be applied successfully (and therefore wasn't dropped).", ["#{results[0]}", nil, "Please #{Brightpearl::Terminal::format_action('open an IDE')} and resolve your conflicts before continuing.", "Don't forget to drop your stash afterwards with: #{Brightpearl::Terminal::format_command("git stash drop #{stash_name}")}"], false)
552
+ results = []
553
+ end
554
+ else
555
+ stashes_to_skip = stashes_to_skip + 1
556
+ results = check_for_stash_get_stashes(repo_dir)
557
+ a = (stashes_to_skip + 0)
558
+ b = 0
559
+ while b < a do
560
+ results.shift
561
+ b += 1
562
+ end
563
+ end
564
+ end
565
+ end
566
+ end
567
+ end
568
+
569
+ # Sub-method for 'show_branches'. Don't call independently.
570
+ # @return Array
571
+ def check_for_stash_get_stashes(repo_dir)
572
+ results = `cd #{repo_dir} && git stash list | grep 'WIP on #{current_branch_for_repo(repo_dir)}:'`
573
+ results = results.split("\n")
574
+ end
575
+
576
+ # Returns an array that include info for BOTH repos. Finds out whether a branch exists and if it's current or not
577
+ # Only does it locally.
578
+ # @return Array
579
+ def branch_data(branch_name, code_db = nil, verbose = true)
580
+ data = []
581
+ repo_loop.each do |repo_dir|
582
+ unless code_db.nil?
583
+ validate_code_db(code_db)
584
+ case code_db
585
+ when CODE
586
+ if repo_dir == Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_DB)
587
+ data << nil
588
+ next
589
+ end
590
+ else
591
+ if repo_dir == Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE)
592
+ data << nil
593
+ next
594
+ end
595
+ end
596
+ end
597
+ Brightpearl::Terminal::output("Retrieving branch data for #{Brightpearl::Terminal::format_branch(branch_name)} \xe2\x80\x94 (#{get_repo_shorthand(repo_dir)})")
598
+ repo_data = {}
599
+ repo_data
600
+ repo_data[:"#{BRANCH_NAME}"] = branch_name
601
+ repo_data[:"#{BRANCH_LOCATION}"] = repo_dir
602
+ repo_data[:"#{BRANCH_EXISTS}"] = true
603
+ repo_data[:"#{BRANCH_EXISTS_LOCALLY}"] = true
604
+ repo_data[:"#{BRANCH_HAS_STASH}"] = false
605
+ repo_data[:"#{BRANCH_HAS_UPSTREAM}"] = branch_has_upstream(repo_dir, branch_name)
606
+ repo_data[:"#{BRANCH_IS_CURRENT}"] = (current_branch_for_repo(repo_dir) == branch_name ? true : false)
607
+ if repo_data[:"#{BRANCH_HAS_UPSTREAM}"]
608
+ # @todo
609
+ repo_data[:"#{BRANCH_IS_UP_TO_DATE}"] = nil
610
+ else
611
+ # @todo
612
+ repo_data[:"#{BRANCH_IS_UP_TO_DATE}"] = nil
613
+ end
614
+ # Check branch exists
615
+ unless branch_exists(branch_name, repo_dir, Brightpearl::Git::LOCAL)
616
+ repo_data[:"#{BRANCH_EXISTS_LOCALLY}"] = false
617
+ Brightpearl::Terminal::warning("Branch #{Brightpearl::Terminal::format_branch(branch_name)} not found #{Brightpearl::Terminal::format_action('locally')} - (#{get_repo_shorthand(repo_dir)})", nil) if verbose
618
+ Brightpearl::Terminal::output('Checking origin') if verbose
619
+ unless branch_exists(branch_name, repo_dir, Brightpearl::Git::REMOTE)
620
+ Brightpearl::Terminal::warning("Branch #{Brightpearl::Terminal::format_branch(branch_name)} not found #{Brightpearl::Terminal::format_action('remotely')} - (#{get_repo_shorthand(repo_dir)})", nil) if verbose
621
+ repo_data[:"#{BRANCH_EXISTS}"] = false
622
+ data << repo_data
623
+ next
624
+ end
625
+ end
626
+ # Check for stashed changes
627
+ stashes = `cd #{repo_dir} && git stash list | grep 'WIP on #{branch_name}:'`
628
+ stashes = stashes.split("\n")
629
+ if stashes.any?
630
+ repo_data[:"#{BRANCH_HAS_STASH}"] = stashes.count
631
+ end
632
+ data << repo_data
633
+ end
634
+ data
635
+ end
636
+
637
+ # Returns TRUE if branch exists, FALSE if not
638
+ # @return Array
639
+ def branch_exists(branch_name, repo_dir, local_remote = LOCAL)
640
+ validate_repo_dir(repo_dir)
641
+ validate_local_remote(local_remote)
642
+ case local_remote
643
+ when LOCAL
644
+ branches = get_branches_as_array(LOCAL, repo_dir)
645
+ else
646
+ branches = get_branches_as_array(REMOTE, repo_dir)
647
+ end
648
+ unless branches.include?(branch_name)
649
+ return false
650
+ end
651
+ true
652
+ end
653
+
654
+ # Checks if branch exists ANYWHERE -- Local, Remote, Code, DB. If the branch name is found anywhere, will return FALSE.
655
+ # @return boolean
656
+ def branch_exists_anywhere(branch_name, case_sensitive = false)
657
+ existing_branches = get_all_branches_as_array
658
+ if case_sensitive
659
+ existing_branches.map!(&:downcase)
660
+ branch_name.downcase!
661
+ end
662
+ unless existing_branches.include?(branch_name)
663
+ return false
664
+ end
665
+ true
666
+ end
667
+
668
+ # Checks if a branch has an upstream (remote) branch. Returns TRUE or FALSE.
669
+ # @return boolean
670
+ # @deprecated
671
+ def branch_has_upstream(repo_dir, branch_name)
672
+ validate_repo_dir(repo_dir)
673
+ result = `cd #{repo_dir} && git branch -vv | grep 'origin/#{branch_name}'`
674
+ result == '' ? false : true
675
+ end
676
+
677
+ # Checks if a branch is at same HEAD as upstream. Returns TRUE or FALSE.
678
+ # @return boolean
679
+ # @deprecated
680
+ def branch_synced_with_upstream(repo_dir, branch_name)
681
+ validate_repo_dir(repo_dir)
682
+ result = `cd #{repo_dir} && git branch -vv | grep 'origin/#{branch_name}'`
683
+ result == '' ? false : true
684
+ end
685
+
686
+ # Gets upstream info for a branch
687
+ # @return hash
688
+ def branch_upstream_info(branch_name)
689
+ unless @branch_upstream_data
690
+ @branch_upstream_data = []
691
+ repo_loop.each do |repo_dir|
692
+ output = `git for-each-ref --shell --format='
693
+ b=%(refname:short)
694
+ u=${b}'@{upstream}'
695
+ if git rev-parse --verify --quiet "$u" >/dev/null 2>&1; then
696
+ test -n "$(git rev-list -n 1 "$u..$b")" &&
697
+ echo "$b: has unpushed commits"
698
+ else
699
+ echo "$b: no upstream configuration" >&2
700
+ fi
701
+ ' refs/heads | sh`
702
+
703
+ @branch_upstream_data << output
704
+ end
705
+ end
706
+ puts @branch_upstream_data
707
+ end
708
+
709
+ # Checks if a branch is up-to-date with its remote
710
+ # @return boolea
711
+ def branch_is_up_to_date(repo_dir, branch_name)
712
+ validate_repo_dir(repo_dir)
713
+ result_local = `cd #{repo_dir} && git rev-parse #{branch_name}`
714
+ result_remote = `cd #{repo_dir} && git rev-parse origin/#{branch_name}`
715
+ result_local == result_remote ? true : false
716
+
717
+ end
718
+
719
+ # Returns array with the paths to both repos.
720
+ # @return Array
721
+ def repo_loop
722
+ Array[
723
+ Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE),
724
+ Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_DB)
725
+ ]
726
+ end
727
+
728
+ # Validates that a parameter is either 'local' or 'remote'
729
+ # @return void
730
+ def validate_local_remote(local_remote)
731
+ unless Array[LOCAL, REMOTE].include?(local_remote)
732
+ ("'#{local_remote}' is not a valid parameter. Must be LOCAL or REMOTE.")
733
+ end
734
+ end
735
+
736
+ # Validates that a parameter is either 'code' or 'db'
737
+ # @return void
738
+ def validate_code_db(code_db)
739
+ unless Array[CODE, DB].include?(code_db)
740
+ abort("'#{code_db}' is not a valid parameter. Must be CODE or DB.")
741
+ end
742
+ end
743
+
744
+ # Makes sure the repo directory is valid.
745
+ # @return void
746
+ def validate_repo_dir(repo_dir)
747
+ unless Array[
748
+ Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE),
749
+ Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_DB)
750
+ ].include?(repo_dir)
751
+ abort("'#{repo_dir}' is not a valid directory.")
752
+ end
753
+ end
754
+
755
+ # Validates if sort option is supported.
756
+ # @return void
757
+ def validate_sort(sort_option)
758
+ unless Array[SORT_DATE, SORT_REFNAME].include?(sort_option)
759
+ abort("'#{sort_option}' is not a valid sort option.")
760
+ end
761
+ end
762
+
763
+ # Returns short-hand string for repo
764
+ # @return String
765
+ def get_repo_shorthand(repo_dir)
766
+ repo_dir == Brightpearl::Config.param(Brightpearl::Config::WORKSTATION_PATH_TO_BP_CODE) ? 'brightpearl-code' : 'brightpearl-db'
767
+ end
768
+
769
+ end
770
+
771
+ end