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.
data/lib/common.rb CHANGED
@@ -57,6 +57,7 @@ module GitMaintain
57
57
 
58
58
  def registerCustom(repo_name, classes)
59
59
  raise("Multiple class for repo #{repo_name}") if @@custom_classes[repo_name] != nil
60
+ classes[:name] = repo_name if classes[:name] == nil
60
61
  @@custom_classes[repo_name] = classes
61
62
  end
62
63
  module_function :registerCustom
@@ -73,6 +74,11 @@ module GitMaintain
73
74
  end
74
75
  module_function :getClass
75
76
 
77
+ def getCustomClasses()
78
+ return @@custom_classes
79
+ end
80
+ module_function :getCustomClasses
81
+
76
82
  def loadClass(default_class, repo_name, *more)
77
83
  @@load_class.push(default_class)
78
84
  obj = GitMaintain::getClass(default_class, repo_name).new(*more)
@@ -95,49 +101,64 @@ module GitMaintain
95
101
 
96
102
  def getActionAttr(attr)
97
103
  if Common.const_get(attr).class == Hash
98
- return ACTION_CLASS.inject({}){|h, x| h.merge(x.const_get(attr))}
104
+ return ACTION_CLASS.inject({}){|h, x| h.merge(getClass(x).const_get(attr))}
99
105
  else
100
- return ACTION_CLASS.map(){|x| x.const_get(attr)}.flatten()
106
+ return ACTION_CLASS.map(){|x| getClass(x).const_get(attr)}.flatten()
101
107
  end
102
108
  end
103
109
  module_function :getActionAttr
104
110
 
105
111
  def setOpts(action, optsParser, opts)
106
112
  ACTION_CLASS.each(){|x|
107
- next if x::ACTION_LIST.index(action) == nil
108
- if x.singleton_methods().index(:set_opts) != nil then
113
+ if x::ACTION_LIST.index(action) != nil &&
114
+ x.singleton_methods().index(:set_opts) != nil then
115
+ matched=true
109
116
  x.set_opts(action, optsParser, opts)
110
117
  end
111
118
  # Try to add repo specific opts
112
119
  y = getClass(x)
113
- if x != y && y.singleton_methods().index(:set_opts) != nil then
120
+ if x != y && y::ACTION_LIST.index(action) != nil &&
121
+ y.singleton_methods().index(:set_opts) != nil then
122
+ matched=true
123
+ x.set_opts(action, optsParser, opts) if x.singleton_methods().index(:set_opts) != nil
114
124
  y.set_opts(action, optsParser, opts)
115
125
  end
116
- break
126
+ break if matched == true
117
127
  }
118
128
  end
119
129
  module_function :setOpts
120
130
 
121
131
  def checkOpts(opts)
122
132
  ACTION_CLASS.each(){|x|
123
- next if x::ACTION_LIST.index(opts[:action]) == nil
124
- next if x.singleton_methods().index(:check_opts) == nil
125
- x.check_opts(opts)
133
+ if x::ACTION_LIST.index(opts[:action]) != nil &&
134
+ x.singleton_methods().index(:check_opts) != nil then
135
+ matched=true
136
+ x.check_opts(opts)
137
+ end
126
138
 
127
139
  # Try to add repo specific opts
128
140
  y = getClass(x)
129
- if x != y && y.singleton_methods().index(:check_opts) != nil then
141
+ if x != y && y::ACTION_LIST.index(opts[:action]) != nil &&
142
+ y.singleton_methods().index(:check_opts) != nil then
143
+ matched=true
144
+ x.check_opts(opts) if x.singleton_methods().index(:check_opts) != nil
130
145
  y.check_opts(opts)
131
146
  end
132
- }
147
+ break if matched == true
148
+ }
133
149
  end
134
150
  module_function :checkOpts
135
151
 
136
152
  def execAction(opts, action)
137
153
  ACTION_CLASS.each(){|x|
138
- next if x::ACTION_LIST.index(action) == nil
139
- x.execAction(opts, action)
140
- break
154
+ if x::ACTION_LIST.index(action) != nil
155
+ return x.execAction(opts, action)
156
+ end
157
+ # Try to add repo specific opts
158
+ y = getClass(x)
159
+ if x != y && y::ACTION_LIST.index(opts[:action]) != nil then
160
+ return y.execAction(opts, action)
161
+ end
141
162
  }
142
163
  end
143
164
  module_function :execAction
@@ -202,6 +223,12 @@ module GitMaintain
202
223
  end
203
224
  module_function :log
204
225
 
