git-maintain 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -16,9 +16,9 @@ The idea is to script most of the maintenance tasks so the maintainer can focus
16
16
  - **list_stable**: List commit present in the stable branch but not in the latest associated relase
17
17
  - **merge**: Merge branch with suffix specified in -m <suff> into the main branch
18
18
  - **push**: Push branches to github for validation
19
- - **monitor**: Check the travis state of all branches
19
+ - **monitor**: Check the CI state of all branches
20
20
  - **push_stable**: Push to stable repo
21
- - **monitor_stable**: Check the travis state of all stable branches
21
+ - **monitor_stable**: Check the CI state of all stable branches
22
22
  - **release**: Create new release on all concerned branches
23
23
  - **reset**: Reset branch against upstream
24
24
  - **submit_release**: Push the to stable and create the release packages
@@ -157,7 +157,7 @@ Apply them to the appropriate branches
157
157
 
158
158
  ```git maintain cp -s deadbeef --version '1[789]'```
159
159
 
160
- And push them to my own github repo so that Travis will check everything out
160
+ And push them to my own github repo so that CI will check everything out
161
161
 
162
162
  ```git maintain push --version '1[789]'```
163
163
 
@@ -179,7 +179,7 @@ Push it to my own github too.
179
179
 
180
180
  ```git maintain push --version '1[789]' -b pending```
181
181
 
182
- Once this gets accepted (and Travis is OK too), I merge this branch back to my 'master'
182
+ Once this gets accepted (and CI is OK too), I merge this branch back to my 'master'
183
183
 
184
184
  ```git maintain merge --version '1[789]' -m pending```
185
185
 
@@ -239,7 +239,7 @@ The tag will not have been propagated anywhere else and can be deleted manually.
239
239
 
240
240
  ```git maintain push_stable --version '1[789]'```
241
241
 
242
- You can then monitor the status on Travis
242
+ You can then monitor the status on CI
243
243
 
244
244
  ```git maintain monitor_stable --version '1[789]'```
245
245
 
@@ -258,6 +258,8 @@ Enjoy, and feel free to report bugs, missing features and/or send patches
258
258
 
259
259
  This is a summary of all the settings that can be set in the git config:
260
260
 
261
+ - `maintain.valid-repo`: Remote github repo to test out branches before submitting. Default = `github`
262
+ - `maintain.stable-repo`: Remote stable github repository t submit validated branches and new releases. Default = `stable`
261
263
  - `maintain.autofetch`: Enable/Disable auto fetching.
262
264
  Can be overriden by the --[no-]fetch option on the CLI.
263
265
  If unset, autofetch is enabled
@@ -274,3 +276,22 @@ This is a summary of all the settings that can be set in the git config:
274
276
  - `maintain.mail-format`: Specify how release annoucement emails are sent. Can be:
275
277
  - `imap_send`: Store prepared email in an IMAP folder. See `main git-imap-send` for more infos. This is the default value.
276
278
  - `send_email`: Generates a file which is compatible with git send-email
279
+
280
+ # License
281
+
282
+ Unless otherwise stated, everything in this repo is covered by the following
283
+ copyright notice:
284
+
285
+ Copyright (c) 2018 SUSE
286
+
287
+ This program is free software: you can redistribute it and/or modify it
288
+ under the terms of the GNU General Public License version 3, as
289
+ published by the Free Software Foundation.
290
+
291
+ This program is distributed in the hope that it will be useful,
292
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
293
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
294
+ GNU General Public License for more details.
295
+
296
+ You should have received a copy of the GNU General Public License
297
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -1,6 +1,7 @@
1
1
  module GitMaintain
2
2
  class RDMACoreBranch < Branch
3
3
  REPO_NAME = "rdma-core"
4
+ AZURE_MIN_VERSION = 25
4
5
 
5
6
  def self.set_opts(action, optsParser, opts)
6
7
  opts[:rel_type] = nil
@@ -73,7 +74,7 @@ module GitMaintain
73
74
  end
74
75
 
75
76
  # Update version number in relevant files
76
- @repo.run("sed -i -e 's/\\(Version:[[:space:]]*\\)[0-9.]\\+/\\1#{new_ver}/g' redhat/rdma-core.spec suse/rdma-core.spec")
77
+ @repo.run("sed -i -e 's/\\(Version:[[:space:]]*\\)[0-9.]\\+/\\1#{new_ver}/g' */*.spec")
77
78
  @repo.run("sed -i -e 's/\\([sS][eE][tT](PACKAGE_VERSION[[:space:]]*\"\\)[0-9.]*\"/\\1#{new_ver}\"/g' CMakeLists.txt")
