##// END OF EJS Templates
some fixs
Matthias BUSSONNIER -
Show More
@@ -1,96 +1,104 b''
1 1 """Functions for Github authorisation."""
2 2 from __future__ import print_function
3 3
4 4 try:
5 5 input = raw_input
6 6 except NameError:
7 7 pass
8 8
9 9 import requests
10 10 import getpass
11 11 import json
12 12
13 13 # Keyring stores passwords by a 'username', but we're not storing a username and
14 14 # password
15 15 fake_username = 'ipython_tools'
16 16
17 17 token = None
18 18 def get_auth_token():
19 19 global token
20 20
21 21 if token is not None:
22 22 return token
23 23
24 24 import keyring
25 25 token = keyring.get_password('github', fake_username)
26 26 if token is not None:
27 27 return token
28 28
29 29 print("Please enter your github username and password. These are not "
30 30 "stored, only used to get an oAuth token. You can revoke this at "
31 31 "any time on Github.")
32 32 user = input("Username: ")
33 33 pw = getpass.getpass("Password: ")
34 34
35 35 auth_request = {
36 36 "scopes": [
37 37 "public_repo",
38 38 "gist"
39 39 ],
40 40 "note": "IPython tools",
41 41 "note_url": "https://github.com/ipython/ipython/tree/master/tools",
42 42 }
43 43 response = requests.post('https://api.github.com/authorizations',
44 44 auth=(user, pw), data=json.dumps(auth_request))
45 45 response.raise_for_status()
46 46 token = json.loads(response.text)['token']
47 47 keyring.set_password('github', fake_username, token)
48 48 return token
49 49
50 50 def make_auth_header():
51 51 return {'Authorization': 'token ' + get_auth_token()}
52 52
53 53 def post_issue_comment(project, num, body):
54 54 url = 'https://api.github.com/repos/{project}/issues/{num}/comments'.format(project=project, num=num)
55 55 payload = json.dumps({'body': body})
56 56 r = requests.post(url, data=payload, headers=make_auth_header())
57 57
58 58 def post_gist(content, description='', filename='file', auth=False):
59 59 """Post some text to a Gist, and return the URL."""
60 60 post_data = json.dumps({
61 61 "description": description,
62 62 "public": True,
63 63 "files": {
64 64 filename: {
65 65 "content": content
66 66 }
67 67 }
68 68 }).encode('utf-8')
69 69
70 70 headers = make_auth_header() if auth else {}
71 71 response = requests.post("https://api.github.com/gists", data=post_data, headers=headers)
72 72 response.raise_for_status()
73 73 response_data = json.loads(response.text)
74 74 return response_data['html_url']
75 75
76 def get_pull_request(project, num, httpv2=False):
77 if httpv2 :
76 def get_pull_request(project, num, github_api=3):
77 """get pull request info by number
78
79 github_api : version of github api to use
80 """
81 if github_api==2 :
78 82 url = "http://github.com/api/v2/json/pulls/{project}/{num}".format(project=project, num=num)
79 else:
83 elif github_api == 3:
80 84 url = "https://api.github.com/repos/{project}/pulls/{num}".format(project=project, num=num)
81 85 response = requests.get(url)
82 86 response.raise_for_status()
83 87 if httpv2 :
84 88 return json.loads(response.text)['pull']
85 89 return json.loads(response.text)
86 90
87 def get_pulls_list(project,httpv2=False):
88 if not httpv2 :
91 def get_pulls_list(project, github_api=3):
92 """get pull request list
93
94 github_api : version of github api to use
95 """
96 if github_api == 3 :
89 97 url = "https://api.github.com/repos/{project}/pulls".format(project=project)
90 98 else :
91 99 url = "http://github.com/api/v2/json/pulls/{project}".format(project=project)
92 100 response = requests.get(url)
93 101 response.raise_for_status()
94 102 if httpv2 :
95 103 return json.loads(response.text)['pulls']
96 104 return json.loads(response.text)
@@ -1,117 +1,136 b''
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """
4 4 Usage:
5 python test_pr.py 1657
5 python git-mpr.py -m 1657
6 6 """
7 7 from __future__ import print_function
8 8
9 9 import re
10 10 import requests
11 import argparse
11 12 from subprocess import call, check_call, check_output, CalledProcessError
12 13 import sys
13 14
14 15 import gh_api
15 16
16 17 ipy_repository = 'git://github.com/ipython/ipython.git'
17 18 gh_project="ipython/ipython"
18 19 not_merged={}
19 20
20 def get_branch(repo, branch, owner, mergeable):
21
22 def merge_branch(repo, branch, owner, mergeable):
23 """try to merge the givent branch into the current one
24
25 If something does not goes smoothly, merge is aborted
26
27 Returns True if merge sucessfull, False otherwise
28 """
21 29 merged_branch = "%s-%s" % (owner, branch)
22 30 # Delete the branch first
23 31 try :
24 32 check_call(['git', 'pull','--no-edit',repo, branch])
25 33 except CalledProcessError :
26 34 check_call(['git', 'merge', '--abort'])
27 35 return False
28 36 return True
29 37
30 def merge_pr(num,httpv2=False):
38
39 def merge_pr(num,github_api=3):
40 """ try to merge the branch of PR `num` into current branch
41
42 github_api : use github api v2 (to bypass https and issues with proxy) to find the
43 remote branch that should be merged by it's number
44 """
31 45 # Get Github authorisation first, so that the user is prompted straight away
32 46 # if their login is needed.
33 47
34 pr = gh_api.get_pull_request(gh_project, num, httpv2)
35 if(httpv2):
48 pr = gh_api.get_pull_request(gh_project, num, github_api)
49 if github_api == 2:
36 50 repo = pr['head']['repository']['url']
37 owner=pr['head']['user']['name'],
38 else :
51 owner = pr['head']['user']['name']
52 elif github_api == 2 :
39 53 repo=pr['head']['repo']['clone_url']
40 owner=pr['head']['repo']['owner']['login'],
54 owner = pr['head']['repo']['owner']['login']
41 55
42 56 branch=pr['head']['ref']
43 mergeable = get_branch(repo=repo,
57 mergeable = merge_branch(repo=repo,
44 58 branch=branch,
45 59 owner=owner,
46 60 mergeable=pr['mergeable'],
47 61 )
48 62 if not mergeable :
49 63 cmd = "git pull "+repo+" "+branch
50 64 not_merged[str(num)]=cmd
51 65 print("==============================================================================")
52 66 print("Something went wrong merging this branch, you can try it manually by runngin :")
53 67 print(cmd)
54 68 print("==============================================================================")
55 69
56 70
57
58 if __name__ == '__main__':
59 import argparse
71 def main(*args):
60 72 parser = argparse.ArgumentParser(
61 73 description="""
62 74 Merge (one|many) github pull request by their number.\
63 75
64 76 If pull request can't be merge as is, cancel merge,
65 77 and continue to the next if any.
66 78 """
67 79 )
68 parser.add_argument('-v2','--githubapiv2', action='store_const', const=True)
80 parser.add_argument('-v2','--githubapiv2', action='store_const', const=2)
69 81
70 82 grp = parser.add_mutually_exclusive_group()
71 83 grp.add_argument(
72 84 '-l',
73 85 '--list',
74 86 action='store_const',
75 87 const=True,
76 88 help='list PR, their number and their mergeability')
77 89 grp.add_argument('-a',
78 90 '--merge-all',
79 91 action='store_const',
80 92 const=True ,
81 93 help='try to merge as many PR as possible, one by one')
82 94 grp.add_argument('-m',
83 95 '--merge',
84 96 type=int,
85 97 help="The pull request numbers",
86 98 nargs='*',
87 99 metavar='pr-number')
88 100 not_merged = {};
89 101 args = parser.parse_args()
90 ghv2 = args.githubapiv2
102 if args.githubapiv2 == 2 :
103 github_api = 2
104 else :
105 github_api = 3
106
91 107 if(args.list):
92 pr_list = gh_api.get_pulls_list(gh_project, ghv2)
108 pr_list = gh_api.get_pulls_list(gh_project, github_api)
93 109 for pr in pr_list :
94 mergeable = gh_api.get_pull_request(gh_project, pr['number'],httpv2=ghv2)['mergeable']
110 mergeable = gh_api.get_pull_request(gh_project, pr['number'],github_api=github_api)['mergeable']
95 111
96 112 ismgb = u"√" if mergeable else " "
97 113 print(u"* #{number} [{ismgb}]: {title}".format(
98 114 number=pr['number'],
99 115 title=pr['title'],
100 116 ismgb=ismgb))
101 117
102 118 if(args.merge_all):
103 119 pr_list = gh_api.get_pulls_list(gh_project)
104 120 for pr in pr_list :
105 121 merge_pr(pr['number'])
106 122
107 123
108 124 elif args.merge:
109 125 for num in args.merge :
110 merge_pr(num,httpv2=ghv2)
126 merge_pr(num, github_api=github_api)
111 127
112 128 if not_merged :
113 129 print('*************************************************************************************')
114 130 print('the following branch have not been merged automatically, considere doing it by hand :')
115 131 for num,cmd in not_merged.items() :
116 132 print( "PR {num}: {cmd}".format(num=num,cmd=cmd))
117 133 print('*************************************************************************************')
134
135 if __name__ == '__main__':
136 main()
General Comments 0
You need to be logged in to leave comments. Login now