git-maintain 0.7.0 → 0.9.0rc1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/repo.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'octokit'
2
+ require 'io/console'
3
+
1
4
  module GitMaintain
2
5
  class Repo
3
6
  @@VALID_REPO = "github"
@@ -10,10 +13,10 @@ module GitMaintain
10
13
  # Internal commands for completion
11
14
  :list_suffixes, :submit_release
12
15
  ]
13
- ACTION_HELP = [
14
- "* submit_release: Push the to stable and create the release packages",
15
- "* summary: Displays a summary of the configuration and the branches git-maintain sees"
16
- ]
16
+ ACTION_HELP = {
17
+ :submit_release => "Push the tags to 'stable' remote and create the release packages",
18
+ :summary => "Displays a summary of the configuration and the branches git-maintain sees"
19
+ }
17
20
 
18
21
  def self.load(path=".")
19
22
  dir = Dir.pwd()
@@ -45,6 +48,7 @@ module GitMaintain
45
48
  @branch_list=nil
46
49
  @stable_branches=nil
47
50
  @suffix_list=nil
51
+ @config_cache={}
48
52
 
49
53
  if path == nil
50
54
  @path = Dir.pwd()
@@ -134,7 +138,7 @@ module GitMaintain
134
138
  fi; git --work-tree=#{@path} imap-send #{cmd}`
135
139
  end
136
140
  def getGitConfig(entry)
137
- return runGit("config #{entry} 2> /dev/null").chomp()
141
+ return @config_cache[entry] ||= runGit("config #{entry} 2> /dev/null").chomp()
138
142
  end
139
143
 
140
144
  def runBash()
@@ -194,7 +198,7 @@ module GitMaintain
194
198
  return @suffix_list
195
199
  end
196
200
 