78
79
 
79
80
  case opts[:rel_type]
@@ -93,7 +94,7 @@ mv debian/changelog.new debian/changelog")
93
94
  end
94
95
 
95
96
  # Add and commit
96
- @repo.runGit("add redhat/rdma-core.spec suse/rdma-core.spec CMakeLists.txt debian/changelog")
97
+ @repo.runGit("add */*.spec CMakeLists.txt debian/changelog")
97
98
  @repo.runGitInteractive("commit -m '#{commit_msg} #{new_ver}' --verbose --edit --signoff")
98
99
  if $? != 0 then
99
100
  raise("Failed to commit on branch #{local_branch}")
@@ -108,7 +109,57 @@ mv debian/changelog.new debian/changelog")
108
109
  `rm -f #{tag_path}`
109
110
  end
110
111
  end
112
+ class RDMACoreRepo < Repo
113
+ AZURE_MIN_VERSION = 25
114
+ def submitReleases(opts, new_tags)
115
+ new_tags.each(){|tag|
116
+ next if tag !~ /v([0-9]*)\.[0-9]*/
117
+ major=$1.to_i
118
+ # Starting from v27, do not create the github release ourself as this is done by Azure
119
+ createRelease(opts, tag, major < AZURE_MIN_VERSION)
120
+ }
121
+ end
122
+ end
123
+
124
+ class RDMACoreCI < CI
125
+ AZURE_MIN_VERSION = 25
126
+ def initialize(repo)
127
+ super(repo)
128
+ @travis = GitMaintain::TravisCI.new(repo)
129
+ @azure = GitMaintain::AzureCI.new(repo, 'ucfconsort', 'ucfconsort')
130
+
131
+ # Auto generate all CI required methods
132
+ # Wicked ruby tricker to find all the public methods of CI but not of inherited classes
133
+ # to dynamically define these method in the object being created
134
+ (GitMaintain::CI.new(repo).public_methods() - Object.new.public_methods()).each(){|method|
135
+ # Skip specific emptyCache method
136
+ next if method == :emptyCache
111
137
 
138
+ self.define_singleton_method(method) { |br, *args|
139
+ if br.version =~ /([0-9]+)/
140
+ major=$1.to_i
141
+ elsif br.version == "master"
142
+ major=99999
143
+ else
144
+ raise("Unable to monitor branch #{br} on a CI")
145
+ end
146
+ if major < AZURE_MIN_VERSION
147
+ @travis.send(method, br, *args)
148
+ else
149
+ @azure.send(method, br, *args)
150
+ end
151
+ }
152
+ }
153
+ end
154
+ def emptyCache()
155
+ @travis.emptyCache()
156
+ @azure.emptyCache()
157
+ end
158
+ end
112
159
  GitMaintain::registerCustom(RDMACoreBranch::REPO_NAME,
113
- { GitMaintain::Branch => RDMACoreBranch })
160
+ {
161
+ GitMaintain::Branch => RDMACoreBranch,
162
+ GitMaintain::Repo => RDMACoreRepo,
163
+ GitMaintain::CI => RDMACoreCI,
164
+ })
114
165
  end
@@ -33,34 +33,35 @@ module GitMaintain
33
33
  "* list_stable: List commit present in the stable branch but not in the latest associated relase",
34
34
  "* merge: Merge branch with suffix specified in -m <suff> into the main branch",
35
35
  "* push: Push branches to github for validation",
36
- "* monitor: Check the travis state of all branches",
36
+ "* monitor: Check the CI state of all branches",
37
37
  "* push_stable: Push to stable repo",
38
- "* monitor_stable: Check the travis state of all stable branches",
38
+ "* monitor_stable: Check the CI state of all stable branches",
39
39
  "* release: Create new release on all concerned branches",
40
40
  "* reset: Reset branch against upstream",
41
41
  ]
42
42
 
43
- def self.load(repo, version, travis, branch_suff)
43
+ def self.load(repo, version, ci, branch_suff)
44
44
  repo_name = File.basename(repo.path)
45
- return GitMaintain::loadClass(Branch, repo_name, repo, version, travis, branch_suff)
45
+ return GitMaintain::loadClass(Branch, repo_name, repo, version, ci, branch_suff)
46
46
  end
47
47
 
48
48
  def self.set_opts(action, optsParser, opts)
49
49
  opts[:base_ver] = 0
