gitcycle 0.1.10 → 0.1.11
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -5
- data/features/gitcycle.feature +26 -16
- data/gitcycle.gemspec +1 -1
- data/lib/gitcycle.rb +132 -126
- metadata +4 -4
data/README.md
CHANGED
@@ -99,11 +99,8 @@ This will add a "pass" label to the issue and will complete the pull request by
|
|
99
99
|
Todo
|
100
100
|
----
|
101
101
|
|
102
|
-
* Make ticket active when starting branch
|
103
|
-
* Label issues with ticket milestone?
|
104
102
|
* Check for conflict whenever merge happens
|
103
|
+
* Add conflict check when calling "qa pass [ticket]"
|
105
104
|
* Instead of detecting CONFLICT, use error status $? != 0
|
106
105
|
* Add comment on lighthouse with issue URL
|
107
|
-
*
|
108
|
-
* Add conflict check when calling "qa pass [ticket]"
|
109
|
-
* Need to change Github.parseLabels so we can have a "Fail" label along side a "Pending" tag, but for all other cases there should only be one of these tags present: "Pending QA", "Pending Review", "Pass"
|
106
|
+
* Label issues with ticket milestone?
|
data/features/gitcycle.feature
CHANGED
@@ -29,13 +29,11 @@ Scenario: Feature branch w/ custom branch name
|
|
29
29
|
"""
|
30
30
|
Retrieving branch information from gitcycle.
|
31
31
|
Your work will eventually merge into 'master'. Is this correct? (y/n)
|
32
|
-
Adding remote repo 'br/gitcycle_test'.
|
33
|
-
Fetching remote repo 'br'.
|
34
|
-
Checking out remote branch 'master' from 'br/gitcycle_test'.
|
35
32
|
Would you like to name your branch 'ticket.id'? (y/n)
|
36
33
|
What would you like to name your branch?
|
37
|
-
|
38
|
-
|
34
|
+
Adding remote repo 'config.owner/config.repo'.
|
35
|
+
Fetching remote repo 'config.owner/config.repo'.
|
36
|
+
Checking out remote branch 'ticket.id-rename' from 'config.owner/config.repo/master'.
|
39
37
|
Pushing 'ticket.id-rename'.
|
40
38
|
Sending branch information to gitcycle.
|
41
39
|
"""
|
@@ -53,12 +51,10 @@ Scenario: Feature branch
|
|
53
51
|
"""
|
54
52
|
Retrieving branch information from gitcycle.
|
55
53
|
Your work will eventually merge into 'master'. Is this correct? (y/n)
|
56
|
-
Adding remote repo 'br/gitcycle_test'.
|
57
|
-
Fetching remote repo 'br'.
|
58
|
-
Checking out remote branch 'master' from 'br/gitcycle_test'.
|
59
54
|
Would you like to name your branch 'ticket.id'? (y/n)
|
60
|
-
|
61
|
-
|
55
|
+
Adding remote repo 'config.owner/config.repo'.
|
56
|
+
Fetching remote repo 'config.owner/config.repo'.
|
57
|
+
Checking out remote branch 'ticket.id' from 'config.owner/config.repo/master'.
|
62
58
|
Pushing 'ticket.id'.
|
63
59
|
Sending branch information to gitcycle.
|
64
60
|
"""
|
@@ -99,7 +95,7 @@ Scenario: Pull changes from upstream
|
|
99
95
|
"""
|
100
96
|
Retrieving branch information from gitcycle.
|
101
97
|
Adding remote repo 'config.owner/config.repo'.
|
102
|
-
Fetching remote repo 'config.owner'.
|
98
|
+
Fetching remote repo 'config.owner/config.repo'.
|
103
99
|
Merging remote branch 'master' from 'config.owner/config.repo'.
|
104
100
|
"""
|
105
101
|
And git log should contain the last commit
|
@@ -179,11 +175,25 @@ Scenario: QA issue
|
|
179
175
|
"""
|
180
176
|
Retrieving branch information from gitcycle.
|
181
177
|
Deleting old QA branch 'qa_master'.
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
178
|
+
Adding remote repo 'config.owner/config.repo'.
|
179
|
+
Fetching remote repo 'config.owner/config.repo'.
|
180
|
+
Checking out remote branch 'qa_master' from 'config.owner/config.repo/master'.
|
181
|
+
Pushing 'qa_master'.
|
182
|
+
Adding remote repo 'config.user/config.repo'.
|
183
|
+
Fetching remote repo 'config.user/config.repo'.
|
184
|
+
Merging remote branch 'ticket.id' from 'config.user/config.repo'.
|
185
|
+
Pushing branch 'qa_master'.
|
187
186
|
Type 'gitc qa pass' to approve all issues in this branch.
|
188
187
|
Type 'gitc qa fail' to reject all issues in this branch.
|
188
|
+
"""
|
189
|
+
|
190
|
+
Scenario: QA issue list
|
191
|
+
When I cd to the owner repo
|
192
|
+
And I checkout master
|
193
|
+
And I execute gitcycle with "qa"
|
194
|
+
Then gitcycle runs
|
195
|
+
And output includes
|
196
|
+
"""
|
197
|
+
qa_master
|
198
|
+
issue #issue.id config.user/ticket.id
|
189
199
|
"""
|
data/gitcycle.gemspec
CHANGED
data/lib/gitcycle.rb
CHANGED
@@ -63,39 +63,32 @@ class Gitcycle
|
|
63
63
|
branch['home'] = @git_login
|
64
64
|
branch['source'] = branches(:current => true)
|
65
65
|
|
66
|
-
unless yes?("
|
66
|
+
unless yes?("\nYour work will eventually merge into '#{branch['source']}'. Is this correct?")
|
67
67
|
branch['source'] = q("What branch would you like to eventually merge into?")
|
68
68
|
end
|
69
69
|
|
70
|
-
checkout_remote_branch(
|
71
|
-
:owner => owner,
|
72
|
-
:repo => repo,
|
73
|
-
:branch => branch['source']
|
74
|
-
)
|
75
|
-
|
76
70
|
unless yes?("Would you like to name your branch '#{name}'?")
|
77
71
|
name = q("\nWhat would you like to name your branch?")
|
78
72
|
name = name.gsub(/[\s\W]/, '-')
|
79
73
|
end
|
80
74
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
75
|
+
checkout_remote_branch(
|
76
|
+
:owner => owner,
|
77
|
+
:repo => repo,
|
78
|
+
:branch => branch['source'],
|
79
|
+
:target => name
|
80
|
+
)
|
85
81
|
end
|
86
82
|
|
87
|
-
if
|
88
|
-
|
89
|
-
|
83
|
+
if branch['exists']
|
84
|
+
if branches(:match => name)
|
85
|
+
puts "Checking out branch '#{name}'.\n".green
|
86
|
+
run("git checkout #{name}")
|
87
|
+
else
|
88
|
+
puts "Tracking branch '#{name}'.\n".green
|
89
|
+
run("git fetch && git checkout -b #{name} origin/#{name}")
|
90
|
+
end
|
90
91
|
else
|
91
|
-
puts "Tracking branch '#{name}'.\n".green
|
92
|
-
run("git fetch && git checkout -b #{name} origin/#{name}")
|
93
|
-
end
|
94
|
-
|
95
|
-
unless branch['exists']
|
96
|
-
puts "Pushing '#{name}'.\n".green
|
97
|
-
run("git push origin #{name}")
|
98
|
-
|
99
92
|
puts "Sending branch information to gitcycle.".green
|
100
93
|
get('branch',
|
101
94
|
'branch[home]' => branch['home'],
|
@@ -175,52 +168,56 @@ class Gitcycle
|
|
175
168
|
puts "\nRetrieving branch information from gitcycle.\n".green
|
176
169
|
qa_branch = get('qa_branch', :source => branch.gsub(/^qa_/, ''))
|
177
170
|
|
178
|
-
|
179
|
-
|
180
|
-
run("git pull origin #{qa_branch['source']}")
|
171
|
+
pass_fail = issues.first
|
172
|
+
issues = issues[1..-1]
|
181
173
|
|
182
|
-
if
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
puts "\nLabeling all issues as '#{label}'.\n".green
|
191
|
-
get('label',
|
192
|
-
'qa_branch[source]' => branch.gsub(/^qa_/, ''),
|
193
|
-
'labels' => [ label ]
|
194
|
-
)
|
174
|
+
if pass_fail == 'pass'
|
175
|
+
puts "Checking out #{qa_branch['source']}.".green
|
176
|
+
run("git checkout #{qa_branch['source']}")
|
177
|
+
run("git pull origin #{qa_branch['source']}")
|
178
|
+
# TODO: track if source branch doesn't exist
|
179
|
+
end
|
195
180
|
|
181
|
+
if issues.empty?
|
196
182
|
branches = qa_branch['branches']
|
197
183
|
else
|
198
|
-
issues = [1..-1]
|
199
|
-
|
200
184
|
branches = qa_branch['branches'].select do |b|
|
201
185
|
issues.include?(b['issue'])
|
202
186
|
end
|
187
|
+
end
|
203
188
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
189
|
+
branches.each do |branch|
|
190
|
+
if pass_fail == 'pass'
|
191
|
+
merge_remote_branch(
|
192
|
+
:owner => branch['home'],
|
193
|
+
:repo => branch['repo'].split(':')[1],
|
194
|
+
:branch => branch['branch'],
|
195
|
+
:issue => branch['issue'],
|
196
|
+
:issues => qa_branch['branches'].collect { |b| b['issue'] },
|
197
|
+
:type => :from_qa
|
198
|
+
)
|
199
|
+
end
|
212
200
|
|
201
|
+
if !issues.empty? || pass_fail == 'pass'
|
213
202
|
puts "\nLabeling issue #{branch['issue']} as '#{label}'.\n".green
|
214
203
|
get('label',
|
215
|
-
'qa_branch[source]' =>
|
204
|
+
'qa_branch[source]' => qa_branch['source'],
|
216
205
|
'issue' => branch['issue'],
|
217
206
|
'labels' => [ label ]
|
218
207
|
)
|
219
208
|
end
|
220
209
|
end
|
221
210
|
|
222
|
-
if issues.
|
223
|
-
puts "\
|
211
|
+
if issues.empty? && pass_fail == 'fail'
|
212
|
+
puts "\nLabeling all issues as '#{label}'.\n".green
|
213
|
+
get('label',
|
214
|
+
'qa_branch[source]' => qa_branch['source'],
|
215
|
+
'labels' => [ label ]
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
if pass_fail == 'pass'
|
220
|
+
puts "Marking Lighthouse tickets as 'pending-approval'.\n".green
|
224
221
|
branches = branches.collect do |b|
|
225
222
|
{ :name => b['branch'], :repo => b['repo'], :user => b['user'] }
|
226
223
|
end
|
@@ -235,26 +232,27 @@ class Gitcycle
|
|
235
232
|
if branch =~ /^qa_/
|
236
233
|
puts "\nRetrieving branch information from gitcycle.\n".green
|
237
234
|
qa_branch = get('qa_branch', :source => branch.gsub(/^qa_/, ''))
|
235
|
+
|
236
|
+
branches = qa_branch['branches']
|
237
|
+
conflict = branches.detect { |branch| branch['conflict'] }
|
238
238
|
|
239
|
-
if qa_branch
|
240
|
-
|
241
|
-
|
239
|
+
if qa_branch && conflict
|
240
|
+
puts "Committing merge resolution of #{conflict['branch']} (issue ##{conflict['issue']}).\n".green
|
241
|
+
run("git add . && git add . -u && git commit -a -F .git/MERGE_MSG")
|
242
242
|
|
243
|
-
|
244
|
-
|
245
|
-
run("git add . && git add . -u && git commit -a -m 'Merge conflict resolution of #{conflict['branch']} (issue ##{conflict['issue']})'")
|
243
|
+
puts "Pushing merge resolution of #{conflict['branch']} (issue ##{conflict['issue']}).\n".green
|
244
|
+
run("git push origin qa_#{qa_branch['source']}")
|
246
245
|
|
247
|
-
|
248
|
-
|
246
|
+
puts "\nDe-conflicting on gitcycle.\n".green
|
247
|
+
get('qa_branch',
|
248
|
+
'issues' => branches.collect { |branch| branch['issue'] }
|
249
|
+
)
|
249
250
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
else
|
256
|
-
puts "Couldn't find record of a conflicted merge.\n".red
|
257
|
-
end
|
251
|
+
create_qa_branch(
|
252
|
+
:preserve => true,
|
253
|
+
:range => (branches.index(conflict)+1..-1),
|
254
|
+
:qa_branch => qa_branch
|
255
|
+
)
|
258
256
|
else
|
259
257
|
puts "Couldn't find record of a conflicted merge.\n".red
|
260
258
|
end
|
@@ -297,17 +295,25 @@ class Gitcycle
|
|
297
295
|
def reviewed(*issues)
|
298
296
|
require_git && require_config
|
299
297
|
|
298
|
+
if issues.include?("fail")
|
299
|
+
issues = issues.reject{|x| x=='fail'}
|
300
|
+
label = 'Fail'
|
301
|
+
else
|
302
|
+
issues = issues.reject{|x| x=='pass'}
|
303
|
+
label = 'Pending QA'
|
304
|
+
end
|
305
|
+
|
300
306
|
if issues.empty?
|
301
|
-
puts "\nLabeling issue as '
|
307
|
+
puts "\nLabeling issue as '#{label}'.\n".green
|
302
308
|
get('label',
|
303
309
|
'branch[name]' => branches(:current => true),
|
304
|
-
'labels' => [
|
310
|
+
'labels' => [ label ]
|
305
311
|
)
|
306
312
|
else
|
307
|
-
puts "\nLabeling issues as '
|
313
|
+
puts "\nLabeling issues as '#{label}'.\n".green
|
308
314
|
get('label',
|
309
315
|
'issues' => issues,
|
310
|
-
'labels' => [
|
316
|
+
'labels' => [ label ],
|
311
317
|
'scope' => 'repo'
|
312
318
|
)
|
313
319
|
end
|
@@ -348,7 +354,7 @@ class Gitcycle
|
|
348
354
|
run("git remote add #{owner} git@github.com:#{owner}/#{repo}.git")
|
349
355
|
end
|
350
356
|
|
351
|
-
puts "
|
357
|
+
puts "Fetching remote repo '#{owner}/#{repo}'.\n".green
|
352
358
|
run("git fetch #{owner}")
|
353
359
|
end
|
354
360
|
|
@@ -367,23 +373,23 @@ class Gitcycle
|
|
367
373
|
owner = options[:owner]
|
368
374
|
repo = options[:repo]
|
369
375
|
branch = options[:branch]
|
376
|
+
target = options[:target] || branch
|
377
|
+
|
378
|
+
if branches(:match => target)
|
379
|
+
unless yes?("You already have a branch called '#{target}'. Overwrite?")
|
380
|
+
run("git checkout #{target}")
|
381
|
+
run("git pull #{owner} #{target}")
|
382
|
+
return
|
383
|
+
end
|
384
|
+
end
|
370
385
|
|
371
386
|
add_remote_and_fetch(options)
|
372
387
|
|
373
|
-
puts "
|
388
|
+
puts "Checking out remote branch '#{target}' from '#{owner}/#{repo}/#{branch}'.\n".green
|
389
|
+
run("git checkout -b #{target} #{owner}/#{branch}")
|
374
390
|
|
375
|
-
|
376
|
-
|
377
|
-
else
|
378
|
-
run("git checkout -b #{branch} #{owner}/#{branch}")
|
379
|
-
end
|
380
|
-
|
381
|
-
if branches(:current => true) == branch
|
382
|
-
run("git pull #{owner} #{branch}")
|
383
|
-
else
|
384
|
-
puts "Oops. Something bad happened.\n".red
|
385
|
-
exit
|
386
|
-
end
|
391
|
+
puts "Pushing '#{target}'.\n".green
|
392
|
+
run("git push origin #{target}")
|
387
393
|
end
|
388
394
|
|
389
395
|
def create_pull_request
|
@@ -423,27 +429,19 @@ class Gitcycle
|
|
423
429
|
|
424
430
|
unless qa_branch['branches'].empty?
|
425
431
|
unless options[:preserve]
|
426
|
-
if branches(:current => source)
|
427
|
-
# Do nothing
|
428
|
-
elsif branches(:match => source)
|
429
|
-
puts "Checking out source branch '#{source}'.\n".green
|
430
|
-
run("git checkout #{source}")
|
431
|
-
else
|
432
|
-
puts "Tracking source branch '#{source}'.\n".green
|
433
|
-
run("git fetch && git checkout -b #{source} origin/#{source}")
|
434
|
-
end
|
435
|
-
|
436
|
-
run("git pull origin #{source}")
|
437
|
-
|
438
432
|
if branches(:match => name, :all => true)
|
439
433
|
puts "Deleting old QA branch '#{name}'.\n".green
|
440
|
-
run("git branch -D #{name}")
|
434
|
+
run("git branch -D #{name}") if branches(:match => name)
|
441
435
|
run("git push origin :#{name}")
|
442
436
|
end
|
443
|
-
|
444
|
-
puts "Creating QA branch '#{name}'.\n".green
|
445
|
-
run("git branch #{name} && git checkout #{name}")
|
446
437
|
|
438
|
+
checkout_remote_branch(
|
439
|
+
:owner => @git_login,
|
440
|
+
:repo => @git_repo,
|
441
|
+
:branch => source,
|
442
|
+
:target => name
|
443
|
+
)
|
444
|
+
|
447
445
|
puts "\n"
|
448
446
|
end
|
449
447
|
|
@@ -456,32 +454,11 @@ class Gitcycle
|
|
456
454
|
output = merge_remote_branch(
|
457
455
|
:owner => home,
|
458
456
|
:repo => repo,
|
459
|
-
:branch => branch
|
457
|
+
:branch => branch,
|
458
|
+
:issue => issue,
|
459
|
+
:issues => qa_branch['branches'].collect { |b| b['issue'] },
|
460
|
+
:type => :to_qa
|
460
461
|
)
|
461
|
-
|
462
|
-
if output.include?('CONFLICT')
|
463
|
-
puts "Conflict occurred when merging '#{branch}' (issue ##{issue}).\n".red
|
464
|
-
answer = q("Would you like to (s)kip or (r)esolve?")
|
465
|
-
|
466
|
-
issues = qa_branch['branches'].collect { |b| b['issue'] }
|
467
|
-
|
468
|
-
if answer.downcase[0..0] == 's'
|
469
|
-
run("git reset --hard HEAD")
|
470
|
-
issues.delete(issue)
|
471
|
-
|
472
|
-
puts "\nSending QA branch information to gitcycle.\n".green
|
473
|
-
get('qa_branch', 'issues' => issues, 'conflict' => issue)
|
474
|
-
else
|
475
|
-
puts "\nSending conflict information to gitcycle.\n".green
|
476
|
-
get('qa_branch', 'issues' => issues, 'conflict' => issue)
|
477
|
-
|
478
|
-
puts "Type 'gitc qa resolved' when finished resolving.\n".yellow
|
479
|
-
exit
|
480
|
-
end
|
481
|
-
else
|
482
|
-
puts "Pushing QA branch '#{name}'.\n".green
|
483
|
-
run("git push origin #{name}")
|
484
|
-
end
|
485
462
|
end
|
486
463
|
|
487
464
|
puts "\nType '".yellow + "gitc qa pass".green + "' to approve all issues in this branch.\n".yellow
|
@@ -490,6 +467,33 @@ class Gitcycle
|
|
490
467
|
end
|
491
468
|
end
|
492
469
|
|
470
|
+
def fix_conflict(options)
|
471
|
+
owner = options[:owner]
|
472
|
+
repo = options[:repo]
|
473
|
+
branch = options[:branch]
|
474
|
+
issue = options[:issue]
|
475
|
+
issues = options[:issues]
|
476
|
+
type = options[:type]
|
477
|
+
|
478
|
+
if $? != 0
|
479
|
+
puts "Conflict occurred when merging '#{branch}'#{" (issue ##{issue})" if issue}.\n".red
|
480
|
+
|
481
|
+
if type # from_qa or to_qa
|
482
|
+
puts "Please resolve this conflict with '#{owner}'.\n".yellow
|
483
|
+
|
484
|
+
puts "\nSending conflict information to gitcycle.\n".green
|
485
|
+
get('qa_branch', 'issues' => issues, "conflict_#{type}" => issue)
|
486
|
+
|
487
|
+
puts "Type 'gitc qa resolved' when finished resolving.\n".yellow
|
488
|
+
exit
|
489
|
+
end
|
490
|
+
elsif type # from_qa or to_qa
|
491
|
+
branch = branches(:current => true)
|
492
|
+
puts "Pushing branch '#{branch}'.\n".green
|
493
|
+
run("git push origin #{branch}")
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
493
497
|
def get(path, hash={})
|
494
498
|
hash.merge!(
|
495
499
|
:login => @login,
|
@@ -538,6 +542,8 @@ class Gitcycle
|
|
538
542
|
|
539
543
|
puts "\nMerging remote branch '#{branch}' from '#{owner}/#{repo}'.\n".green
|
540
544
|
run("git merge #{owner}/#{branch}")
|
545
|
+
|
546
|
+
fix_conflict(options)
|
541
547
|
end
|
542
548
|
|
543
549
|
def remotes(options={})
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitcycle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 11
|
10
|
+
version: 0.1.11
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Winton Welsh
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-01-
|
18
|
+
date: 2012-01-23 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|