git-maintain 0.7.0 → 0.8.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.
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