gitcycle 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/gitcycle.rb CHANGED
@@ -15,12 +15,24 @@ require 'yajl'
15
15
  $:.unshift File.dirname(__FILE__)
16
16
 
17
17
  require "ext/string"
18
+ require "gitcycle/branch"
19
+ require "gitcycle/checkout"
20
+ require "gitcycle/commit"
21
+ require "gitcycle/discuss"
22
+ require "gitcycle/incident"
23
+ require "gitcycle/open"
24
+ require "gitcycle/pull"
25
+ require "gitcycle/push"
26
+ require "gitcycle/qa"
27
+ require "gitcycle/ready"
28
+ require "gitcycle/review"
29
+ require "gitcycle/setup"
18
30
 
19
31
  class Gitcycle
20
32
 
21
33
  API =
22
- if ENV['ENV'] == 'development'
23
- "http://127.0.0.1:8080/api"
34
+ if ENV['ENV'] == 'test'
35
+ "http://127.0.0.1:3000/api"
24
36
  else
25
37
  "http://gitcycle.bleacherreport.com/api"
26
38
  end
@@ -36,6 +48,19 @@ class Gitcycle
36
48
  :last_command_errored => 8,
37
49
  }
38
50
 
51
+ include Branch
52
+ include Checkout
53
+ include Commit
54
+ include Discuss
55
+ include Incident
56
+ include Open
57
+ include Pull
58
+ include Push
59
+ include QA
60
+ include Ready
61
+ include Review
62
+ include Setup
63
+
39
64
  def initialize(args=nil)
40
65
  $remotes = {}
41
66
 
@@ -51,524 +76,6 @@ class Gitcycle
51
76
  start(args) if args
52
77
  end
53
78
 