226
+ def crit(msg)
227
+ log(:ERROR, msg)
228
+ raise msg
229
+ end
230
+ module_function :crit
231
+
205
232
  def setVerbose(val)
206
233
  @@verbose_log = val
207
234
  end
@@ -217,3 +244,16 @@ Dir.entries(BACKPORT_LIB_DIR + "/addons/").each(){|entry|
217
244
  require entry.sub(/.rb$/, "")
218
245
  }
219
246
  $LOAD_PATH.pop()
247
+
248
+ if ENV["GIT_MAINTAIN_ADDON_DIR"].to_s() != "" then
249
+ ADDON_DIR=ENV["GIT_MAINTAIN_ADDON_DIR"].to_s()
250
+ if Dir.exist?(ADDON_DIR) then
251
+ $LOAD_PATH.push(ADDON_DIR)
252
+ Dir.entries(ADDON_DIR).each(){|entry|
253
+ next if (!File.file?(ADDON_DIR + "/" + entry) || entry !~ /\.rb$/ );
254
+ require entry.sub(/.rb$/, "")
255
+ }
256
+ $LOAD_PATH.pop()
257
+ end
258
+ end
259
+
data/lib/repo.rb CHANGED
@@ -2,6 +2,11 @@ require 'octokit'
2
2
  require 'io/console'
3
3
 
4
4
  module GitMaintain
5
+ class NoRefError < RuntimeError
6
+ def initialize(ref)
7
+ super("Reference '#{ref}' was not found")
8
+ end
9
+ end
5
10
  class Repo
6
11
  @@VALID_REPO = "github"
7
12
  @@STABLE_REPO = "stable"
@@ -19,7 +24,7 @@ module GitMaintain
19
24
  }
20
25
 
21
26
  def self.load(path=".")
22
- dir = Dir.pwd()
27
+ dir = File.realdirpath(path)
23
28
  repo_name = File.basename(dir)
24
29
  return GitMaintain::loadClass(Repo, repo_name, dir)
25
30
  end
@@ -60,9 +65,9 @@ module GitMaintain
60
65
  @stable_repo = getGitConfig("maintain.stable-repo")
61
66
  @stable_repo = @@STABLE_REPO if @stable_repo == ""
62
67
 