50
- opts[:version] = /.*/
50
+ opts[:version] = []
51
51
  opts[:commits] = []
52
52
  opts[:do_merge] = false
53
53
  opts[:push_force] = false
54
- opts[:no_travis] = false
54
+ opts[:no_ci] = false
55
55
  opts[:all] = false
56
56
  opts[:check_only] = false
57
57
  opts[:fetch] = nil
58
58
  opts[:watch] = false
59
+ opts[:delete_remote] = false
59
60
 
60
61
  optsParser.on("-v", "--base-version [MIN_VER]", Integer, "Older release to consider.") {
61
62
  |val| opts[:base_ver] = val}
62
63
  optsParser.on("-V", "--version [regexp]", Regexp, "Regexp to filter versions.") {
63
- |val| opts[:version] = val}
64
+ |val| opts[:version] << val}
64
65
 
65
66
  if ALL_BRANCHES_ACTIONS.index(action) == nil &&
66
67
  action != :merge &&
@@ -79,13 +80,16 @@ module GitMaintain
79
80
  optsParser.banner += "-c <sha1> [-c <sha1> ...]"
80
81
  optsParser.on("-c", "--sha1 [SHA1]", String, "Commit to cherry-pick. Can be used multiple time.") {
81
82
  |val| opts[:commits] << val}
83
+ when :delete
84
+ optsParser.on("--remote", "Delete the remote staging branch instead of the local ones.") {
85
+ |val| opts[:delete_remote] = true}
82
86
  when :merge
83
87
  optsParser.banner += "-m <suffix>"
84
88
  optsParser.on("-m", "--merge [SUFFIX]", "Merge branch with suffix.") {
85
89
  |val| opts[:do_merge] = val}
86
90
  when :monitor, :monitor_stable
87
91
  optsParser.on("-w", "--watch <PERIOD>", Integer,
88
- "Watch and refresh travis status every <PERIOD>.") {
92
+ "Watch and refresh CI status every <PERIOD>.") {
89
93
  |val| opts[:watch] = val}
90
94
  when :push
91
95
  optsParser.banner += "[-f]"
@@ -93,8 +97,8 @@ module GitMaintain
93
97
  |val| opts[:push_force] = val}
94
98
  when :push_stable
95
99
  optsParser.banner += "[-T]"
96
- optsParser.on("-T", "--no-travis", "Ignore Travis build status and push anyway.") {
97
- |val| opts[:no_travis] = true}
100
+ optsParser.on("-T", "--no-ci", "Ignore CI build status and push anyway.") {
101
+ |val| opts[:no_ci] = true}
98
102
  optsParser.on("-c", "--check", "Check if there is something to be pushed.") {
99
103
  |val| opts[:check_only] = true}
100
104
  when :steal
@@ -112,18 +116,19 @@ module GitMaintain
112
116
  raise "Action #{opts[:action]} can only be done on 'master' suffixed branches"
113
117
  end
114
118
  end
115
- if opts[:action] == :delete then
119
+ if opts[:action] == :delete && opts[:delete_remote] != true then
116
120
  if opts[:br_suff] == "master" then
117
121
  raise "Action #{opts[:action]} can NOT be done on 'master' suffixed branches"
118
122
  end
119
123
  end
124
+ opts[:version] = [ /.*/ ] if opts[:version].length == 0
120
125
  end
121
126
 
122
127
  def self.execAction(opts, action)
123
128
  repo = Repo::load()
124
- travis = TravisChecker::load(repo)
129
+ ci = CI::load(repo)
125
130
  opts[:repo] = repo
126
- opts[:travis] = travis
131
+ opts[:ci] = ci
127
132
  brClass = GitMaintain::getClass(self, repo.name)
128
133
 
129
134
  if NO_FETCH_ACTIONS.index(action) == nil && opts[:fetch] != false then
@@ -140,7 +145,7 @@ module GitMaintain
140
145
  unfilteredList = repo.getBranchList(opts[:br_suff])
141
146
  end
142
147
  branchList = unfilteredList.map(){|br|
143
- branch = Branch::load(repo, br, travis, opts[:br_suff])
148
+ branch = Branch::load(repo, br, ci, opts[:br_suff])
144
149
  case branch.is_targetted?(opts)
145
150
  when :too_old
146
151
  GitMaintain::log(:VERBOSE, "Skipping older v#{branch.version}")
@@ -153,7 +158,7 @@ module GitMaintain
153
158
  branch
154
159
  }.compact()
155
160
  else
