contrib: add `github_merge` the script I use to produce merge of PR
[nit.git] / contrib / github_merge.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Query the Github PR API to perform a merge
16 module github_merge
17
18 import github_api
19 import template
20
21 redef class Object
22 # Factorize cast
23 fun json_as_a: Array[nullable Object] do return self.as(Array[nullable Object])
24 # Factorize cast
25 fun json_as_map: Map[String, nullable Object] do return self.as(Map[String, nullable Object])
26 end
27
28 redef class GithubCurl
29 # Get a given pull request (PR)
30 fun getpr(number: Int): Map[String, nullable Object]
31 do
32 var pr = get_and_check("https://api.github.com/repos/privat/nit/pulls/{number}")
33 var prm = pr.json_as_map
34 var sha = prm["head"].json_as_map["sha"]
35 var statuses = get_and_check("https://api.github.com/repos/privat/nit/statuses/{sha}")
36 prm["statuses"] = statuses
37 print "{prm["title"]}: by {prm["user"].json_as_map["login"]} (# {prm["number"]})"
38 print "\tmergable: {prm["mergeable"]}"
39 print "\tstatus: {prm["statuses"].json_as_a[0].json_as_map["state"]}"
40 return prm
41 end
42
43 # Get reviewers of a PR
44 fun getrev(pr: Map[String, nullable Object]): Array[String]
45 do
46 var number = pr["number"].as(Int)
47 var user = pr["user"].json_as_map["login"].as(String)
48 var comments = new Array[nullable Object]
49 comments.add_all(get_and_check("https://api.github.com/repos/privat/nit/issues/{number}/comments").json_as_a)
50 comments.add_all(get_and_check("https://api.github.com/repos/privat/nit/pulls/{number}/comments").json_as_a)
51 var logins = new Array[String]
52 for c in comments do
53 var cm = c.json_as_map
54 var l = cm["user"].json_as_map["login"]
55 assert l isa String
56 if l != user and not logins.has(l) then logins.add(l)
57 end
58 var res = new Array[String]
59 for l in logins do
60 var u = get_and_check("https://api.github.com/users/{l}").json_as_map
61 var r = "{u["name"]} <{u["email"]}>"
62 res.add r
63
64 end
65 return res
66 end
67
68 end
69
70 if "NIT_TESTING".environ == "true" then exit 0
71
72 var auth = get_github_oauth
73
74 if auth == "" then
75 print "Not github token, please configure one with"
76 print " git config --add github.oauthtoken MYOAUTHTOKEN"
77 return
78 end
79
80 var curl = new GithubCurl(auth, "Merge-o-matic (privat/nit)")
81
82 if args.length != 1 then
83 # Without args, list `ok_will_merge`
84 var x = curl.get_and_check("https://api.github.com/repos/privat/nit/issues?labels=ok_will_merge")
85 for y in x.json_as_a do
86 var number = y.json_as_map["number"].as(Int)
87 var pr = curl.getpr(number)
88 end
89 else
90 # With a arg, merge the PR
91 var number = args.first.to_i
92 var pr = curl.getpr(number)
93 var revs = curl.getrev(pr)
94
95 var mergemsg = new Template
96 mergemsg.add "Merge: {pr["title"]}\n\n"
97 mergemsg.add "{pr["body"]}\n\n"
98 mergemsg.add "Pull-Request: #{pr["number"]}\n"
99 for r in revs do
100 mergemsg.add "Reviewed-by: {r}\n"
101 end
102 mergemsg.write_to_file("mergemsg")
103
104 var sha = pr["head"].json_as_map["sha"].as(String)
105 if system("git show -s --pretty=format:%h {sha}") != 0 then
106 print "Commit {sha} not in local repository; did you fetch github?"
107 return
108 end
109 if system("git merge --no-commit {sha}") != 0 then
110 print "Problem during merge... Let's do the commit manually."
111 return
112 end
113 system("git commit -F mergemsg")
114 print "The merge is made"
115 end
116