197
- def submitReleases(opts)
201
+ def getUnreleasedTags(opts)
198
202
  remote_tags=runGit("ls-remote --tags #{@stable_repo} |
199
203
  egrep 'refs/tags/v[0-9.]*$'").split("\n").map(){
200
204
  |x| x.gsub(/.*refs\/tags\//, '')
@@ -202,75 +206,76 @@ module GitMaintain
202
206
  local_tags =runGit("tag -l | egrep '^v[0-9.]*$'").split("\n")
203
207
 
204
208
  new_tags = local_tags - remote_tags
205
- if new_tags.empty? then
206
- log(:INFO, "All tags are already submitted.")
207
- return
208
- end
209
-
210
- log(:WARNING, "This will officially release these tags: #{new_tags.join(", ")}")
211
- rep = GitMaintain::confirm(opts, "release them")
212
- if rep != 'y' then
213
- raise "Aborting.."
214
- end
215
-
216
- if @NOTIFY_RELEASE != false
217
- mail_path=`mktemp`.chomp()
218
- mail = File.open(mail_path, "w+")
219
- mail.puts "From " + runGit("rev-parse HEAD") + " " + `date`.chomp()
220
- mail.puts "From: " + getGitConfig("user.name") +
221
- " <" + getGitConfig("user.email") +">"
222
- mail.puts "To: " + getGitConfig("patch.target")
223
- mail.puts "Date: " + `date -R`.chomp()
224
-
225
- if new_tags.length > 4 then
226
- mail.puts "Subject: [ANNOUNCE] " + File.basename(@path) + ": new stable releases"
227
- mail.puts ""
228
- mail.puts "These version were tagged/released:\n * " +
229
- new_tags.join("\n * ")
230
- mail.puts ""
231
- else
232
- mail.puts "Subject: [ANNOUNCE] " + File.basename(@path) + " " +
233
- (new_tags.length > 1 ?
234
- (new_tags[0 .. -2].join(", ") + " and " + new_tags[-1] + " have") :
235
- (new_tags.join(" ") + " has")) +
236
- " been tagged/released"
237
- mail.puts ""
238
- end
239
- mail.puts "It's available at the normal places:"
209
+ return new_tags
210
+ end
211
+ def genReleaseNotif(opts, new_tags)
212
+ return if @NOTIFY_RELEASE == false
213
+
214
+ mail_path=`mktemp`.chomp()
215
+ mail = File.open(mail_path, "w+")
216
+ mail.puts "From " + runGit("rev-parse HEAD") + " " + `date`.chomp()
217
+ mail.puts "From: " + getGitConfig("user.name") +
218
+ " <" + getGitConfig("user.email") +">"
219
+ mail.puts "To: " + getGitConfig("patch.target")
220
+ mail.puts "Date: " + `date -R`.chomp()
221
+
222
+ if new_tags.length > 4 then
223
+ mail.puts "Subject: [ANNOUNCE] " + File.basename(@path) + ": new stable releases"
240
224
  mail.puts ""
241
- mail.puts "git://github.com/#{@remote_stable}"
242
- mail.puts "https://github.com/#{@remote_stable}/releases"
225
+ mail.puts "These version were tagged/released:\n * " +
226
+ new_tags.join("\n * ")
243
227
  mail.puts ""
244
- mail.puts "---"
228
+ else
229
+ mail.puts "Subject: [ANNOUNCE] " + File.basename(@path) + " " +
230
+ (new_tags.length > 1 ?
231
+ (new_tags[0 .. -2].join(", ") + " and " + new_tags[-1] + " have") :
232
+ (new_tags.join(" ") + " has")) +
233
+ " been tagged/released"
245
234
  mail.puts ""
246
- mail.puts "Here's the information from the tags:"
247
- new_tags.sort().each(){|tag|
248
- mail.puts `git show #{tag} --no-decorate -q | awk '!p;/^-----END PGP SIGNATURE-----/{p=1}'`
249
- mail.puts ""
250
- }
251
- mail.puts "It's available at the normal places:"
235
+ end
236
+ mail.puts "It's available at the normal places:"
237
+ mail.puts ""
238
+ mail.puts "git://github.com/#{@remote_stable}"
239
+ mail.puts "https://github.com/#{@remote_stable}/releases"
240
+ mail.puts ""
241
+ mail.puts "---"
242
+ mail.puts ""
243
+ mail.puts "Here's the information from the tags:"
244
+ new_tags.sort().each(){|tag|
245
+ mail.puts `git show #{tag} --no-decorate -q | awk '!p;/^-----END PGP SIGNATURE-----/{p=1}'`
252
246
  mail.puts ""
253
- mail.puts "git://github.com/#{@remote_stable}"
254
- mail.puts "https://github.com/#{@remote_stable}/releases"
255
- mail.close()
256
-
257
- case @mail_format
258
- when :imap_send
259
- puts runGitImap("< #{mail_path}")
260
- when :send_email
261
- run("cp #{mail_path} announce-release.eml")
262
- log(:INFO, "Generated annoucement email in #{@path}/announce-release.eml")
263
- end
264
- run("rm -f #{mail_path}")
247
+ }
248
+ mail.close()
249
+
250
+ case @mail_format
251
+ when :imap_send
252
+ puts runGitImap("< #{mail_path}")
253
+ when :send_email
254
+ run("cp #{mail_path} announce-release.eml")
255
+ log(:INFO, "Generated annoucement email in #{@path}/announce-release.eml")
265
256
  end
257
+ run("rm -f #{mail_path}")
258
+ end
259
+ def submitReleases(opts, new_tags)
260
+ new_tags.each(){|tag|
261
+ createRelease(opts, tag)
262
+ }
263
+ end
266
264
 
267
- log(:WARNING, "Last chance to cancel before submitting")
268
- rep= GitMaintain::confirm(opts, "submit these releases")
269
- if rep != 'y' then
270
- raise "Aborting.."
265
+ def createRelease(opts, tag, github_rel=true)
266
+ log(:INFO, "Creating a release for #{tag}")
267
+ runGit("push #{@stable_repo} refs/tags/#{tag}")
268
+
269
+ if github_rel == true then
270
+ msg = runGit("tag -l -n1000 '#{tag}'") + "\n"
271
+
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)
271
277
  end
272
- puts `#{@@SUBMIT_BINARY}`
273
- end
278
+ end
274
279
 
275
280
  def versionToLocalBranch(version, suff)
276
281
  return @branch_format_raw.gsub(/\\\//, '/').
@@ -304,12 +309,33 @@ module GitMaintain
304
309
  puts getSuffixList()
305
310
  end
306
311
  def submit_release(opts)
307
- submitReleases(opts)
312
+ new_tags = getUnreleasedTags(opts)
313
+ if new_tags.empty? then
314
+ log(:INFO, "All tags are already submitted.")
315
+ return
316
+ end
317
+
318
+ log(:WARNING, "This will officially release these tags: #{new_tags.join(", ")}")
319
+ rep = GitMaintain::confirm(opts, "release them", true)
320
+ if rep != 'y' then
321
+ raise "Aborting.."
322
+ end
323
+
324
+ if @NOTIFY_RELEASE != false
325
+ genReleaseNotif(opts, new_tags)
326
+ end
327
+
328
+ log(:WARNING, "Last chance to cancel before submitting")
329
+ rep= GitMaintain::confirm(opts, "submit these releases", true)
330
+ if rep != 'y' then
331
+ raise "Aborting.."
332
+ end
333
+ submitReleases(opts, new_tags)
308
334
  end
309
335
  def summary(opts)
310
336
  log(:INFO, "Configuration summary:")
311
- log(:INFO, "Stable remote: #{@@STABLE_REPO}")
312
- log(:INFO, "Validation remote: #{@@VALID_REPO}")
337
+ log(:INFO, "Stable remote: #{@stable_repo}")
338
+ log(:INFO, "Validation remote: #{@valid_repo}")
313
339
  log(:INFO, "")
314
340
  log(:INFO, "Branch config:")
315
341
  log(:INFO, "Local branch format: /#{@branch_format_raw}/")
@@ -369,5 +395,50 @@ module GitMaintain
369
395
 
370
396
  return alts
371
397
  end
372
- end
398
+
399
+ #
400
+ # Github API stuff
401
+ #
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")
411
+ 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
429
+ rescue Octokit::OneTimePasswordRequired
430
+ print "Github OTP: "
431
+ otp = $stdin.noecho(&:gets).chomp
432
+ res = api.create_authorization(:scopes => [:repo], :note => "git-maintain",
433
+ :headers => {"X-GitHub-OTP" => otp})
434
+ end
435
+
436
+ token = res[:token]
437
+ runGit("config --global maintain.api-token '#{token}'")
438
+
439
+ # Now reopen with the token so OTP does not bother us
440
+ @api=nil
441
+ token
442
+ end
443
+ end
373
444
  end
data/lib/travis.rb CHANGED
@@ -1,56 +1,13 @@
1
1
  module GitMaintain
2
- class TravisChecker
3
- TRAVIS_URL='https://api.travis-ci.org/'
4
-
5
- def self.load(repo)
6
- repo_name = File.basename(repo.path)
7
- return GitMaintain::loadClass(TravisChecker, repo_name, repo)
8
- end
2
+ class TravisCI < CI
3
+ TRAVIS_URL='https://api.travis-ci.com/'
9
4
 
10
5
  def initialize(repo)
11
- GitMaintain::checkDirectConstructor(self.class)
12
-
13
- @repo = repo
14
- @cachedJson={}
6
+ super(repo)
7
+ @url = TRAVIS_URL
15
8
  end
16
9
 
17
10
  private
18
- def log(lvl, str)
19
- GitMaintain::log(lvl, str)
20
- end
21
-
22
- def fetch(uri_str, limit = 10)
23
- # You should choose a better exception.
24
- raise ArgumentError, 'too many HTTP redirects' if limit == 0
25
-
26
- response = Net::HTTP.get_response(URI(uri_str))
27
-
28
- case response
29
- when Net::HTTPSuccess then
30
- response
31
- when Net::HTTPRedirection then
32
- location = response['location']
33
- fetch(location, limit - 1)
34
- else
35
- response.value
36
- end
37
- end
38
- def getJson(query_label, query, json=true)
39
- return @cachedJson[query_label] if @cachedJson[query_label] != nil
40
- url = TRAVIS_URL + query
41
- uri = URI(url)
42
- log(:INFO, "Querying travis...")
43
- log(:DEBUG_TRAVIS, url)
44
- response = fetch(uri)
45
- raise("Travis request failed '#{url}'") if response.code.to_s() != '200'
46
-
47
- if json == true
48
- @cachedJson[query_label] = JSON.parse(response.body)
49
- else
50
- @cachedJson[query_label] = response.body
51
- end
52
- return @cachedJson[query_label]
53
- end
54
11
  def getState(sha1, resp)
55
12
  br = findBranch(sha1, resp)
56
13
  return "not found" if br == nil
@@ -61,7 +18,7 @@ module GitMaintain
61
18
  br = findBranch(sha1, resp)
62
19
  raise("Travis build not found") if br == nil
63
20
  job_id = br["job_ids"].last().to_s()
64
- return getJson("log_" + job_id, 'jobs/' + job_id + '/log', false)
21
+ return getJson(@url, "travis_log_" + job_id, 'jobs/' + job_id + '/log', false)
65
22
  end
66
23
  def getTS(sha1, resp)
67
24
  br = findBranch(sha1, resp)
@@ -73,17 +30,17 @@ module GitMaintain
73
30
  end
74
31
 
75
32
  def getBrValidJson()
76
- return getJson(:br_valid, 'repos/' + @repo.remote_valid + '/branches')
33
+ return getJson(@url, :travis_br_valid, 'repos/' + @repo.remote_valid + '/branches')
77
34
  end
78
35
  def getBrStableJson()
79
- return getJson(:br_stable, 'repos/' + @repo.remote_stable + '/branches')
36
+ return getJson(@url, :travis_br_stable, 'repos/' + @repo.remote_stable + '/branches')
80
37
  end
81
38
  def findBranch(sha1, resp)
82
- log(:DEBUG_TRAVIS, "Looking for build for #{sha1}")
39
+ log(:DEBUG_CI, "Looking for build for #{sha1}")
83
40
  resp["branches"].each(){|br|
84
41
  commit=resp["commits"].select(){|e| e["id"] == br["commit_id"]}.first()
85
42
  raise("Incomplete JSON received from Travis") if commit == nil
86
- log(:DEBUG_TRAVIS, "Found entry for sha #{commit["sha"]}")
43
+ log(:DEBUG_CI, "Found entry for sha #{commit["sha"]}")
87
44
  next if commit["sha"] != sha1
88
45
  return br
89
46
  }
@@ -91,33 +48,33 @@ module GitMaintain
91
48
  end
92
49
 
93
50
  public
94
- def getValidState(sha1)
51
+ def getValidState(br, sha1)
95
52
  return getState(sha1, getBrValidJson())
96
53
  end
97
- def checkValidState(sha1)
54
+ def checkValidState(br, sha1)
98
55
  return checkState(sha1, getBrValidJson())
99
56
  end
100
- def getValidLog(sha1)
57
+ def getValidLog(br, sha1)
101
58
  return getLog(sha1, getBrValidJson())
102
59
  end
103
- def getValidTS(sha1)
60
+ def getValidTS(br, sha1)
104
61
  return getTS(sha1, getBrValidJson())
105
62
  end
106
63
 
107
- def getStableState(sha1)
64
+ def getStableState(br, sha1)
108
65
  return getState(sha1, getBrStableJson())
109
66
  end
110
- def checkStableState(sha1)
67
+ def checkStableState(br, sha1)
111
68
  return checkState(sha1, getBrStableJson())
112
69
  end
113
- def getStableLog(sha1)
70
+ def getStableLog(br, sha1)
114
71
  return getLog(sha1, getBrStableJson())
115
72
  end
116
- def getStableTS(sha1)
73
+ def getStableTS(br, sha1)
117
74
  return getTS(sha1, getBrStableJson())
118
75
  end
119
- def emptyCache()
120
- @cachedJson={}
76
+ def isErrored(br, status)
77
+ return status == "failed" || status == "errored"
121
78
  end
122
79
  end
123
80
  end
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-maintain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0rc1
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: 2019-05-29 00:00:00.000000000 Z
11
+ date: 2022-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: github-release
14
+ name: octokit
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '3.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '0'
29
+ version: '3.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5'
27
33
  description: |-
28
34
  Be lazy and let git-maintain do all the heavy lifting for maintaining stable branches.
29
35
  Leaves you only with the essential: reviewing the selected patches and decide where they should go.
@@ -39,13 +45,16 @@ files:
39
45
  - bin/git-maintain
40
46
  - git-maintain-completion.sh
41
47
  - lib/addons/RDMACore.rb
48
+ - lib/addons/git-maintain.rb
49
+ - lib/azure.rb
42
50
  - lib/branch.rb
51
+ - lib/ci.rb
43
52
  - lib/common.rb
44
53
  - lib/repo.rb
45
54
  - lib/travis.rb
46
55
  homepage: https://github.com/nmorey/git-maintain
47
56
  licenses:
48
- - MIT
57
+ - GPL-3.0
49
58
  metadata: {}
50
59
  post_install_message:
51
60
  rdoc_options: []
@@ -58,12 +67,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
58
67
  version: '0'
59
68
  required_rubygems_version: !ruby/object:Gem::Requirement
60
69
  requirements:
61
- - - ">="
70
+ - - ">"
62
71
  - !ruby/object:Gem::Version
63
- version: '0'
72
+ version: 1.3.1
64
73
  requirements: []
65
- rubygems_version: 3.0.3
74
+ rubygems_version: 3.0.8
66
75
  signing_key:
67
76
  specification_version: 4
68
- summary: Your ultimate script for maintaining stable branches.
77
+ summary: Your ultimate script for maintaining stable branches and releasing your project.
69
78
  test_files: []