##// END OF EJS Templates
enable posting GitHub downloads
MinRK -
Show More
@@ -1,104 +1,204 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 import os
10
9 11 import requests
10 12 import getpass
11 13 import json
12 14
13 15 # Keyring stores passwords by a 'username', but we're not storing a username and
14 16 # password
15 17 fake_username = 'ipython_tools'
16 18
17 19 token = None
18 20 def get_auth_token():
19 21 global token
20 22
21 23 if token is not None:
22 24 return token
23 25
24 26 import keyring
25 27 token = keyring.get_password('github', fake_username)
26 28 if token is not None:
27 29 return token
28 30
29 31 print("Please enter your github username and password. These are not "
30 32 "stored, only used to get an oAuth token. You can revoke this at "
31 33 "any time on Github.")
32 34 user = input("Username: ")
33 35 pw = getpass.getpass("Password: ")
34 36
35 37 auth_request = {
36 38 "scopes": [
37 39 "public_repo",
38 40 "gist"
39 41 ],
40 42 "note": "IPython tools",
41 43 "note_url": "https://github.com/ipython/ipython/tree/master/tools",
42 44 }
43 45 response = requests.post('https://api.github.com/authorizations',
44 46 auth=(user, pw), data=json.dumps(auth_request))
45 47 response.raise_for_status()
46 48 token = json.loads(response.text)['token']
47 49 keyring.set_password('github', fake_username, token)
48 50 return token
49 51
50 52 def make_auth_header():
51 53 return {'Authorization': 'token ' + get_auth_token()}
52 54
53 55 def post_issue_comment(project, num, body):
54 56 url = 'https://api.github.com/repos/{project}/issues/{num}/comments'.format(project=project, num=num)
55 57 payload = json.dumps({'body': body})
56 58 r = requests.post(url, data=payload, headers=make_auth_header())
57 59
58 60 def post_gist(content, description='', filename='file', auth=False):
59 61 """Post some text to a Gist, and return the URL."""
60 62 post_data = json.dumps({
61 63 "description": description,
62 64 "public": True,
63 65 "files": {
64 66 filename: {
65 67 "content": content
66 68 }
67 69 }
68 70 }).encode('utf-8')
69 71
70 72 headers = make_auth_header() if auth else {}
71 73 response = requests.post("https://api.github.com/gists", data=post_data, headers=headers)
72 74 response.raise_for_status()
73 75 response_data = json.loads(response.text)
74 76 return response_data['html_url']
75 77
76 78 def get_pull_request(project, num, github_api=3):
77 79 """get pull request info by number
78 80
79 81 github_api : version of github api to use
80 82 """
81 83 if github_api==2 :
82 84 url = "http://github.com/api/v2/json/pulls/{project}/{num}".format(project=project, num=num)
83 85 elif github_api == 3:
84 86 url = "https://api.github.com/repos/{project}/pulls/{num}".format(project=project, num=num)
85 87 response = requests.get(url)
86 88 response.raise_for_status()
87 89 if github_api == 2 :
88 90 return json.loads(response.text)['pull']
89 91 return json.loads(response.text)
90 92
91 93 def get_pulls_list(project, github_api=3):
92 94 """get pull request list
93 95
94 96 github_api : version of github api to use
95 97 """
96 98 if github_api == 3 :
97 99 url = "https://api.github.com/repos/{project}/pulls".format(project=project)
98 100 else :
99 101 url = "http://github.com/api/v2/json/pulls/{project}".format(project=project)
100 102 response = requests.get(url)
101 103 response.raise_for_status()
102 104 if github_api == 2 :
103 105 return json.loads(response.text)['pulls']
104 106 return json.loads(response.text)
107
108 # encode_multipart_formdata is from urllib3.filepost
109 # The only change is to iter_fields, to enforce S3's required key ordering
110
111 def iter_fields(fields):
112 fields = fields.copy()
113 for key in ('key', 'acl', 'Filename', 'success_action_status', 'AWSAccessKeyId',
114 'Policy', 'Signature', 'Content-Type', 'file'):
115 yield (key, fields.pop(key))
116 for (k,v) in fields.items():
117 yield k,v
118
119 def encode_multipart_formdata(fields, boundary=None):
120 """
121 Encode a dictionary of ``fields`` using the multipart/form-data mime format.
122
123 :param fields:
124 Dictionary of fields or list of (key, value) field tuples. The key is
125 treated as the field name, and the value as the body of the form-data
126 bytes. If the value is a tuple of two elements, then the first element
127 is treated as the filename of the form-data section.
128
129 Field names and filenames must be unicode.
130
131 :param boundary:
132 If not specified, then a random boundary will be generated using
133 :func:`mimetools.choose_boundary`.
134 """
135 # copy requests imports in here:
136 from io import BytesIO
137 from requests.packages.urllib3.filepost import (
138 choose_boundary, six, writer, b, get_content_type
139 )
140 body = BytesIO()
141 if boundary is None:
142 boundary = choose_boundary()
143
144 for fieldname, value in iter_fields(fields):
145 body.write(b('--%s\r\n' % (boundary)))
146
147 if isinstance(value, tuple):
148 filename, data = value
149 writer(body).write('Content-Disposition: form-data; name="%s"; '
150 'filename="%s"\r\n' % (fieldname, filename))
151 body.write(b('Content-Type: %s\r\n\r\n' %
152 (get_content_type(filename))))
153 else:
154 data = value
155 writer(body).write('Content-Disposition: form-data; name="%s"\r\n'
156 % (fieldname))
157 body.write(b'Content-Type: text/plain\r\n\r\n')
158
159 if isinstance(data, int):
160 data = str(data) # Backwards compatibility
161 if isinstance(data, six.text_type):
162 writer(body).write(data)
163 else:
164 body.write(data)
165
166 body.write(b'\r\n')
167
168 body.write(b('--%s--\r\n' % (boundary)))
169
170 content_type = b('multipart/form-data; boundary=%s' % boundary)
171
172 return body.getvalue(), content_type
173
174
175 def post_download(project, filename, name=None, description=""):
176 """Upload a file to the GitHub downloads area"""
177 if name is None:
178 name = os.path.basename(filename)
179 with open(filename, 'rb') as f:
180 filedata = f.read()
181
182 url = "https://api.github.com/repos/{project}/downloads".format(project=project)
183
184 payload = json.dumps(dict(name=name, size=len(filedata),
185 description=description))
186 response = requests.post(url, data=payload, headers=make_auth_header())
187 response.raise_for_status()
188 reply = json.loads(response.content)
189 s3_url = reply['s3_url']
190
191 fields = dict(
192 key=reply['path'],
193 acl=reply['acl'],
194 success_action_status=201,
195 Filename=reply['name'],
196 AWSAccessKeyId=reply['accesskeyid'],
197 Policy=reply['policy'],
198 Signature=reply['signature'],
199 file=(reply['name'], filedata),
200 )
201 fields['Content-Type'] = reply['mime_type']
202 data, content_type = encode_multipart_formdata(fields)
203 s3r = requests.post(s3_url, data=data, headers={'Content-Type': content_type})
204 return s3r
General Comments 0
You need to be logged in to leave comments. Login now