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.
- 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: []
|