git-maintain 0.7.0 → 0.9.0rc1
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 +22 -0
- data/LICENSE +674 -22
- data/README.md +26 -5
- data/bin/git-maintain +8 -5
- data/lib/addons/RDMACore.rb +67 -7
- data/lib/addons/git-maintain.rb +66 -0
- data/lib/azure.rb +98 -0
- data/lib/branch.rb +141 -78
- data/lib/ci.rb +88 -0
- data/lib/common.rb +29 -16
- data/lib/repo.rb +143 -72
- data/lib/travis.rb +19 -62
- metadata +19 -10
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
|
-
|
15
|
-
|
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
|
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
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
mail.puts "
|
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 "
|
242
|
-
|
225
|
+
mail.puts "These version were tagged/released:\n * " +
|
226
|
+
new_tags.join("\n * ")
|
243
227
|
mail.puts ""
|
244
|
-
|
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
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
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
|
-
|
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
|
-
|
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: #{
|
312
|
-
log(:INFO, "Validation remote: #{
|
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
|
-
|
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
|
3
|
-
TRAVIS_URL='https://api.travis-ci.
|
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
|
-
|
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("
|
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(:
|
33
|
+
return getJson(@url, :travis_br_valid, 'repos/' + @repo.remote_valid + '/branches')
|
77
34
|
end
|
78
35
|
def getBrStableJson()
|
79
|
-
return getJson(:
|
36
|
+
return getJson(@url, :travis_br_stable, 'repos/' + @repo.remote_stable + '/branches')
|
80
37
|
end
|
81
38
|
def findBranch(sha1, resp)
|
82
|
-
log(:
|
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(:
|
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
|
120
|
-
|
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.
|
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:
|
11
|
+
date: 2022-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
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
|
-
-
|
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:
|
72
|
+
version: 1.3.1
|
64
73
|
requirements: []
|
65
|
-
rubygems_version: 3.0.
|
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: []
|