156
- branchList = [ Branch::load(repo, opts[:manual_branch], travis, opts[:br_suff]) ]
161
+ branchList = [ Branch::load(repo, opts[:manual_branch], ci, opts[:br_suff]) ]
157
162
  end
158
163
 
159
164
  loop do
@@ -178,15 +183,15 @@ module GitMaintain
178
183
 
179
184
  break if opts[:watch] == false
180
185
  sleep(opts[:watch])
181
- travis.emptyCache()
186
+ ci.emptyCache()
182
187
  end
183
188
  end
184
189
 
185
- def initialize(repo, version, travis, branch_suff)
190
+ def initialize(repo, version, ci, branch_suff)
186
191
  GitMaintain::checkDirectConstructor(self.class)
187
192
 
188
193
  @repo = repo
189
- @travis = travis
194
+ @ci = ci
190
195
  @version = version
191
196
  @branch_suff = branch_suff
192
197
 
@@ -223,10 +228,10 @@ module GitMaintain
223
228
  if @version.to_i < opts[:base_ver] then
224
229
  return :too_old
225
230
  end
226
- if @version !~ opts[:version] then
227
- return :no_match
228
- end
229
- return true
231
+ opts[:version].each() {|regexp|
232
+ return true if @version =~ regexp
233
+ }
234
+ return :no_match
230
235
  end
231
236
 
232
237
  # Checkout the repo to the given branch
@@ -271,7 +276,7 @@ module GitMaintain
271
276
  end
272
277
 
273
278
  master_sha=@repo.runGit("rev-parse origin/master")
274
- res = steal_all(opts, "#{base_ref}..#{master_sha}")
279
+ res = steal_all(opts, "#{base_ref}..#{master_sha}", true)
275
280
 
276
281
  # If we picked all the commits (or nothing happened)
277
282
  # Mark the current master as the last checked point so we
@@ -345,22 +350,22 @@ module GitMaintain
345
350
  "#{opts[:repo].valid_repo} #{branches.join(" ")}")
346
351
  end
347
352
 
348
- # Monitor the build status on Travis
353
+ # Monitor the build status on CI
349
354
  def monitor(opts)
350
- st = @travis.getValidState(head)
355
+ st = @ci.getValidState(self, @head)
351
356
  suff=""
352
357
  case st
353
358
  when "started"
354
- suff= " started at #{@travis.getValidTS(head)}"
359
+ suff= " started at #{@ci.getValidTS(self, @head)}"
355
360
  end
356
361
  log(:INFO, "Status for v#{@version}: " + st + suff)
357
- if (st == "failed" || st == "errored") && opts[:watch] == false
362
+ if @ci.isErrored(self, st) && opts[:watch] == false
358
363
  rep = "y"
359
364
  suff=""
360
365
  while rep == "y"
361
366
  rep = GitMaintain::confirm(opts, "see the build log#{suff}")
362
367
  if rep == "y" then
363
- log = @travis.getValidLog(head)
368
+ log = @ci.getValidLog(self, @head)
364
369
  tmp = `mktemp`.chomp()
365
370
  tmpfile = File.open(tmp, "w+")
366
371
  tmpfile.puts(log)
@@ -375,9 +380,9 @@ module GitMaintain
375
380
 
376
381
  # Push branch to the stable repo
377
382
  def push_stable(opts)
378
- if (opts[:no_travis] != true && @NO_TRAVIS != true) &&
379
- @travis.checkValidState(@head) != true then
380
- log(:WARNING, "Build is not passed on travis. Skipping push to stable")
383
+ if (opts[:no_ci] != true && @NO_CI != true) &&
384
+ @ci.checkValidState(self, @head) != true then
385
+ log(:WARNING, "Build is not passed on CI. Skipping push to stable")
381
386
  return
382
387
  end
383
388
 
@@ -408,13 +413,13 @@ module GitMaintain
408
413
  return if branches.length == 0
409
414
  opts[:repo].runGit("push #{opts[:repo].stable_repo} #{branches.join(" ")}")
410
415
  end
411
- # Monitor the build status of the stable branch on Travis
416
+ # Monitor the build status of the stable branch on CI
412
417
  def monitor_stable(opts)
413
- st = @travis.getStableState(@stable_head)
418
+ st = @ci.getStableState(self, @stable_head)
414
419
  suff=""
415
420
  case st
416
421
  when "started"
417
- suff= " started at #{@travis.getStableTS(@stable_head)}"
422
+ suff= " started at #{@ci.getStableTS(self, @stable_head)}"
418
423
  end
419
424
  log(:INFO, "Status for v#{@version}: " + st + suff)