54
- def branch(*args)
55
- url = args.detect { |arg| arg =~ /^https?:\/\// }
56
- title = args.detect { |arg| arg =~ /\s/ }
57
-
58
- exec_git(:branch, args) unless url || title
59
-
60
- require_git && require_config
61
-
62
- params = {
63
- 'branch[source]' => branches(:current => true)
64
- }
65
-
66
- if url && url.include?('lighthouseapp.com/')
67
- params.merge!('branch[lighthouse_url]' => url)
68
- elsif url && url.include?('github.com/')
69
- params.merge!('branch[issue_url]' => url)
70
- elsif url
71
- puts "Gitcycle only supports Lighthouse or Github Issue URLs.".red
72
- exit ERROR[:unrecognized_url]
73
- elsif title
74
- params.merge!(
75
- 'branch[name]' => title,
76
- 'branch[title]' => title
77
- )
78
- else
79
- exec_git(:branch, args)
80
- end
81
-
82
- unless yes?("\nYour work will eventually merge into '#{params['branch[source]']}'. Is this correct?")
83
- params['branch[source]'] = q("What branch would you like to eventually merge into?")
84
- end
85
-
86
- source = params['branch[source]']
87
-
88
- puts "\nRetrieving branch information from gitcycle.\n".green
89
- branch = get('branch', params)
90
- name = branch['name']
91
-
92
- begin
93
- owner, repo = branch['repo'].split(':')
94
- branch['home'] ||= @git_login
95
-
96
- unless yes?("Would you like to name your branch '#{name}'?")
97
- name = q("\nWhat would you like to name your branch?")
98
- name = name.gsub(/[\s\W]/, '-')
99
- end
100
-
101
- checkout_remote_branch(
102
- :owner => owner,
103
- :repo => repo,
104
- :branch => branch['source'],
105
- :target => name
106
- )
107
-
108
- puts "Sending branch information to gitcycle.".green
109
- get('branch',
110
- 'branch[home]' => branch['home'],
111
- 'branch[name]' => branch['name'],
112
- 'branch[rename]' => name != branch['name'] ? name : nil,
113
- 'branch[source]' => branch['source']
114
- )
115
- rescue SystemExit, Interrupt
116
- puts "\nDeleting branch from gitcycle.\n".green
117
- get('branch',
118
- 'branch[name]' => branch['name'],
119
- 'create' => 0,
120
- 'reset' => 1
121
- )
122
- end
123
-
124
- puts "\n"
125
- end
126
-
127
- def checkout(*args)
128
- if args.length != 1 || options?(args)
129
- exec_git(:checkout, args)
130
- end
131
-
132
- require_git && require_config
133
-
134
- if args[0] =~ /^https?:\/\//
135
- puts "\nRetrieving branch information from gitcycle.\n".green
136
- branch = get('branch', 'branch[lighthouse_url]' => args[0], 'create' => 0)
137
- if branch
138
- checkout_or_track(:name => branch['name'], :remote => 'origin')
139
- else
140
- puts "\nBranch not found!\n".red
141
- puts "\nDid you mean: gitc branch #{args[0]}\n".yellow
142
- end
143
- elsif args[0] =~ /^\d*$/
144
- puts "\nLooking for a branch for LH ticket ##{args[0]}.\n".green
145
- results = branches(:array => true).select {|b| b.include?("-#{args[0]}-") }
146
- if results.size == 0
147
- puts "\nNo matches for ticket ##{args[0]} found.\n".red
148
- elsif results.size == 1
149
- branch = results.first
150
- if branch.strip == branches(:current => true).strip
151
- puts "Already on Github branch for LH ticket ##{args[0]} (#{branch})".yellow
152
- else
153
- puts "\nSwitching to branch '#{branch}'\n".green
154
- run("git checkout #{branch}")
155
- end
156
- else
157
- puts "\nFound #{results.size} matches with that LH ticket number:\n".yellow
158
- puts results
159
- puts "\nDid not switch branches. Please check your ticket number.\n".red
160
- end
161
- else
162
- remote, branch = args[0].split('/')
163
- remote, branch = nil, remote if branch.nil?
164
- collab = branch && remote
165
-
166
- unless branches(:match => branch)
167
- og_remote = nil
168
-
169
- puts "\nRetrieving repo information from gitcycle.\n".green
170
- repo = get('repo')
171
- remote = repo['owner'] unless collab
172
-
173
- output = add_remote_and_fetch(
174
- :catch => false,
175
- :owner => remote,
176
- :repo => @git_repo
177
- )
178
-
179
- if errored?(output)
180
- og_remote = remote
181
- remote = repo["owner"]
182
-
183
- add_remote_and_fetch(
184
- :owner => remote,
185
- :repo => @git_repo
186
- )
187
- end
188
-
189
- puts "Creating branch '#{branch}' from '#{remote}/#{branch}'.\n".green
190
- output = run("git branch --no-track #{branch} #{remote}/#{branch}", :catch => false)
191
-
192
- if errored?(output)
193
- puts "Could not find branch #{"'#{og_remote}/#{branch}' or " if og_remote}'#{remote}/#{branch}'.\n".red
194
- exit ERROR[:could_not_find_branch]
195
- end
196
- end
197
-
198
- if collab
199
- puts "Sending branch information to gitcycle.".green
200
- get('branch',
201
- 'branch[home]' => remote,
202
- 'branch[name]' => branch,
203
- 'branch[source]' => branch,
204
- 'branch[collab]' => 1,
205
- 'create' => 1
206
- )
207
- end
208
-
209
- puts "Checking out '#{branch}'.\n".green
210
- run("git checkout -q #{branch}")
211
- end
212
- end
213
- alias :co :checkout
214
-
215
- def commit(*args)
216
- msg = nil
217
- no_add = args.delete("--no-add")
218
-
219
- if args.empty?
220
- require_git && require_config
221
-
222
- puts "\nRetrieving branch information from gitcycle.\n".green
223
- branch = get('branch',
224
- 'branch[name]' => branches(:current => true),
225
- 'create' => 0
226
- )
227
-
228
- id = branch["lighthouse_url"].match(/tickets\/(\d+)/)[1] rescue nil
229
-
230
- if branch && id
231
- msg = "[##{id}]"
232
- msg += " #{branch["title"]}" if branch["title"]
233
- end
234
- end
235
-
236
- if no_add
237
- cmd = "git commit"
238
- else
239
- cmd = "git add . && git add . -u && git commit -a"
240
- end
241
-
242
- if File.exists?("#{Dir.pwd}/.git/MERGE_HEAD")
243
- Kernel.exec(cmd)
244
- elsif msg
245
- run(cmd + " -m #{msg.dump.gsub('`', "'")}")
246
- Kernel.exec("git commit --amend")
247
- elsif args.empty?
248
- Kernel.exec(cmd)
249
- else
250
- exec_git(:commit, args)
251
- end
252
- end
253
- alias :ci :commit
254
-
255
- def discuss(*issues)
256
- require_git && require_config
257
-
258
- if issues.empty?
259
- branch = create_pull_request
260
-
261
- if branch == false
262
- puts "Branch not found.\n".red
263
- elsif branch['issue_url']
264
- puts "\nLabeling issue as 'Discuss'.\n".green
265
- get('label',
266
- 'branch[name]' => branch['name'],
267
- 'labels' => [ 'Discuss' ]
268
- )
269
-
270
- puts "Opening issue: #{branch['issue_url']}\n".green
271
- Launchy.open(branch['issue_url'])
272
- else
273
- puts "You must push code before opening a pull request.\n".red
274
- end
275
- else
276
- puts "\nRetrieving branch information from gitcycle.\n".green
277
-
278
- get('branch', 'issues' => issues, 'scope' => 'repo').each do |branch|
279
- if branch['issue_url']
280
- puts "Opening issue: #{branch['issue_url']}\n".green
281
- Launchy.open(branch['issue_url'])
282
- end
283
- end
284
- end
285
- end
286
-
287
- def pull(*args)
288
- exec_git(:pull, args) if args.length > 0
289
-
290
- require_git && require_config
291
-
292
- current_branch = branches(:current => true)
293
-
294
- puts "\nRetrieving branch information from gitcycle.\n".green
295
- branch = get('branch',
296
- 'branch[name]' => current_branch,
297
- 'include' => [ 'repo' ],
298
- 'create' => 0
299
- )
300
-
301
- if branch && branch['collab']
302
- # Merge from collab
303
- merge_remote_branch(
304
- :owner => owner = branch['home'],
305
- :repo => branch['repo']['name'],
306
- :branch => branch['source']
307
- )
308
- elsif branch
309
- # Merge from upstream source branch
310
- merge_remote_branch(
311
- :owner => owner = branch['repo']['owner'],
312
- :repo => branch['repo']['name'],
313
- :branch => branch['source']
314
- )
315
- else
316
- puts "\nRetrieving repo information from gitcycle.\n".green
317
- repo = get('repo')
318
-
319
- # Merge from upstream branch with same name
320
- merge_remote_branch(
321
- :owner => owner = repo['owner'],
322
- :repo => repo['name'],
323
- :branch => current_branch
324
- )
325
- end
326
-
327
- unless branch && branch['collab'] || owner == @git_login
328
- # Merge from origin
329
- merge_remote_branch(
330
- :owner => @git_login,
331
- :repo => @git_repo,
332
- :branch => current_branch
333
- )
334
- end
335
-
336
- branch
337
- end
338
-
339
- def push(*args)
340
- exec_git(:push, args) if args.length > 0
341
-
342
- require_git && require_config
343
-
344
- branch = pull
345
-
346
- if branch && branch['collab']
347
- puts "\nPushing branch '#{branch['home']}/#{branch['name']}'.\n".green
348
- run("git push #{branch['home']} #{branch['name']} -q")
349
- elsif branch
350
- puts "\nPushing branch 'origin/#{branch['name']}'.\n".green
351
- run("git push origin #{branch['name']} -q")
352
- else
353
- current_branch = branches(:current => true)
354
- puts "\nPushing branch 'origin/#{current_branch}'.\n".green
355
- run("git push origin #{current_branch} -q")
356
- end
357
- end
358
-
359
- def qa(*issues)
360
- require_git && require_config
361
-
362
- if issues.empty?
363
- puts "\n"
364
- get('qa_branch').each do |branches|
365
- puts "qa_#{branches['source']}_#{branches['user']}".green
366
- branches['branches'].each do |branch|
367
- puts " #{"issue ##{branch['issue']}".yellow}\t#{branch['user']}/#{branch['branch']}"
368
- end
369
- puts "\n"
370
- end
371
- elsif issues.first == 'fail' || issues.first == 'pass'
372
- branch = branches(:current => true)
373
- pass_fail = issues.first
374
- label = pass_fail.capitalize
375
- issues = issues[1..-1]
376
-
377
- if pass_fail == 'pass' && !issues.empty?
378
- puts "\nWARNING: #{
379
- issues.length == 1 ? "This issue" : "These issues"
380
- } will merge straight into '#{branch}' without testing.\n".red
381
-
382
- if yes?("Continue?")
383
- qa_branch = create_qa_branch(
384
- :instructions => false,
385
- :issues => issues,
386
- :source => branch
387
- )
388
- `git checkout qa_#{qa_branch['source']}_#{qa_branch['user']} -q`
389
- $remotes = {}
390
- qa('pass')
391
- else
392
- exit ERROR[:told_not_to_merge]
393
- end
394
- elsif branch =~ /^qa_/
395
- puts "\nRetrieving branch information from gitcycle.\n".green
396
- qa_branch = get('qa_branch', :source => branch.gsub(/^qa_/, ''))
397
-
398
- if pass_fail == 'pass'
399
- checkout_or_track(:name => qa_branch['source'], :remote => 'origin')
400
- end
401
-
402
- if issues.empty?
403
- branches = qa_branch['branches']
404
- else
405
- branches = qa_branch['branches'].select do |b|
406
- issues.include?(b['issue'])
407
- end
408
- end
409
-
410
- if pass_fail == 'pass' && issues.empty?
411
- owner, repo = qa_branch['repo'].split(':')
412
- merge_remote_branch(
413
- :owner => owner,
414
- :repo => repo,
415
- :branch => "qa_#{qa_branch['source']}_#{qa_branch['user']}",
416
- :type => :from_qa
417
- )
418
- end
419
-
420
- unless issues.empty?
421
- branches.each do |branch|
422
- puts "\nLabeling issue #{branch['issue']} as '#{label}'.\n".green
423
- get('label',
424
- 'qa_branch[source]' => qa_branch['source'],
425
- 'issue' => branch['issue'],
426
- 'labels' => [ label ]
427
- )
428
- end
429
- end
430
-
431
- if issues.empty?
432
- puts "\nLabeling all issues as '#{label}'.\n".green
433
- get('label',
434
- 'qa_branch[source]' => qa_branch['source'],
435
- 'labels' => [ label ]
436
- )
437
- end
438
- else
439
- puts "\nYou are not in a QA branch.\n".red
440
- end
441
- elsif issues.first == 'resolved'
442
- branch = branches(:current => true)
443
-
444
- if branch =~ /^qa_/
445
- puts "\nRetrieving branch information from gitcycle.\n".green
446
- qa_branch = get('qa_branch', :source => branch.gsub(/^qa_/, ''))
447
-
448
- branches = qa_branch['branches']
449
- conflict = branches.detect { |branch| branch['conflict'] }
450
-
451
- if qa_branch && conflict
452
- puts "Committing merge resolution of #{conflict['branch']} (issue ##{conflict['issue']}).\n".green
453
- run("git add . && git add . -u && git commit -a -F .git/MERGE_MSG")
454
-
455
- puts "Pushing merge resolution of #{conflict['branch']} (issue ##{conflict['issue']}).\n".green
456
- run("git push origin qa_#{qa_branch['source']}_#{qa_branch['user']} -q")
457
-
458
- puts "\nDe-conflicting on gitcycle.\n".green
459
- get('qa_branch',
460
- 'issues' => branches.collect { |branch| branch['issue'] }
461
- )
462
-
463
- create_qa_branch(
464
- :preserve => true,
465
- :range => (branches.index(conflict)+1..-1),
466
- :qa_branch => qa_branch
467
- )
468
- else
469
- puts "Couldn't find record of a conflicted merge.\n".red
470
- end
471
- else
472
- puts "\nYou aren't on a QA branch.\n".red
473
- end
474
- else
475
- create_qa_branch(:issues => issues)
476
- end
477
- end
478
-
479
- def ready(*issues)
480
- require_git && require_config
481
-
482
- branch = pull
483
-
484
- if branch && !branch['collab']
485
- # Recreate pull request if force == true
486
- force = branch['labels'] && branch['labels'].include?('Pass')
487
- force ||= branch['state'] && branch['state'] == 'closed'
488
-
489
- branch = create_pull_request(branch, force)
490
- end
491
-
492
- if branch == false
493
- puts "Branch not found.\n".red
494
- elsif branch['collab']
495
- remote, branch = branch['home'], branch['source']
496
- puts "\nPushing branch '#{remote}/#{branch}'.\n".green
497
- run("git push #{remote} #{branch} -q")
498
- elsif branch['issue_url']
499
- puts "\nLabeling issue as 'Pending Review'.\n".green
500
- get('label',
501
- 'branch[name]' => branch['name'],
502
- 'labels' => [ 'Pending Review' ]
503
- )
504
-
505
- puts "Opening issue: #{branch['issue_url']}\n".green
506
- Launchy.open(branch['issue_url'])
507
- else
508
- puts "You have not pushed any commits to '#{branch['name']}'.\n".red
509
- end
510
- end
511
-
512
- def review(pass_fail, *issues)
513
- require_git && require_config
514
-
515
- if pass_fail == 'fail'
516
- label = 'Fail'
517
- else
518
- label = 'Pending QA'
519
- end
520
-
521
- if issues.empty?
522
- puts "\nLabeling issue as '#{label}'.\n".green
523
- get('label',
524
- 'branch[name]' => branches(:current => true),
525
- 'labels' => [ label ]
526
- )
527
- else
528
- puts "\nLabeling issues as '#{label}'.\n".green
529
- get('label',
530
- 'issues' => issues,
531
- 'labels' => [ label ],
532
- 'scope' => 'repo'
533
- )
534
- end
535
- end
536
-
537
- def open(*issues)
538
- require_git && require_config
539
-
540
- if issues.empty?
541
- branch = create_pull_request
542
-
543
- if branch == false
544
- puts "Branch not found.\n".red
545
- elsif branch['issue_url']
546
- puts "\nOpening the pull request in GitHub\n".green
547
-
548
- puts "Opening issue: #{branch['issue_url']}\n".green
549
- Launchy.open(branch['issue_url'])
550
- else
551
- puts "You must push code before opening a pull request.\n".red
552
- end
553
- else
554
- puts "\nRetrieving branch information from gitcycle.\n".green
555
-
556
- get('branch', 'issues' => issues, 'scope' => 'repo').each do |branch|
557
- if branch['issue_url']
558
- puts "Opening issue: #{branch['issue_url']}\n".green
559
- Launchy.open(branch['issue_url'])
560
- end
561
- end
562
- end
563
- end
564
-
565
- def setup(login, repo, token)
566
- repo = "#{login}/#{repo}" unless repo.include?('/')
567
- @config[repo] = [ login, token ]
568
- save_config
569
- puts "\nConfiguration saved.\n".green
570
- end
571
-
572
79
  def start(args=[])
573
80
  command = args.shift
574
81
 
@@ -700,84 +207,6 @@ class Gitcycle
700
207
  branch
701
208
  end
702
209
 
703
- def create_qa_branch(options)
704
- instructions = options[:instructions]
705
- issues = options[:issues]
706
- range = options[:range] || (0..-1)
707
- source = options[:source]
708
-
709
- if (issues && !issues.empty?) || options[:qa_branch]
710
- if options[:qa_branch]
711
- qa_branch = options[:qa_branch]
712
- else
713
- unless source
714
- source = branches(:current => true)
715
-
716
- unless yes?("\nDo you want to create a QA branch from '#{source}'?")
717
- source = q("What branch would you like to base this QA branch off of?")
718
- end
719
- end
720
-
721
- puts "\nRetrieving branch information from gitcycle.\n".green
722
- qa_branch = get('qa_branch', 'issues' => issues, 'source' => source)
723
- end
724
-
725
- source = qa_branch['source']
726
- name = "qa_#{source}_#{qa_branch['user']}"
727
-
728
- unless qa_branch['branches'].empty?
729
- qa_branch['branches'][range].each do |branch|
730
- if source != branch['source']
731
- puts "You can only QA issues based on '#{source}'\n".red
732
- exit ERROR[:cannot_qa]
733
- end
734
- end
735
-
736
- unless options[:preserve]
737
- if branches(:match => name, :all => true)
738
- puts "Deleting old QA branch '#{name}'.\n".green
739
- if branches(:match => name)
740
- run("git checkout master -q")
741
- run("git branch -D #{name}")
742
- end
743
- run("git push origin :#{name} -q")
744
- end
745
-
746
- checkout_remote_branch(
747
- :owner => @git_login,
748
- :repo => @git_repo,
749
- :branch => source,
750
- :target => name
751
- )
752
-
753
- puts "\n"
754
- end
755
-
756
- qa_branch['branches'][range].each do |branch|
757
- issue = branch['issue']
758
- owner, repo = branch['repo'].split(':')
759
- home = branch['home']
760
-
761
- output = merge_remote_branch(
762
- :owner => home,
763
- :repo => repo,
764
- :branch => branch['branch'],
765
- :issue => issue,
766
- :issues => qa_branch['branches'].collect { |b| b['issue'] },
767
- :type => :to_qa
768
- )
769
- end
770
-
771
- unless options[:instructions] == false
772
- puts "\nType '".yellow + "gitc qa pass".green + "' to approve all issues in this branch.\n".yellow
773
- puts "Type '".yellow + "gitc qa fail".red + "' to reject all issues in this branch.\n".yellow
774
- end
775
- end
776
-
777
- qa_branch
778
- end
779
- end
780
-
781
210
  def errored?(output)
782
211
  output.include?("fatal: ") || output.include?("ERROR: ") || $?.exitstatus != 0
783
212
  end
@@ -821,7 +250,9 @@ class Gitcycle
821
250
  :uid => (0...20).map{ ('a'..'z').to_a[rand(26)] }.join
822
251
  )
