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/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
|
19
|
+
- **monitor**: Check the CI state of all branches
|
20
20
|
- **push_stable**: Push to stable repo
|
21
|
-
- **monitor_stable**: Check the
|
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
|
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
|
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
|
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) 2022 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/>.
|
data/bin/git-maintain
CHANGED
@@ -11,17 +11,17 @@ $LOAD_PATH.pop()
|
|
11
11
|
|
12
12
|
opts = {
|
13
13
|
:br_suff => "master",
|
14
|
-
:
|
14
|
+
:yn_default => nil,
|
15
15
|
}
|
16
|
-
|
16
|
+
ACTION_HELPS = GitMaintain::getActionAttr("ACTION_HELP")
|
17
17
|
actionParser = OptionParser.new(nil, 60)
|
18
18
|
actionParser.banner = "Usage: #{__FILE__} <action> [action options]"
|
19
19
|
actionParser.separator ""
|
20
20
|
actionParser.separator "Options:"
|
21
21
|
actionParser.on("-h", "--help", "Display usage.") { |val| puts actionParser.to_s; exit 0 }
|
22
22
|
actionParser.separator "Possible actions:"
|
23
|
-
|
24
|
-
actionParser.separator "\t " + x
|
23
|
+
ACTION_HELPS.each(){|k, x|
|
24
|
+
actionParser.separator "\t * " + k.to_s() + ": " + x
|
25
25
|
}
|
26
26
|
rest = actionParser.order!(ARGV);
|
27
27
|
if rest.length <= 0 then
|
@@ -38,13 +38,16 @@ ARGV.shift()
|
|
38
38
|
|
39
39
|
optsParser = OptionParser.new(nil, 60)
|
40
40
|
optsParser.banner = "Usage: #{__FILE__} #{action_s} "
|
41
|
+
optsParser.separator "# " + ACTION_HELPS[action].to_s()
|
41
42
|
optsParser.separator ""
|
42
43
|
optsParser.separator "Options:"
|
43
44
|
optsParser.on("-h", "--help", "Display usage.") { |val| puts optsParser.to_s; exit 0 }
|
44
45
|
optsParser.on("-b", "--branch-suffix [SUFFIX]", "Branch suffix. Default is 'master'.") {
|
45
46
|
|val| opts[:br_suff] = val}
|
46
47
|
optsParser.on("-n", "--no", "Assume no to all questions.") {
|
47
|
-
|val| opts[:
|
48
|
+
|val| opts[:yn_default] = :no}
|
49
|
+
optsParser.on("-y", "--yes", "Assume yes to all questions.") {
|
50
|
+
|val| opts[:yn_default] = :yes}
|
48
51
|
optsParser.on("--verbose", "Displays more informations.") {
|
49
52
|
|val| GitMaintain::setVerbose(true)}
|
50
53
|
GitMaintain::setOpts(action, optsParser, opts)
|
data/lib/addons/RDMACore.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module GitMaintain
|
2
2
|
class RDMACoreBranch < Branch
|
3
3
|
REPO_NAME = "rdma-core"
|
4
|
+
AZURE_MIN_VERSION = 18
|
4
5
|
|
5
6
|
def self.set_opts(action, optsParser, opts)
|
6
7
|
opts[:rel_type] = nil
|
@@ -15,8 +16,14 @@ module GitMaintain
|
|
15
16
|
end
|
16
17
|
def self.check_opts(opts)
|
17
18
|
if opts[:action] == :release then
|
18
|
-
|
19
|
+
case opts[:rel_type]
|
20
|
+
when nil
|
19
21
|
raise "No release type specified use --stable or --major"
|
22
|
+
when :major
|
23
|
+
if opts[:manual_branch] == nil then
|
24
|
+
GitMaintain::log(:INFO, "Major release selected. Auto-forcing branch to master")
|
25
|
+
opts[:manual_branch] = "master"
|
26
|
+
end
|
20
27
|
end
|
21
28
|
end
|
22
29
|
end
|
@@ -64,16 +71,19 @@ module GitMaintain
|
|
64
71
|
tag_file.puts `git log HEAD ^#{git_prev_ver} --no-merges --format=' * %s'`
|
65
72
|
tag_file.close()
|
66
73
|
|
74
|
+
edit_flag = ""
|
75
|
+
edit_flag = "--edit" if opts[:no_edit] == false
|
76
|
+
|
67
77
|
if opts[:rel_type] == :major
|
68
78
|
# For major, tag the current version first
|
69
|
-
@repo.runGitInteractive("tag -a -s v#{rel_ver}
|
79
|
+
@repo.runGitInteractive("tag -a -s v#{rel_ver} #{edit_flag} -F #{tag_path}")
|
70
80
|
if $? != 0 then
|
71
81
|
raise("Failed to tag branch #{local_branch}")
|
72
82
|
end
|
73
83
|
end
|
74
84
|
|
75
85
|
# Update version number in relevant files
|
76
|
-
@repo.run("sed -i -e 's/\\(Version:[[:space:]]*\\)[0-9.]\\+/\\1#{new_ver}/g'
|
86
|
+
@repo.run("sed -i -e 's/\\(Version:[[:space:]]*\\)[0-9.]\\+/\\1#{new_ver}/g' */*.spec")
|
77
87
|
@repo.run("sed -i -e 's/\\([sS][eE][tT](PACKAGE_VERSION[[:space:]]*\"\\)[0-9.]*\"/\\1#{new_ver}\"/g' CMakeLists.txt")
|
78
88
|
|
79
89
|
case opts[:rel_type]
|
@@ -93,14 +103,14 @@ mv debian/changelog.new debian/changelog")
|
|
93
103
|
end
|
94
104
|
|
95
105
|
# Add and commit
|
96
|
-
@repo.runGit("add
|
97
|
-
@repo.runGitInteractive("commit -m '#{commit_msg} #{new_ver}' --verbose
|
106
|
+
@repo.runGit("add */*.spec CMakeLists.txt debian/changelog")
|
107
|
+
@repo.runGitInteractive("commit -m '#{commit_msg} #{new_ver}' --verbose #{edit_flag} --signoff")
|
98
108
|
if $? != 0 then
|
99
109
|
raise("Failed to commit on branch #{local_branch}")
|
100
110
|
end
|
101
111
|
|
102
112
|
if opts[:rel_type] == :stable
|
103
|
-
@repo.runGitInteractive("tag -a -s v#{rel_ver}
|
113
|
+
@repo.runGitInteractive("tag -a -s v#{rel_ver} #{edit_flag} -F #{tag_path}")
|
104
114
|
if $? != 0 then
|
105
115
|
raise("Failed to tag branch #{local_branch}")
|
106
116
|
end
|
@@ -108,7 +118,57 @@ mv debian/changelog.new debian/changelog")
|
|
108
118
|
`rm -f #{tag_path}`
|
109
119
|
end
|
110
120
|
end
|
121
|
+
class RDMACoreRepo < Repo
|
122
|
+
AZURE_MIN_VERSION = 18
|
123
|
+
def submitReleases(opts, new_tags)
|
124
|
+
new_tags.each(){|tag|
|
125
|
+
next if tag !~ /v([0-9]*)\.[0-9]*/
|
126
|
+
major=$1.to_i
|
127
|
+
# Starting from v27, do not create the github release ourself as this is done by Azure
|
128
|
+
createRelease(opts, tag, major < AZURE_MIN_VERSION)
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class RDMACoreCI < CI
|
134
|
+
AZURE_MIN_VERSION = 18
|
135
|
+
def initialize(repo)
|
136
|
+
super(repo)
|
137
|
+
@travis = GitMaintain::TravisCI.new(repo)
|
138
|
+
@azure = GitMaintain::AzureCI.new(repo, 'ucfconsort', 'ucfconsort')
|
111
139
|
|
140
|
+
# Auto generate all CI required methods
|
141
|
+
# Wicked ruby tricker to find all the public methods of CI but not of inherited classes
|
142
|
+
# to dynamically define these method in the object being created
|
143
|
+
(GitMaintain::CI.new(repo).public_methods() - Object.new.public_methods()).each(){|method|
|
144
|
+
# Skip specific emptyCache method
|
145
|
+
next if method == :emptyCache
|
146
|
+
|
147
|
+
self.define_singleton_method(method) { |br, *args|
|
148
|
+
if br.version =~ /([0-9]+)/
|
149
|
+
major=$1.to_i
|
150
|
+
elsif br.version == "master"
|
151
|
+
major=99999
|
152
|
+
else
|
153
|
+
raise("Unable to monitor branch #{br} on a CI")
|
154
|
+
end
|
155
|
+
if major < AZURE_MIN_VERSION
|
156
|
+
@travis.send(method, br, *args)
|
157
|
+
else
|
158
|
+
@azure.send(method, br, *args)
|
159
|
+
end
|
160
|
+
}
|
161
|
+
}
|
162
|
+
end
|
163
|
+
def emptyCache()
|
164
|
+
@travis.emptyCache()
|
165
|
+
@azure.emptyCache()
|
166
|
+
end
|
167
|
+
end
|
112
168
|
GitMaintain::registerCustom(RDMACoreBranch::REPO_NAME,
|
113
|
-
{
|
169
|
+
{
|
170
|
+
GitMaintain::Branch => RDMACoreBranch,
|
171
|
+
GitMaintain::Repo => RDMACoreRepo,
|
172
|
+
GitMaintain::CI => RDMACoreCI,
|
173
|
+
})
|
114
174
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module GitMaintain
|
2
|
+
class GitMaintainBranch < Branch
|
3
|
+
REPO_NAME = "git-maintain"
|
4
|
+
|
5
|
+
def release(opts)
|
6
|
+
prev_ver=@repo.runGit("show HEAD:CHANGELOG | grep -A 1 -- '---------' | head -n 2 | tail -n 1 | awk '{ print $1}'").chomp()
|
7
|
+
ver_nums = prev_ver.split(".")
|
8
|
+
|
9
|
+
if opts[:manual_branch] == nil then
|
10
|
+
new_ver = (ver_nums[0 .. -2] + [ver_nums[-1].to_i() + 1 ]).join(".")
|
11
|
+
git_prev_ver = "v" + (ver_nums[-1] == "0" ? ver_nums[0 .. -2].join(".") : prev_ver)
|
12
|
+
else
|
13
|
+
new_ver = (ver_nums[0 .. -3] + [ver_nums[-2].to_i() + 1 ] + [ "0" ]).join(".")
|
14
|
+
git_prev_ver = "v" + prev_ver
|
15
|
+
end
|
16
|
+
|
17
|
+
changes=@repo.runGit("show HEAD:CHANGELOG | awk ' BEGIN {count=0} {if ($1 == \"------------------\") count++; if (count == 0) print $0}'")
|
18
|
+
|
19
|
+
puts "Preparing release #{prev_ver} => #{new_ver}"
|
20
|
+
rep = GitMaintain::checkLog(opts, @local_branch, git_prev_ver, "release")
|
21
|
+
if rep != "y" then
|
22
|
+
puts "Skipping release"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
# Prepare tag message
|
27
|
+
tag_path=`mktemp`.chomp()
|
28
|
+
puts tag_path
|
29
|
+
tag_file = File.open(tag_path, "w+")
|
30
|
+
tag_file.puts "git-maintain-#{new_ver}"
|
31
|
+
tag_file.puts ""
|
32
|
+
tag_file.puts changes
|
33
|
+
tag_file.close()
|
34
|
+
|
35
|
+
@repo.run("cat <<EOF > CHANGELOG.new
|
36
|
+
------------------
|
37
|
+
#{new_ver} #{`date '+ (%Y-%m-%d)'`.chomp()}
|
38
|
+
------------------
|
39
|
+
|
40
|
+
$(cat CHANGELOG)
|
41
|
+
EOF
|
42
|
+
mv CHANGELOG.new CHANGELOG")
|
43
|
+
|
44
|
+
# Add and commit
|
45
|
+
@repo.runGit("add CHANGELOG")
|
46
|
+
@repo.runGitInteractive("commit -F #{tag_path} --verbose --edit --signoff")
|
47
|
+
if $? != 0 then
|
48
|
+
raise("Failed to commit on branch #{local_branch}")
|
49
|
+
end
|
50
|
+
@repo.runGitInteractive("tag -a -s v#{new_ver} --edit -F #{tag_path}")
|
51
|
+
if $? != 0 then
|
52
|
+
raise("Failed to tag branch #{local_branch}")
|
53
|
+
end
|
54
|
+
`rm -f #{tag_path}`
|
55
|
+
end
|
56
|
+
end
|
57
|
+
class GitMaintainRepo < Repo
|
58
|
+
def initialize(path)
|
59
|
+
super(path)
|
60
|
+
@NOTIFY_RELEASE = false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
GitMaintain::registerCustom(GitMaintainBranch::REPO_NAME,
|
64
|
+
{ GitMaintain::Branch => GitMaintainBranch,
|
65
|
+
GitMaintain::Repo => GitMaintainRepo})
|
66
|
+
end
|
data/lib/azure.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
module GitMaintain
|
2
|
+
class AzureCI < CI
|
3
|
+
AZURE_URL='https://dev.azure.com/'
|
4
|
+
|
5
|
+
def initialize(repo, stable='', valid='')
|
6
|
+
super(repo)
|
7
|
+
@url = AZURE_URL
|
8
|
+
@stable_org=stable
|
9
|
+
@valid_org=valid
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def getState(sha1, resp)
|
14
|
+
br = findBranch(sha1, resp)
|
15
|
+
return "not found" if br == nil
|
16
|
+
return "running" if br["result"] == nil
|
17
|
+
return br["result"].to_s()
|
18
|
+
end
|
19
|
+
def getLog(sha1, resp)
|
20
|
+
str=""
|
21
|
+
# br = findBranch(sha1, resp)
|
22
|
+
# raise("Travis build not found") if br == nil
|
23
|
+
# job_id = br["id"].to_s()
|
24
|
+
# logs= getJson(@url, "azure_log_list" + job_id,
|
25
|
+
# @repo.name + "/_apis/build/builds/#{job_id}/logs?api-version=5.1")
|
26
|
+
# 1.upto(logs["count"]) { |x|
|
27
|
+
# log(:DEBUG_CI, "Downloading log file #{x}/#{logs["count"]}")
|
28
|
+
# nzstr = getJson(@url, "azure_log_" + job_id + '_' + x.to_s(),
|
29
|
+
# @repo.name + "/_apis/build/builds/#{job_id}/logs/#{x}?api-version=5.1", false)
|
30
|
+
# # This is zipped. We need to extract it
|
31
|
+
# }
|
32
|
+
return str
|
33
|
+
end
|
34
|
+
def getTS(sha1, resp)
|
35
|
+
br = findBranch(sha1, resp)
|
36
|
+
raise("Travis build not found") if br == nil
|
37
|
+
return br["started_at"]
|
38
|
+
end
|
39
|
+
def checkState(sha1, resp)
|
40
|
+
st = getState(sha1, resp)
|
41
|
+
return st == "passed" || st == "succeeded"
|
42
|
+
end
|
43
|
+
|
44
|
+
def getBrValidJson()
|
45
|
+
raise("Validation organisation not provided") if @valid_org == ''
|
46
|
+
return getJson(@url + @valid_org + '/',
|
47
|
+
:azure_br_valid, @repo.name + '/_apis/build/builds?api-version=5.1')
|
48
|
+
end
|
49
|
+
def getBrStableJson()
|
50
|
+
raise("Stable organisation not provided") if @stable_org == ''
|
51
|
+
return getJson(@url + @stable_org + '/',
|
52
|
+
:azure_br_stable, @repo.name + '/_apis/build/builds?api-version=5.1')
|
53
|
+
end
|
54
|
+
def findBranch(sha1, resp)
|
55
|
+
log(:DEBUG_CI, "Looking for build for #{sha1}")
|
56
|
+
resp["value"].each(){|br|
|
57
|
+
commit= br["sourceVersion"]
|
58
|
+
raise("Incomplete JSON received from Travis") if commit == nil
|
59
|
+
log(:DEBUG_CI, "Found entry for sha #{commit}")
|
60
|
+
next if commit != sha1
|
61
|
+
return br
|
62
|
+
}
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
public
|
67
|
+
def getValidState(br, sha1)
|
68
|
+
return getState(sha1, getBrValidJson())
|
69
|
+
end
|
70
|
+
def checkValidState(br, sha1)
|
71
|
+
return checkState(sha1, getBrValidJson())
|
72
|
+
end
|
73
|
+
def getValidLog(br, sha1)
|
74
|
+
return getLog(sha1, getBrValidJson())
|
75
|
+
end
|
76
|
+
def getValidTS(br, sha1)
|
77
|
+
return getTS(sha1, getBrValidJson())
|
78
|
+
end
|
79
|
+
|
80
|
+
def getStableState(br, sha1)
|
81
|
+
return getState(sha1, getBrStableJson())
|
82
|
+
end
|
83
|
+
def checkStableState(br, sha1)
|
84
|
+
return checkState(sha1, getBrStableJson())
|
85
|
+
end
|
86
|
+
def getStableLog(br, sha1)
|
87
|
+
return getLog(sha1, getBrStableJson())
|
88
|
+
end
|
89
|
+
def getStableTS(br, sha1)
|
90
|
+
return getTS(sha1, getBrStableJson())
|
91
|
+
end
|
92
|
+
def isErrored(br, status)
|
93
|
+
# https://docs.microsoft.com/en-us/rest/api/azure/devops/build/builds/list?
|
94
|
+
# view=azure-devops-rest-5.1#buildresult
|
95
|
+
return status == "failed"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|