420
425
  end
@@ -446,14 +451,36 @@ module GitMaintain
446
451
  end
447
452
 
448
453
  def delete(opts)
449
- rep = GitMaintain::confirm(opts, "delete branch #{@local_branch}")
454
+ if opts[:delete_remote] == true then
455
+ msg = "delete remote branch #{@repo.valid_repo}/#{@local_branch}"
456
+ else
457
+ msg = "delete branch #{@local_branch}"
458
+ end
459
+ rep = GitMaintain::confirm(opts, msg)
450
460
  if rep == "y" then
451
- @repo.runGit("branch -D #{@local_branch}")
461
+ return @local_branch
452
462
  else
453
463
  log(:INFO, "Skipping deletion")
454
464
  return
455
465
  end
456
466
  end
467
+ def self.delete_epilogue(opts, branches)
468
+ # Compact to remove empty entries
469
+ branches.compact!()
470
+
471
+ return if branches.length == 0
472
+ puts "Deleting #{opts[:delete_remote] == true ? "remote" : "local"} branches: #{branches.join(" ")}"
473
+ rep = GitMaintain::confirm(opts, "continue")
474
+ if rep != "y" then
475
+ log(:INFO, "Cancelling")
476
+ return
477
+ end
478
+ if opts[:delete_remote] == true then
479
+ opts[:repo].runGit("push #{opts[:repo].valid_repo} #{branches.map(){|x| ":" + x}.join(" ")}")
480
+ else
481
+ opts[:repo].runGit("branch -D #{branches.join(" ")}")
482
+ end
483
+ end
457
484
 
458
485
  private
459
486
  def add_blacklist(commit)
@@ -532,13 +559,15 @@ module GitMaintain
532
559
  end
533
560
 
534
561
  # Let's see if there's a version tag in this commit
535
- full=@repo.runGit("show #{commit} | grep -i 'stable@'").gsub(/.* /, "")
562
+ full=@repo.runGit("show #{commit} | grep -i 'stable@'").gsub(/.* #?/, "")
536
563
 
537
564
  # Sanity check our extraction
538
565
  if full =~ /stable/ then
539
566
  return false
540
567
  end
541
568
 
569
+ full = @repo.runGit("rev-parse #{full}^{commit}")
570
+
542
571
  # Make sure our branch contains this version
543
572
  if @repo.runGit("merge-base #{@head} #{full}") == full then
544
573
  return true
@@ -607,17 +636,23 @@ module GitMaintain
607
636
  return do_cp
608
637
  end
609
638
 
610
- def steal_one(opts, commit)
611
- subj=@repo.getCommitSubj(commit)
612
- subj.gsub!(/"/, '\"')
639
+ def steal_one(opts, commit, mainline=false)
613
640
  msg=''
614
-
615
- # Let's grab the mainline commit id, this is useful if the version tag
616
- # doesn't exist in the commit we're looking at but exists upstream.
617
- orig_cmt=@repo.runGit("log --no-merges --format=\"%H\" -F --grep \"#{subj}\" " +
618
- "#{@stable_base}..origin/master | tail -n1")
619
-
620
- # If the commit doesn't apply for us, skip it
641
+ orig_cmt=commit
642
+
643
+ if mainline == false then
644
+ subj=@repo.getCommitSubj(commit)
645
+ subj.gsub!(/"/, '\"')
646
+ # Let's grab the mainline commit id, this is useful if the version tag
647
+ # doesn't exist in the commit we're looking at but exists upstream.
648
+ orig_cmt=@repo.runGit("log --no-merges --format=\"%H\" -F --grep \"#{subj}\" " +
649
+ "#{@stable_base}..origin/master | tail -n1")
650
+
651
+ if orig_cmt == "" then
652
+ log(:WARNING, "Could not find commit #{commit} in mainline")
653
+ end
654
+ end
655
+ # If the commit doesn't apply for us, skip it
621
656
  if is_relevant?(orig_cmt) != true
622
657
  return true
623
658
  end
@@ -663,10 +698,10 @@ module GitMaintain
663
698
  end
664
699
  end
665
700
 
666
- def steal_all(opts, range)
701
+ def steal_all(opts, range, mainline = false)
667
702
  res = true
668
703
  @repo.runGit("log --no-merges --format=\"%H\" #{range} | tac").split("\n").each(){|commit|
669
- res &= steal_one(opts, commit)
704
+ res &= steal_one(opts, commit, mainline)
670
705
  }
671
706
  return res
672
707
  end