823
252
 
824
- puts "\nTransaction ID: #{hash[:uid]}".green
253
+ hash[:test] = 1 if ENV['ENV'] == 'test'
254
+
255
+ puts "Transaction ID: #{hash[:uid]}".green
825
256
 
826
257
  params = ''
827
258
  hash[:session] = 0
@@ -858,14 +289,6 @@ class Gitcycle
858
289
  end
859
290
  end
860
291
 
861
- def load_config
862
- if File.exists?(@config_path)
863
- @config = YAML.load(File.read(@config_path))
864
- else
865
- @config = {}
866
- end
867
- end
868
-
869
292
  def git_config_path(path)
870
293
  config = "#{path}/.git/config"
871
294
  if File.exists?(config)
@@ -878,6 +301,14 @@ class Gitcycle
878
301
  end
879
302
  end
880
303
 
304
+ def load_config
305
+ if File.exists?(@config_path)
306
+ @config = YAML.load(File.read(@config_path))
307
+ else
308
+ @config = {}
309
+ end
310
+ end
311
+
881
312
  def load_git
882
313
  path = git_config_path(Dir.pwd)
883
314
  if path
@@ -906,6 +337,11 @@ class Gitcycle
906
337
  def options?(args)
907
338
  args.any? { |arg| arg =~ /^-/ }
908
339
  end
340
+
341
+ def q(question, extra='')
342
+ puts "#{question.yellow}#{extra}"
343
+ $input ? $input.shift : $stdin.gets.strip
344
+ end
909
345
 
910
346
  def remotes(options={})
911
347
  b = `git remote`
@@ -915,11 +351,6 @@ class Gitcycle
915
351
  b
916
352
  end
917
353
  end
918
-
919
- def q(question, extra='')
920
- puts "#{question.yellow}#{extra}"
921
- $input ? $input.shift : $stdin.gets.strip
922
- end
923
354
 
924
355
  def require_config
925
356
  unless @login && @token