63
- @remote_valid=runGit("remote -v | egrep '^#{@valid_repo}' | grep fetch |
68
+ @remote_valid=runGit("remote -v | grep -E '^#{@valid_repo}' | grep fetch |
64
69
  awk '{ print $2}' | sed -e 's/.*://' -e 's/\\.git//'")
65
- @remote_stable=runGit("remote -v | egrep '^#{@stable_repo}' | grep fetch |
70
+ @remote_stable=runGit("remote -v | grep -E '^#{@stable_repo}' | grep fetch |
66
71
  awk '{ print $2}' | sed -e 's/.*://' -e 's/\\.git//'")
67
72
 
68
73
  @auto_fetch = getGitConfig("maintain.autofetch")
@@ -83,7 +88,7 @@ module GitMaintain
83
88
  @stable_base_format = getGitConfig("maintain.stable-base-format")
84
89
 
85
90
  @stable_base_patterns=
86
- runGit("config --get-regexp stable-base | egrep '^stable-base\.' | "+
91
+ runGit("config --get-regexp stable-base | grep -E '^stable-base\.' | "+
87
92
  "sed -e 's/stable-base\.//' -e 's/---/\\//g'").split("\n").inject({}){ |m, x|
88
93
  y=x.split(" ");
89
94
  m[y[0]] = y[1]
@@ -110,22 +115,41 @@ module GitMaintain
110
115
  GitMaintain::log(lvl, str)
111
116
  end
112
117
 
113
- def run(cmd)
114
- return `cd #{@path} && #{cmd}`
118
+ def _run_check_ret(ret, opts)
119
+ raise(RuntimeError.new(ret)) if $?.exitstatus != 0 && opts.fetch(:check_err, true) == true
115
120
  end
116
- def runSystem(cmd)
117
- return system("cd #{@path} && #{cmd}")
121
+ def run(cmd, opts = {})
122
+ ret = `cd #{@path} && #{cmd}`
123
+ _run_check_ret(ret, opts)
124
+ return ret
118
125
  end
126
+ def runSystem(cmd, opts = {})
127
+ ret = system("cd #{@path} && #{cmd}")
128
+ _run_check_ret(nil, opts)
129
+ return ret
119
130
 
120
- def runGit(cmd)
131
+ end
132
+ def runGit(cmd, opts = {})
121
133
  log(:DEBUG, "Called from #{caller[1]}")
122
134
  log(:DEBUG, "Running git command '#{cmd}'")
123
- return `git --work-tree=#{@path} #{cmd}`.chomp()
135
+ ret = `git --work-tree=#{@path} #{cmd}`.chomp()
136
+ _run_check_ret(ret, opts)
137
+ return ret
124
138
  end
125
- def runGitInteractive(cmd)
139
+ def runGitInteractive(cmd, opts = {})
126
140
  log(:DEBUG, "Called from #{caller[1]}")
127
141
  log(:DEBUG, "Running interactive git command '#{cmd}'")
128
- return system("git --work-tree=#{@path} #{cmd}")
142
+ ret = system("git --work-tree=#{@path} #{cmd}")
143
+ _run_check_ret(nil, opts)
144
+ return ret
145
+
146
+ end
147
+ def ref_exist?(ref)
148
+ begin
149
+ return runGit("rev-parse --verify --quiet '#{ref}'")
150
+ rescue RuntimeError
151
+ raise(NoRefError.new(ref))
152
+ end
129
153
  end
130
154
 
131
155
  def runGitImap(cmd)
@@ -138,17 +162,18 @@ module GitMaintain
138
162
  fi; git --work-tree=#{@path} imap-send #{cmd}`
139
163
  end
140
164
  def getGitConfig(entry)
141
- return @config_cache[entry] ||= runGit("config #{entry} 2> /dev/null").chomp()
165
+ return @config_cache[entry] ||= runGit("config #{entry} 2> /dev/null", :check_err => false).chomp()
142
166
  end
143
167
 
144
- def runBash()
145
- runSystem("bash")
146
- if $? == 0 then
147
- log(:INFO, "Continuing...")
148
- else
168
+ def runBash(env="")
169
+ begin
170
+ runSystem(env + " bash")
171
+ rescue RuntimeError
149
172
  log(:ERROR, "Shell exited with code #{$?}. Exiting")
150
173
  raise("Cancelled by user")
151
174
  end
175
+ log(:INFO, "Continuing...")
176
+
152
177
  end
153
178
 
154
179
  def getCommitHeadline(sha)
@@ -200,10 +225,10 @@ module GitMaintain
200
225
 
201
226
  def getUnreleasedTags(opts)
202
227
  remote_tags=runGit("ls-remote --tags #{@stable_repo} |
203
- egrep 'refs/tags/v[0-9.]*$'").split("\n").map(){
228
+ grep -E 'refs/tags/v[0-9.]*$'").split("\n").map(){
204
229
  |x| x.gsub(/.*refs\/tags\//, '')
205
230
  }
206
- local_tags =runGit("tag -l | egrep '^v[0-9.]*$'").split("\n")
231
+ local_tags =runGit("tag -l | grep -E '^v[0-9.]*$'").split("\n")
207
232
 
208
233
  new_tags = local_tags - remote_tags
209
234
  return new_tags
@@ -264,22 +289,22 @@ module GitMaintain
264
289
 
265
290
  def createRelease(opts, tag, github_rel=true)
266
291
  log(:INFO, "Creating a release for #{tag}")
267
- runGit("push #{@stable_repo} refs/tags/#{tag}")
292
+ runGit("push #{@stable_repo} refs/tags/#{tag}")
268
293
 
269
294
  if github_rel == true then
270
- msg = runGit("tag -l -n1000 '#{tag}'") + "\n"
295
+ msg = runGit("tag -l -n1000 '#{tag}'") + "\n"
271
296
 
272
- # Ye ghods is is a horrific format to parse
273
- name, body = msg.split("\n", 2)
274
- name = name.gsub(/^#{tag}/, '').strip
275
- body = body.split("\n").map { |l| l.sub(/^ /, '') }.join("\n")
276
- api.create_release(@remote_stable, tag, :name => name, :body => body)
297
+ # Ye ghods is is a horrific format to parse
298
+ name, body = msg.split("\n", 2)
299
+ name = name.gsub(/^#{tag}/, '').strip
300
+ body = body.split("\n").map { |l| l.sub(/^ /, '') }.join("\n")
301
+ api.create_release(@remote_stable, tag, :name => name, :body => body)
277
302
  end
278
- end
303
+ end
279
304
 
280
305
  def versionToLocalBranch(version, suff)
281
306
  return @branch_format_raw.gsub(/\\\//, '/').
282
- gsub(/\(.*\)/, version) + "/#{suff}"
307
+ gsub(/\(.*\)/, version) + "/#{suff}"
283
308
  end
284
309
 
285
310
  def versionToStableBranch(version)
@@ -333,56 +358,65 @@ module GitMaintain
333
358
  submitReleases(opts, new_tags)
334
359
  end
335
360
  def summary(opts)
336
- log(:INFO, "Configuration summary:")
337
- log(:INFO, "Stable remote: #{@stable_repo}")
338
- log(:INFO, "Validation remote: #{@valid_repo}")
339
- log(:INFO, "")
340
- log(:INFO, "Branch config:")
341
- log(:INFO, "Local branch format: /#{@branch_format_raw}/")
342
- log(:INFO, "Remote stable branch format: #{@stable_branch_format}")
343
- log(:INFO, "Remote stable base format: #{@stable_base_format}")
344
-
345
- if @stable_base_patterns.length > 0 then
346
- log(:INFO, "")
347
- log(:INFO, "Stable base rules:")
348
- @stable_base_patterns.each(){|name, base|
349
- log(:INFO, "\t#{name} -> #{base}")
350
- }
351
- end
352
- brList = getBranchList(opts[:br_suff])
353
- brStList = getStableBranchList()
354
-
355
- if brList.length > 0 then
356
- log(:INFO, "")
357
- log(:INFO, "Local branches:")
358
- brList.each(){|br|
359
- branch = Branch.load(self, br, nil, opts[:branch_suff])
360
- localBr = branch.local_branch
361
- stableBr = @@STABLE_REPO + "/" + branch.remote_branch
362
- stableBase = branch.stable_base
363
- runGit("rev-parse --verify --quiet #{stableBr}")
364
- stableBr = "<MISSING>" if $? != 0
365
- log(:INFO, "\t#{localBr} -> #{stableBr} (#{stableBase})")
366
- brStList.delete(br)
367
- }
368
- end
369
-
370
- if brStList.length > 0 then
371
- log(:INFO, "")
372
- log(:INFO, "Upstream branches:")
373
- brStList.each(){|br|
374
- branch = Branch.load(self, br, nil, opts[:branch_suff])
375
- stableBr = @@STABLE_REPO + "/" + branch.remote_branch
376
- stableBase = branch.stable_base
377
- log(:INFO, "\t<MISSING> -> #{stableBr} (#{stableBase})")
378
- }
379
- end
380
- end
361
+ log(:INFO, "Configuration summary:")
362
+ if self.class != GitMaintain::Repo then
363
+ log(:INFO, "Using custom repo class: #{self.class.to_s()}")
364
+ end
365
+ log(:INFO, "Stable remote: #{@stable_repo}")
366
+ log(:INFO, "Validation remote: #{@valid_repo}")
367
+ log(:INFO, "")
368
+ log(:INFO, "Branch config:")
369
+ log(:INFO, "Local branch format: /#{@branch_format_raw}/")
370
+ log(:INFO, "Remote stable branch format: #{@stable_branch_format}")
371
+ log(:INFO, "Remote stable base format: #{@stable_base_format}")
372
+
373
+ if @stable_base_patterns.length > 0 then
374
+ log(:INFO, "")
375
+ log(:INFO, "Stable base rules:")
376
+ @stable_base_patterns.each(){|name, base|
377
+ log(:INFO, "\t#{name} -> #{base}")
378
+ }
379
+ end
380
+ brList = getBranchList(opts[:br_suff])
381
+ brStList = getStableBranchList()
382
+
383
+ if brList.length > 0 then
384
+ log(:INFO, "")
385
+ log(:INFO, "Local branches:")
386
+ brList.each(){|br|
387
+ branch = Branch.load(self, br, nil, opts[:br_suff])
388
+ localBr = branch.local_branch
389
+ stableBr = @@STABLE_REPO + "/" + branch.remote_branch
390
+ stableBase = branch.stable_base
391
+ begin
392
+ ref_exist?(stableBr)
393
+ rescue NoRefError
394
+ stableBr = "<MISSING>"
395
+ end
396
+ log(:INFO, "\t#{localBr} -> #{stableBr} (#{stableBase})")
397
+ brStList.delete(br)
398
+ }
399
+ end
400
+
401
+ if brStList.length > 0 then
402
+ log(:INFO, "")
403
+ log(:INFO, "Upstream branches:")
404
+ brStList.each(){|br|
405
+ branch = Branch.load(self, br, nil, opts[:branch_suff])
406
+ stableBr = @@STABLE_REPO + "/" + branch.remote_branch
407
+ stableBase = branch.stable_base
408
+ log(:INFO, "\t<MISSING> -> #{stableBr} (#{stableBase})")
409
+ }
410
+ end
411
+ end
381
412
  def find_alts(commit)
382
413
  alts=[]
383
414
 
384
- subj=runGit("log -1 --pretty='%s' #{commit}")
385
- return alts if $? != 0
415
+ begin
416
+ subj=runGit("log -1 --pretty='%s' #{commit}")
417
+ rescue RuntimeError
418
+ return []
419
+ end
386
420
 
387
421
  branches = getStableBranchList().map(){|v| @@STABLE_REPO + "/" + versionToStableBranch(v)}
388
422
 
@@ -399,46 +433,46 @@ module GitMaintain
399
433
  #
400
434
  # Github API stuff
401
435
  #
402
- def api
403
- @api ||= Octokit::Client.new(:access_token => token, :auto_paginate => true)
404
- end
405
-
406
- def token
407
- @token ||= begin
408
- # We cannot use the 'defaults' functionality of git_config here,
409
- # because get_new_token would be evaluated before git_config ran
410
- tok = getGitConfig("maintain.api-token")
436
+ def api
437
+ @api ||= Octokit::Client.new(:access_token => token, :auto_paginate => true)
438
+ end
439
+
440
+ def token
441
+ @token ||= begin
442
+ # We cannot use the 'defaults' functionality of git_config here,
443
+ # because get_new_token would be evaluated before git_config ran
444
+ tok = getGitConfig("maintain.api-token")
411
445
  tok.to_s() == "" ? get_new_token : tok
412
- end
413
- end
414
- def get_new_token
415
- puts "Requesting a new OAuth token from Github..."
416
- print "Github username: "
417
- user = $stdin.gets.chomp
418
- print "Github password: "
419
- pass = $stdin.noecho(&:gets).chomp
420
- puts
421
-
422
- api = Octokit::Client.new(:login => user, :password => pass)
423
-
424
- begin
425
- res = api.create_authorization(:scopes => [:repo], :note => "git-maintain")
426
- rescue Octokit::Unauthorized
427
- puts "Username or password incorrect. Please try again."
428
- return get_new_token
446
+ end
447
+ end
448
+ def get_new_token
449
+ puts "Requesting a new OAuth token from Github..."
450
+ print "Github username: "
451
+ user = $stdin.gets.chomp
452
+ print "Github password: "
453
+ pass = $stdin.noecho(&:gets).chomp
454
+ puts
455
+
456
+ api = Octokit::Client.new(:login => user, :password => pass)
457
+
458
+ begin
459
+ res = api.create_authorization(:scopes => [:repo], :note => "git-maintain")
460
+ rescue Octokit::Unauthorized
461
+ puts "Username or password incorrect. Please try again."
462
+ return get_new_token
429
463
  rescue Octokit::OneTimePasswordRequired
430
- print "Github OTP: "
431
- otp = $stdin.noecho(&:gets).chomp
432
- res = api.create_authorization(:scopes => [:repo], :note => "git-maintain",
464
+ print "Github OTP: "
465
+ otp = $stdin.noecho(&:gets).chomp
466
+ res = api.create_authorization(:scopes => [:repo], :note => "git-maintain",
433
467
  :headers => {"X-GitHub-OTP" => otp})
434
- end
468
+ end
435
469
 
436
- token = res[:token]
437
- runGit("config --global maintain.api-token '#{token}'")
470
+ token = res[:token]
471
+ runGit("config --global maintain.api-token '#{token}'")
438
472
 
439
473
  # Now reopen with the token so OTP does not bother us
440
474
  @api=nil
441
475
  token
442
- end
443
- end
476
+ end
477
+ end
444
478
  end
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-maintain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Morey-Chaisemartin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-18 00:00:00.000000000 Z
11
+ date: 2025-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: octokit
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '5'
19
+ version: '5.0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: '3.0'
30
- - - "<"
24
+ - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: '5'
26
+ version: '5.0'
33
27
  description: |-
34
28
  Be lazy and let git-maintain do all the heavy lifting for maintaining stable branches.
35
29
  Leaves you only with the essential: reviewing the selected patches and decide where they should go.
@@ -71,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
65
  - !ruby/object:Gem::Version
72
66
  version: '0'
73
67
  requirements: []
74
- rubygems_version: 3.0.8
68
+ rubygems_version: 3.2.33
75
69
  signing_key:
76
70
  specification_version: 4
77
71
  summary: Your ultimate script for maintaining stable branches and releasing your project.