git-maintain 0.9.0 → 0.12.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.
- checksums.yaml +4 -4
- data/CHANGELOG +29 -0
- data/README.md +9 -7
- data/bin/git-maintain +9 -0
- data/git-maintain-completion.sh +2 -2
- data/lib/addons/RDMACore.rb +71 -16
- data/lib/addons/git-maintain.rb +32 -12
- data/lib/azure.rb +2 -2
- data/lib/branch.rb +313 -232
- data/lib/common.rb +54 -14
- data/lib/repo.rb +144 -110
- metadata +7 -13
data/lib/branch.rb
CHANGED
@@ -10,16 +10,15 @@ module GitMaintain
|
|
10
10
|
|
11
11
|
class Branch
|
12
12
|
ACTION_LIST = [
|
13
|
-
:cp, :steal, :list,
|
14
|
-
:merge, :push, :monitor,
|
15
|
-
:push_stable, :monitor_stable,
|
13
|
+
:cp, :steal, :list,
|
14
|
+
:merge, :pull, :push, :monitor,
|
16
15
|
:release, :reset, :create, :delete
|
17
16
|
]
|
18
17
|
NO_FETCH_ACTIONS = [
|
19
18
|
:cp, :merge, :monitor, :release, :delete
|
20
19
|
]
|
21
20
|
NO_CHECKOUT_ACTIONS = [
|
22
|
-
:create, :delete, :list, :
|
21
|
+
:create, :delete, :list, :push, :monitor
|
23
22
|
]
|
24
23
|
ALL_BRANCHES_ACTIONS = [
|
25
24
|
:create
|
@@ -30,12 +29,10 @@ module GitMaintain
|
|
30
29
|
:delete => "Delete all local branches using the suffix",
|
31
30
|
:steal => "Steal commit from upstream that fixes commit in the branch or were tagged as stable",
|
32
31
|
:list => "List commit present in the branch but not in the stable branch",
|
33
|
-
:list_stable => "List commit present in the stable branch but not in the latest associated relase",
|
34
32
|
:merge => "Merge branch with suffix specified in -m <suff> into the main branch",
|
35
33
|
:push => "Push branches to github for validation",
|
34
|
+
:pull => "Rebase branches on top of the upstream one",
|
36
35
|
:monitor => "Check the CI state of all branches",
|
37
|
-
:push_stable => "Push to stable repo",
|
38
|
-
:monitor_stable => "Check the CI state of all stable branches",
|
39
36
|
:release => "Create new release on all concerned branches",
|
40
37
|
:reset => "Reset branch against upstream",
|
41
38
|
}
|
@@ -58,6 +55,7 @@ module GitMaintain
|
|
58
55
|
opts[:watch] = false
|
59
56
|
opts[:delete_remote] = false
|
60
57
|
opts[:no_edit] = false
|
58
|
+
opts[:stable] = false
|
61
59
|
|
62
60
|
optsParser.on("-v", "--base-version [MIN_VER]", Integer, "Older release to consider.") {
|
63
61
|
|val| opts[:base_ver] = val}
|
@@ -84,41 +82,49 @@ module GitMaintain
|
|
84
82
|
when :delete
|
85
83
|
optsParser.on("--remote", "Delete the remote staging branch instead of the local ones.") {
|
86
84
|
|val| opts[:delete_remote] = true}
|
85
|
+
when :list
|
86
|
+
optsParser.on("--stable", "List unreleased commits in the upstream stable branch.") {
|
87
|
+
opts[:stable] = true }
|
87
88
|
when :merge
|
88
89
|
optsParser.banner += "-m <suffix>"
|
89
90
|
optsParser.on("-m", "--merge [SUFFIX]", "Merge branch with suffix.") {
|
90
91
|
|val| opts[:do_merge] = val}
|
91
|
-
when :monitor
|
92
|
+
when :monitor
|
92
93
|
optsParser.on("-w", "--watch <PERIOD>", Integer,
|
93
94
|
"Watch and refresh CI status every <PERIOD>.") {
|
94
95
|
|val| opts[:watch] = val}
|
96
|
+
optsParser.on("--stable", "Check CI status on stable repo.") {
|
97
|
+
opts[:stable] = true }
|
98
|
+
when :pull
|
99
|
+
optsParser.on("--stable", "List unreleased commits in the upstream stable branch.") {
|
100
|
+
opts[:stable] = true }
|
95
101
|
when :push
|
96
102
|
optsParser.banner += "[-f]"
|
97
103
|
optsParser.on("-f", "--force", "Add --force to git push (for 'push' action).") {
|
98
|
-
|
99
|
-
|
104
|
+
opts[:push_force] = true}
|
105
|
+
optsParser.on("--stable", "Push to stable repo.") {
|
106
|
+
opts[:stable] = true }
|
100
107
|
optsParser.banner += "[-T]"
|
101
108
|
optsParser.on("-T", "--no-ci", "Ignore CI build status and push anyway.") {
|
102
|
-
|
109
|
+
opts[:no_ci] = true}
|
103
110
|
optsParser.on("-c", "--check", "Check if there is something to be pushed.") {
|
104
|
-
|
111
|
+
opts[:check_only] = true}
|
105
112
|
when :release
|
106
|
-
|
107
|
-
|
113
|
+
optsParser.on("--no-edit", "Do not edit release commit nor tag.") {
|
114
|
+
opts[:no_edit] = true }
|
108
115
|
when :steal
|
109
116
|
optsParser.banner += "[-a][-b <HEAD>]"
|
110
117
|
optsParser.on("-a", "--all", "Check all commits from master. "+
|
111
|
-
|
118
|
+
"By default only new commits (since last successful run) are considered.") {
|
112
119
|
|val| opts[:steal_base] = :all}
|
113
120
|
optsParser.on("-b", "--base <HEAD>", "Check all commits from this commit. "+
|
114
|
-
|
121
|
+
"By default only new commits (since last successful run) are considered.") {
|
115
122
|
|val| opts[:steal_base] = val}
|
116
123
|
end
|
117
124
|
end
|
118
125
|
|
119
126
|
def self.check_opts(opts)
|
120
|
-
if opts[:action] == :
|
121
|
-
opts[:action] == :release then
|
127
|
+
if opts[:action] == :release then
|
122
128
|
if opts[:br_suff] != "master" then
|
123
129
|
raise "Action #{opts[:action]} can only be done on 'master' suffixed branches"
|
124
130
|
end
|
@@ -128,6 +134,11 @@ module GitMaintain
|
|
128
134
|
raise "Action #{opts[:action]} can NOT be done on 'master' suffixed branches"
|
129
135
|
end
|
130
136
|
end
|
137
|
+
if opts[:action] == :push
|
138
|
+
if opts[:stable] == true && opts[:push_force] == true then
|
139
|
+
raise "Action push can NOT be use both --stable and --force"
|
140
|
+
end
|
141
|
+
end
|
131
142
|
opts[:version] = [ /.*/ ] if opts[:version].length == 0
|
132
143
|
end
|
133
144
|
|
@@ -192,6 +203,8 @@ module GitMaintain
|
|
192
203
|
sleep(opts[:watch])
|
193
204
|
ci.emptyCache()
|
194
205
|
end
|
206
|
+
GitMaintain::log(:INFO, "Done working on selected branches")
|
207
|
+
|
195
208
|
end
|
196
209
|
|
197
210
|
def initialize(repo, version, ci, branch_suff)
|
@@ -213,9 +226,15 @@ module GitMaintain
|
|
213
226
|
@verbose_name = version
|
214
227
|
end
|
215
228
|
|
216
|
-
@head = @repo.
|
229
|
+
@head = @repo.ref_exist?(@local_branch)
|
230
|
+
@valid_ref = "#{@repo.valid_repo}/#{@local_branch}"
|
217
231
|
@remote_ref = "#{@repo.stable_repo}/#{@remote_branch}"
|
218
|
-
@stable_head =
|
232
|
+
@stable_head =
|
233
|
+
begin
|
234
|
+
@repo.ref_exist?(@remote_ref)
|
235
|
+
rescue
|
236
|
+
nil
|
237
|
+
end
|
219
238
|
case @branch_type
|
220
239
|
when :std
|
221
240
|
@stable_base = @repo.findStableBase(@local_branch)
|
@@ -223,7 +242,7 @@ module GitMaintain
|
|
223
242
|
@stable_base = @remote_ref
|
224
243
|
end
|
225
244
|
end
|
226
|
-
attr_reader :version, :local_branch, :head, :remote_branch, :remote_ref, :stable_head,
|
245
|
+
attr_reader :version, :local_branch, :head, :remote_branch, :valid_ref, :remote_ref, :stable_head,
|
227
246
|
:verbose_name, :exists, :stable_base
|
228
247
|
|
229
248
|
def log(lvl, str)
|
@@ -243,9 +262,10 @@ module GitMaintain
|
|
243
262
|
|
244
263
|
# Checkout the repo to the given branch
|
245
264
|
def checkout()
|
246
|
-
|
247
|
-
|
248
|
-
|
265
|
+
begin
|
266
|
+
print @repo.runGit("checkout -q #{@local_branch}")
|
267
|
+
rescue RuntimeError => e
|
268
|
+
crit("Failed to checkout the branch #{@local_branch}")
|
249
269
|
end
|
250
270
|
end
|
251
271
|
|
@@ -254,15 +274,16 @@ module GitMaintain
|
|
254
274
|
opts[:commits].each(){|commit|
|
255
275
|
prev_head=@repo.runGit("rev-parse HEAD")
|
256
276
|
log(:INFO, "Applying #{@repo.getCommitHeadline(commit)}")
|
257
|
-
|
258
|
-
|
277
|
+
begin
|
278
|
+
@repo.runGitInteractive("cherry-pick #{commit}")
|
279
|
+
rescue RuntimeError
|
259
280
|
log(:WARNING, "Cherry pick failure. Starting bash for manual fixes. Exit shell to continue")
|
260
|
-
|
261
|
-
|
281
|
+
@repo.runBash("PS1_WARNING='CP FIX'")
|
282
|
+
end
|
262
283
|
new_head=@repo.runGit("rev-parse HEAD")
|
263
284
|
# Do not make commit pretty if it was not applied
|
264
285
|
if new_head != prev_head
|
265
|
-
|
286
|
+
make_pretty(commit)
|
266
287
|
end
|
267
288
|
}
|
268
289
|
end
|
@@ -274,22 +295,26 @@ module GitMaintain
|
|
274
295
|
# If we are not force checking everything,
|
275
296
|
# try to start from the last tag we steal upto
|
276
297
|
case opts[:steal_base]
|
277
|
-
|
298
|
+
when nil
|
299
|
+
begin
|
278
300
|
sha = @repo.runGit("rev-parse 'git-maintain/steal/last/#{@stable_base}' 2>&1")
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
301
|
+
base_ref=sha
|
302
|
+
log(:VERBOSE, "Starting from last successfull run:")
|
303
|
+
log(:VERBOSE, @repo.getCommitHeadline(base_ref))
|
304
|
+
rescue RuntimeError
|
305
|
+
# No matching tag found. Not an issue
|
306
|
+
end
|
307
|
+
when :all
|
308
|
+
base_ref=@stable_base
|
309
|
+
else
|
310
|
+
begin
|
287
311
|
sha = @repo.runGit("rev-parse #{opts[:steal_base]} 2>&1")
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
312
|
+
base_ref=sha
|
313
|
+
log(:VERBOSE, "Starting from base:")
|
314
|
+
log(:VERBOSE, @repo.getCommitHeadline(base_ref))
|
315
|
+
rescue RuntimeError
|
316
|
+
crit("Could not find specified base '#{opts[:steal_base]}'")
|
317
|
+
end
|
293
318
|
end
|
294
319
|
|
295
320
|
master_sha=@repo.runGit("rev-parse origin/master")
|
@@ -305,16 +330,15 @@ module GitMaintain
|
|
305
330
|
end
|
306
331
|
end
|
307
332
|
|
308
|
-
# List commits in the branch that are no in the stable branch
|
309
333
|
def list(opts)
|
310
334
|
GitMaintain::log(:INFO, "Working on #{@verbose_name}")
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
335
|
+
if opts[:stable] == true then
|
336
|
+
# List commits in the stable_branch that are no in the latest release
|
337
|
+
GitMaintain::showLog(opts, @remote_ref, @repo.runGit("describe --abbrev=0 #{@local_branch}"))
|
338
|
+
else
|
339
|
+
# List commits in the branch that are no in the stable branch
|
340
|
+
GitMaintain::showLog(opts, @local_branch, @remote_ref)
|
341
|
+
end
|
318
342
|
end
|
319
343
|
|
320
344
|
# Merge merge_branch into this one
|
@@ -322,8 +346,9 @@ module GitMaintain
|
|
322
346
|
merge_branch = @repo.versionToLocalBranch(@version, opts[:do_merge])
|
323
347
|
|
324
348
|
# Make sure branch exists
|
325
|
-
|
326
|
-
|
349
|
+
begin
|
350
|
+
hash_to_merge = @repo.ref_exist?(merge_branch)
|
351
|
+
rescue NoRefError
|
327
352
|
log(:INFO, "Branch #{merge_branch} does not exists. Skipping...")
|
328
353
|
return
|
329
354
|
end
|
@@ -337,25 +362,68 @@ module GitMaintain
|
|
337
362
|
|
338
363
|
rep = GitMaintain::checkLog(opts, merge_branch, @local_branch, "merge")
|
339
364
|
if rep == "y" then
|
340
|
-
|
341
|
-
|
365
|
+
begin
|
366
|
+
@repo.runGitInteractive("merge #{merge_branch}")
|
367
|
+
rescue RuntimeError
|
342
368
|
log(:WARNING, "Merge failure. Starting bash for manual fixes. Exit shell to continue")
|
343
|
-
|
344
|
-
|
369
|
+
@repo.runBash("PS1_WARNING='MERGING'")
|
370
|
+
end
|
345
371
|
else
|
346
372
|
log(:INFO, "Skipping merge")
|
347
373
|
return
|
348
374
|
end
|
349
375
|
end
|
350
376
|
|
377
|
+
def pull(opts)
|
378
|
+
remoteRef = opts[:stable] == true ? @remote_ref : @valid_ref
|
379
|
+
|
380
|
+
# Make sure branch exists
|
381
|
+
begin
|
382
|
+
@repo.ref_exist?(remoteRef)
|
383
|
+
rescue NoRefError
|
384
|
+
log(:INFO, "Branch #{remoteRef} does not exists. Skipping...")
|
385
|
+
return
|
386
|
+
end
|
387
|
+
@repo.runGitInteractive("rebase #{remoteRef}")
|
388
|
+
|
389
|
+
end
|
351
390
|
# Push the branch to the validation repo
|
352
391
|
def push(opts)
|
353
|
-
|
392
|
+
remoteRef = opts[:stable] == true ? @remote_ref : @valid_ref
|
393
|
+
|
394
|
+
# Check both where we want to push and the final remote_ref
|
395
|
+
# We may have destroyed the validation branch but if we already merged
|
396
|
+
# in the final repo, no need to worry about it.
|
397
|
+
if same_sha?(@local_branch, remoteRef) ||
|
354
398
|
same_sha?(@local_branch, @remote_ref) then
|
355
399
|
log(:INFO, "Nothing to push on #{@local_branch}")
|
356
400
|
return
|
357
401
|
end
|
358
|
-
|
402
|
+
|
403
|
+
# For stable branches, we need to check for CI
|
404
|
+
if opts[:stable] == true &&
|
405
|
+
(opts[:no_ci] != true && @NO_CI != true) &&
|
406
|
+
@ci.checkValidState(self, @head) != true then
|
407
|
+
log(:WARNING, "Build is not passed on CI. Skipping push to stable")
|
408
|
+
return
|
409
|
+
end
|
410
|
+
|
411
|
+
if opts[:check_only] == true then
|
412
|
+
GitMaintain::checkLog(opts, @local_branch, @remote_ref, "")
|
413
|
+
return
|
414
|
+
end
|
415
|
+
|
416
|
+
# For validation/CI push, let's go and push already
|
417
|
+
return "#{@local_branch}:#{@local_branch}" if opts[:stable] != true
|
418
|
+
|
419
|
+
# For stable, we need to confirm with the user that he really wants to push
|
420
|
+
rep = GitMaintain::checkLog(opts, @local_branch, @remote_ref, "submit")
|
421
|
+
if rep == "y" then
|
422
|
+
return "#{@local_branch}:#{@remote_branch}"
|
423
|
+
else
|
424
|
+
log(:INFO, "Skipping push to stable")
|
425
|
+
return
|
426
|
+
end
|
359
427
|
end
|
360
428
|
|
361
429
|
def self.push_epilogue(opts, branches)
|
@@ -364,17 +432,26 @@ module GitMaintain
|
|
364
432
|
|
365
433
|
return if branches.length == 0
|
366
434
|
|
435
|
+
repo = (opts[:stable] == true) ? opts[:repo].stable_repo : opts[:repo].valid_repo
|
367
436
|
opts[:repo].runGit("push #{opts[:push_force] == true ? "-f" : ""} "+
|
368
|
-
"#{
|
437
|
+
"#{repo} #{branches.join(" ")}")
|
369
438
|
end
|
370
439
|
|
371
440
|
# Monitor the build status on CI
|
372
441
|
def monitor(opts)
|
373
|
-
st =
|
442
|
+
ts = st = head = nil
|
374
443
|
suff=""
|
444
|
+
if opts[:stable] == true then
|
445
|
+
st = @ci.getStableState(self, @stable_head)
|
446
|
+
ts = @ci.getStableTS(self, @stable_head) if st == "started"
|
447
|
+
else
|
448
|
+
st = @ci.getValidState(self, @head)
|
449
|
+
ts = @ci.getValidTS(self, @head) if st == "started"
|
450
|
+
end
|
451
|
+
|
375
452
|
case st
|
376
453
|
when "started"
|
377
|
-
suff= "
|
454
|
+
suff= " at #{ts}"
|
378
455
|
end
|
379
456
|
log(:INFO, "Status for v#{@version}: " + st + suff)
|
380
457
|
if @ci.isErrored(self, st) && opts[:watch] == false
|
@@ -396,52 +473,6 @@ module GitMaintain
|
|
396
473
|
end
|
397
474
|
end
|
398
475
|
|
399
|
-
# Push branch to the stable repo
|
400
|
-
def push_stable(opts)
|
401
|
-
if same_sha?(@local_branch, @remote_ref) then
|
402
|
-
log(:INFO, "Stable is already up-to-date")
|
403
|
-
return
|
404
|
-
end
|
405
|
-
|
406
|
-
if (opts[:no_ci] != true && @NO_CI != true) &&
|
407
|
-
@ci.checkValidState(self, @head) != true then
|
408
|
-
log(:WARNING, "Build is not passed on CI. Skipping push to stable")
|
409
|
-
return
|
410
|
-
end
|
411
|
-
|
412
|
-
if opts[:check_only] == true then
|
413
|
-
GitMaintain::checkLog(opts, @local_branch, @remote_ref, "")
|
414
|
-
return
|
415
|
-
end
|
416
|
-
|
417
|
-
rep = GitMaintain::checkLog(opts, @local_branch, @remote_ref, "submit")
|
418
|
-
if rep == "y" then
|
419
|
-
return "#{@local_branch}:#{@remote_branch}"
|
420
|
-
else
|
421
|
-
log(:INFO, "Skipping push to stable")
|
422
|
-
return
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
|
427
|
-
def self.push_stable_epilogue(opts, branches)
|
428
|
-
# Compact to remove empty entries
|
429
|
-
branches.compact!()
|
430
|
-
|
431
|
-
return if branches.length == 0
|
432
|
-
opts[:repo].runGit("push #{opts[:repo].stable_repo} #{branches.join(" ")}")
|
433
|
-
end
|
434
|
-
# Monitor the build status of the stable branch on CI
|
435
|
-
def monitor_stable(opts)
|
436
|
-
st = @ci.getStableState(self, @stable_head)
|
437
|
-
suff=""
|
438
|
-
case st
|
439
|
-
when "started"
|
440
|
-
suff= " started at #{@ci.getStableTS(self, @stable_head)}"
|
441
|
-
end
|
442
|
-
log(:INFO, "Status for v#{@version}: " + st + suff)
|
443
|
-
end
|
444
|
-
|
445
476
|
# Reset the branch to the upstream stable one
|
446
477
|
def reset(opts)
|
447
478
|
if same_sha?(@local_branch, @remote_ref) then
|
@@ -470,8 +501,9 @@ module GitMaintain
|
|
470
501
|
|
471
502
|
def delete(opts)
|
472
503
|
if opts[:delete_remote] == true then
|
473
|
-
|
474
|
-
|
504
|
+
begin
|
505
|
+
@repo.ref_exist?("#{@repo.valid_repo}/#{@local_branch}")
|
506
|
+
rescue NoRefError
|
475
507
|
log(:DEBUG, "Skipping non existing remote branch #{@local_branch}.")
|
476
508
|
return
|
477
509
|
end
|
@@ -507,13 +539,16 @@ module GitMaintain
|
|
507
539
|
|
508
540
|
private
|
509
541
|
def add_blacklist(commit)
|
510
|
-
|
542
|
+
@repo.runGit("notes append -m \"#{@local_branch}\" #{commit}")
|
511
543
|
end
|
512
544
|
|
513
545
|
def is_blacklisted?(commit)
|
514
|
-
|
515
|
-
|
516
|
-
|
546
|
+
begin
|
547
|
+
@repo.runGit("notes show #{commit} 2> /dev/null").split("\n").each(){|br|
|
548
|
+
return true if br == @local_branch
|
549
|
+
}
|
550
|
+
rescue
|
551
|
+
end
|
517
552
|
return false
|
518
553
|
end
|
519
554
|
|
@@ -523,113 +558,115 @@ module GitMaintain
|
|
523
558
|
|
524
559
|
msg_path=`mktemp`.chomp()
|
525
560
|
msg_file = File.open(msg_path, "w+")
|
526
|
-
|
561
|
+
msg_file.puts @repo.runGit("log -1 --format=\"%s%n%n[ Upstream commit #{msg_commit} ]%n%n%b\" #{orig_commit}")
|
527
562
|
msg_file.close()
|
528
|
-
|
563
|
+
@repo.runGit("commit -s --amend -F #{msg_path}")
|
529
564
|
`rm -f #{msg_path}`
|
530
565
|
end
|
531
566
|
|
532
567
|
def is_in_tree?(commit, src_commit=commit)
|
533
|
-
|
568
|
+
fullhash=nil
|
569
|
+
begin
|
570
|
+
fullhash=@repo.ref_exist?(commit)
|
571
|
+
rescue NoRefError
|
534
572
|
# This might happen if someone pointed to a commit that doesn't exist in our
|
535
573
|
# tree.
|
536
|
-
if $? != 0 then
|
537
574
|
log(:WARNING, "Commit #{src_commit} points to a SHA #{commit} not in tree")
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
# Try and find if there's a commit with given subject the hard way
|
554
|
-
@repo.runGit("log --pretty=\"%H\" -F --grep \"#{subj.gsub("\"", '\\"')}\" "+
|
575
|
+
return false
|
576
|
+
end
|
577
|
+
|
578
|
+
# Hope for the best, same commit is/isn't in the current branch
|
579
|
+
if @repo.runGit("merge-base #{fullhash} HEAD") == fullhash then
|
580
|
+
return true
|
581
|
+
end
|
582
|
+
|
583
|
+
# Grab the subject, since commit sha1 is different between branches we
|
584
|
+
# have to look it up based on subject.
|
585
|
+
subj=@repo.getCommitSubj(commit)
|
586
|
+
|
587
|
+
# Try and find if there's a commit with given subject the hard way
|
588
|
+
@repo.runGit("log --pretty=\"%H\" -F --grep \"#{subj.gsub("\"", '\\"')}\" "+
|
555
589
|
"#{@stable_base}..HEAD").split("\n").each(){|cmt|
|
556
590
|
cursubj=@repo.runGit("log -1 --format=\"%s\" #{cmt}")
|
557
591
|
if cursubj = subj then
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
592
|
+
return true
|
593
|
+
end
|
594
|
+
}
|
595
|
+
return false
|
562
596
|
end
|
563
597
|
|
564
598
|
def is_relevant?(commit)
|
565
|
-
|
566
|
-
|
599
|
+
# Let's grab the commit that this commit fixes (if exists (based on the "Fixes:" tag)).
|
600
|
+
fixescmt=@repo.runGit("log -1 #{commit} | grep -i \"fixes:\" | head -n 1 | "+
|
567
601
|
"sed -e 's/^[ \\t]*//' | cut -f 2 -d ':' | "+
|
568
602
|
"sed -e 's/^[ \\t]*//' -e 's/\\([0-9a-f]\\+\\)(/\\1 (/' | cut -f 1 -d ' '")
|
569
603
|
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
604
|
+
# If this commit fixes anything, but the broken commit isn't in our branch we don't
|
605
|
+
# need this commit either.
|
606
|
+
if fixescmt != "" then
|
607
|
+
if is_in_tree?(fixescmt, commit) then
|
608
|
+
return true
|
609
|
+
else
|
610
|
+
return false
|
611
|
+
end
|
578
612
|
end
|
579
613
|
|
580
|
-
|
581
|
-
|
582
|
-
|
614
|
+
if @repo.runGit("show #{commit} | grep -i 'stable@' | wc -l") == "0" then
|
615
|
+
return false
|
616
|
+
end
|
583
617
|
|
584
|
-
|
585
|
-
|
618
|
+
# Let's see if there's a version tag in this commit
|
619
|
+
full=@repo.runGit("show #{commit} | grep -i 'stable@'").gsub(/.* #?/, "")
|
586
620
|
|
587
|
-
|
621
|
+
# Sanity check our extraction
|
588
622
|
if full =~ /stable/ then
|
589
623
|
return false
|
590
624
|
end
|
591
625
|
|
592
626
|
full = @repo.runGit("rev-parse #{full}^{commit}")
|
593
627
|
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
628
|
+
# Make sure our branch contains this version
|
629
|
+
if @repo.runGit("merge-base #{@head} #{full}") == full then
|
630
|
+
return true
|
631
|
+
end
|
598
632
|
|
599
|
-
|
600
|
-
|
633
|
+
# Tag is not in history, ignore
|
634
|
+
return false
|
601
635
|
end
|
602
636
|
|
603
637
|
def pick_one(commit)
|
604
|
-
|
605
|
-
|
638
|
+
cpCmd="cherry-pick --strategy=recursive -Xpatience -x"
|
639
|
+
@repo.runGitInteractive("#{cpCmd} #{commit} &> /dev/null", :check_err => false)
|
640
|
+
return if $? == 0
|
641
|
+
|
606
642
|
if @repo.runGit("status -uno --porcelain | wc -l") == "0" then
|
607
|
-
|
643
|
+
@repo.runGit("reset --hard")
|
608
644
|
raise CherryPickErrorException.new("Failed to cherry pick commit #{commit}", commit)
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
645
|
+
end
|
646
|
+
@repo.runGit("reset --hard")
|
647
|
+
|
648
|
+
# That didn't work? Let's try that with every variation of the commit
|
649
|
+
# in other stable trees.
|
613
650
|
@repo.find_alts(commit).each(){|alt_commit|
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
651
|
+
@repo.runGitInteractive("#{cpCmd} #{alt_commit} &> /dev/null", :check_err => false)
|
652
|
+
if $? == 0 then
|
653
|
+
return
|
654
|
+
end
|
655
|
+
@repo.runGit("reset --hard")
|
619
656
|
}
|
620
|
-
|
621
|
-
|
622
|
-
|
657
|
+
|
658
|
+
# Still no? Let's go back to the original commit and hand it off to
|
659
|
+
# the user.
|
660
|
+
@repo.runGitInteractive("#{cpCmd} #{commit} &> /dev/null", :check_err => false)
|
623
661
|
raise CherryPickErrorException.new("Failed to cherry pick commit #{commit}", commit)
|
624
|
-
return false
|
625
662
|
end
|
626
663
|
|
627
664
|
def confirm_one(opts, commit)
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
665
|
+
rep=""
|
666
|
+
do_cp=false
|
667
|
+
puts @repo.getCommitHeadline(commit)
|
668
|
+
while rep != "y" do
|
669
|
+
puts "Do you want to steal this commit ? (y/n/b/?)"
|
633
670
|
case opts[:yn_default]
|
634
671
|
when :no
|
635
672
|
log(:INFO, "Auto-replying no due to --no option")
|
@@ -642,38 +679,38 @@ module GitMaintain
|
|
642
679
|
rep = STDIN.gets.chomp()
|
643
680
|
end
|
644
681
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
682
|
+
case rep
|
683
|
+
when "n"
|
684
|
+
log(:INFO, "Skip this commit")
|
685
|
+
break
|
686
|
+
when "b"
|
687
|
+
log(:INFO, "Blacklisting this commit for the current branch")
|
688
|
+
add_blacklist(commit)
|
689
|
+
break
|
690
|
+
when "y"
|
691
|
+
rep="y"
|
692
|
+
do_cp=true
|
693
|
+
break
|
694
|
+
when "?"
|
695
|
+
puts @repo.runGit("show #{commit}")
|
659
696
|
else
|
660
|
-
|
661
|
-
|
697
|
+
log(:ERROR, "Invalid answer $rep")
|
698
|
+
puts @repo.runGit("show --format=oneline --no-patch --no-decorate #{commit}")
|
662
699
|
end
|
663
|
-
|
700
|
+
end
|
664
701
|
return do_cp
|
665
702
|
end
|
666
703
|
|
667
704
|
def steal_one(opts, commit, mainline=false)
|
668
|
-
|
705
|
+
msg=''
|
669
706
|
orig_cmt=commit
|
670
707
|
|
671
708
|
if mainline == false then
|
672
|
-
|
709
|
+
subj=@repo.getCommitSubj(commit)
|
673
710
|
subj.gsub!(/"/, '\"')
|
674
|
-
|
675
|
-
|
676
|
-
|
711
|
+
# Let's grab the mainline commit id, this is useful if the version tag
|
712
|
+
# doesn't exist in the commit we're looking at but exists upstream.
|
713
|
+
orig_cmt=@repo.runGit("log --no-merges --format=\"%H\" -F --grep \"#{subj}\" " +
|
677
714
|
"#{@stable_base}..origin/master | tail -n1")
|
678
715
|
|
679
716
|
if orig_cmt == "" then
|
@@ -681,24 +718,24 @@ module GitMaintain
|
|
681
718
|
end
|
682
719
|
end
|
683
720
|
# If the commit doesn't apply for us, skip it
|
684
|
-
|
721
|
+
if is_relevant?(orig_cmt) != true
|
685
722
|
return true
|
686
|
-
|
723
|
+
end
|
687
724
|
|
688
725
|
log(:VERBOSE, "Found relevant commit #{@repo.getCommitHeadline(commit)}")
|
689
|
-
|
690
|
-
|
726
|
+
if is_in_tree?(orig_cmt) == true
|
727
|
+
# Commit is already in the stable branch, skip
|
691
728
|
log(:VERBOSE, "Commit is already in tree")
|
692
729
|
return true
|
693
|
-
|
730
|
+
end
|
694
731
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
732
|
+
# Check if it's not blacklisted by a git-notes
|
733
|
+
if is_blacklisted?(orig_cmt) == true then
|
734
|
+
# Commit is blacklisted
|
735
|
+
log(:INFO, "Skipping 'blacklisted' commit " +
|
736
|
+
@repo.getCommitHeadline(orig_cmt))
|
700
737
|
return true
|
701
|
-
|
738
|
+
end
|
702
739
|
|
703
740
|
do_cp = confirm_one(opts, orig_cmt)
|
704
741
|
return false if do_cp != true
|
@@ -706,39 +743,83 @@ module GitMaintain
|
|
706
743
|
prev_head=@repo.runGit("rev-parse HEAD")
|
707
744
|
|
708
745
|
begin
|
709
|
-
|
746
|
+
pick_one(commit)
|
710
747
|
rescue CherryPickErrorException => e
|
711
|
-
|
712
|
-
|
748
|
+
log(:WARNING, "Cherry pick failed. Fix, commit (or reset) and exit.")
|
749
|
+
@repo.runBash("PS1_WARNING='CP FIX'")
|
713
750
|
end
|
714
751
|
new_head=@repo.runGit("rev-parse HEAD")
|
715
752
|
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
753
|
+
# If we didn't find the commit upstream then this must be a custom commit
|
754
|
+
# in the given tree - make sure the user checks this commit.
|
755
|
+
if orig_cmt == "" then
|
756
|
+
msg="Custom"
|
757
|
+
orig_cmt=@repo.runGit("rev-parse HEAD")
|
758
|
+
log(:WARNING, "Custom commit, please double-check!")
|
759
|
+
@repo.runBash("PS1_WARNING='CHECK'")
|
760
|
+
end
|
724
761
|
if new_head != prev_head
|
725
|
-
|
762
|
+
make_pretty(orig_cmt, msg)
|
726
763
|
end
|
727
764
|
end
|
728
765
|
|
729
766
|
def steal_all(opts, range, mainline = false)
|
730
767
|
res = true
|
731
|
-
|
768
|
+
@repo.runGit("log --no-merges --format=\"%H\" #{range} | tac").split("\n").each(){|commit|
|
732
769
|
res &= steal_one(opts, commit, mainline)
|
733
770
|
}
|
734
771
|
return res
|
735
|
-
|
772
|
+
end
|
736
773
|
|
737
774
|
def same_sha?(ref1, ref2)
|
738
|
-
|
739
|
-
|
740
|
-
|
775
|
+
begin
|
776
|
+
c1=@repo.ref_exist?(ref1)
|
777
|
+
c2=@repo.ref_exist?(ref2)
|
778
|
+
return c1 == c2
|
779
|
+
rescue
|
780
|
+
return false
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
|
785
|
+
def release_do_add_commit(opts, filelist, commit_path, commit_msg=nil)
|
786
|
+
edit_flag = ""
|
787
|
+
edit_flag = "--edit" if opts[:no_edit] == false
|
788
|
+
|
789
|
+
raise("No commit message provided") if commit_path == nil && commit_msg == nil
|
790
|
+
commit_flag=""
|
791
|
+
if commit_msg != nil
|
792
|
+
commit_flag = "-m '#{commit_msg}'"
|
793
|
+
else
|
794
|
+
commit_flag = "-F '#{commit_path}'"
|
795
|
+
end
|
741
796
|
|
797
|
+
# Add and commit
|
798
|
+
begin
|
799
|
+
@repo.runGit("add " + filelist.join(" "))
|
800
|
+
@repo.runGitInteractive("commit #{commit_flag} --verbose #{edit_flag} --signoff")
|
801
|
+
rescue RuntimeError
|
802
|
+
raise("Failed to commit on branch #{@local_branch}")
|
803
|
+
end
|
804
|
+
return 0
|
742
805
|
end
|
806
|
+
|
807
|
+
def release_do_tag(opts, version, tag_path)
|
808
|
+
edit_flag = ""
|
809
|
+
edit_flag = "--edit" if opts[:no_edit] == false
|
810
|
+
begin
|
811
|
+
@repo.runGitInteractive("tag -a -s #{version} #{edit_flag} -F #{tag_path}")
|
812
|
+
rescue RuntimeError
|
813
|
+
raise("Failed to tag branch #{@local_branch}")
|
814
|
+
end
|
815
|
+
return 0
|
816
|
+
end
|
817
|
+
|
818
|
+
def release_do_add_commit_tag(opts, filelist, version, message_path)
|
819
|
+
release_do_add_commit(opts, filelist, message_path)
|
820
|
+
release_do_tag(opts, version, message_path)
|
821
|
+
return 0
|
822
|
+
end
|
823
|
+
|
743
824
|
end
|
744
825
|
end
|