Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 205 lines (144 sloc) 5.895 kb
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
1 #!/usr/bin/env python
2
3 import httplib, mimetools, re, svn.core, svn.fs, svn.repos, sys, urllib, urlparse
4 from lxml.etree import ElementTree, HTMLParser
5 from lxml.cssselect import CSSSelector
6
7 # Create HTTP connection from URL scheme, host, and port
8 def http_connection(url):
9 components = list(urlparse.urlparse(url))
10
11 if 'https' == components[0]:
12 return httplib.HTTPSConnection(components[1])
13
14 return httplib.HTTPConnection(components[1])
15
16 # Depending on the method, add params to the URL or the request body and set
17 # any headers. An HTTP request object would be nice here, but need to remember
18 # this is just a quick script to close Google project hosting issues : )
19 def encode_params(method, url, params):
20 body = None
21 headers = {}
22
23 if 'POST' == method.upper():
24 headers['Content-Type'] = 'application/x-www-form-urlencoded'
25 body = urllib.urlencode(params)
26
27 else:
28 components = list(urlparse.urlparse(url))
29 components[4] = urllib.urlencode(params)
30 url = urlparse.urlunparse(components)
31
32 return url, headers, body
33
b2d8a88b »
2010-05-29 Refactor form action and enctype handling into encode_form(), for reuse
34 def encode_form(method, url, params, form):
35 url = urlparse.urljoin(url, form.get('action'))
36
37 url, headers, body = encode_params(method, url, params)
38
39 # Encode multipart/form-data
40 if 'multipart/form-data' == form.get('enctype'):
41 boundary = mimetools.choose_boundary()
42
43 headers['Content-Type'] = 'multipart/form-data; boundary=' + boundary
44
45 components = []
46 for name, value in params:
47 components.append('--' + boundary)
48 components.append('Content-Disposition: form-data; name="' + name + '"')
49 components.append('')
50 components.append(value)
51
52 components.append('--' + boundary + '--')
53
54 body = '\r\n'.join(components)
55
56 return url, headers, body
57
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
58 # Check arguments and print usage
59 if 6 != len(sys.argv):
60 print """
61 %s requires five arguments,
62
63 [1] REPOS-PATH (the path to the repository)
64 [2] REV (the number of the revision)
65 [3] EMAIL (the Google account email)
66 [4] PASSWORD (the Google account password)
67 [5] PROJECT (the Google project hosting project)
68 """ % sys.argv[0]
69
70 sys.exit(1)
71
72 # Open Subversion repository
73 repos = svn.repos.open(sys.argv[1])
74 fs = svn.repos.fs(repos)
75
76 # Get commit log
77 log = svn.fs.revision_prop(fs, int(sys.argv[2]), svn.core.SVN_PROP_REVISION_LOG)
78
0f7045ee »
2009-08-26 Add examples of magic words to comment
79 # Find magic words in commit log, e.g.
80 #
81 # * Closes issue 123
82 # * Fixes issue 123
83 # * Closes issues 123 and 321
84 # * Closes issue 123 and 321
85 # NOT Closes issues 123
86 # * Closes issues 123, 321, and 456
87 # * Closes issues 123, 321 and 456
88 # * Closes issue 123 and issue 321
89 # NOT Closes issues 123 and issue 321
90 # TODO Closes issues 123, 321, and issue 456
222e533f »
2010-07-22 Cosmetic change
91
c86c0f40 »
2009-09-06 Fix regular expression, s/+/*, or "fixes issue 123 and issue 321" wor…
92 matches = re.findall('(?:closes|fixes)\\s+issue(?:s?\\s+#?\\d+(?:,?\\s+(?:(?:&|and)\\s+)?#?\\d+)+|\\s+#?\\d+(?:,?\\s+(?:(?:&|and)\\s+)?issue\s+#?\\d+)*)', log, re.I)
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
93
94 if matches:
95
96 # Login to Google account
07c95601 »
2010-05-29 Google login now needs cookie and XSRF params
97 method = 'GET'
3a3c4a01 »
2010-06-02 Google login now uses different URL
98 url = 'https://www.google.com/accounts/ServiceLogin'
99 params = [('service', 'code')]
100
101 url, headers, body = encode_params(method, url, params)
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
102
103 conn = http_connection(url)
07c95601 »
2010-05-29 Google login now needs cookie and XSRF params
104
3a3c4a01 »
2010-06-02 Google login now uses different URL
105 conn.request(method, url, body, headers)
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
106 response = conn.getresponse()
107
108 # Get cookie
109 cookie = response.getheader('Set-Cookie')
110
07c95601 »
2010-05-29 Google login now needs cookie and XSRF params
111 parser = HTMLParser()
112 tree = ElementTree()
113
114 tree.parse(response, parser)
115
116 sel = CSSSelector('#gaia_loginform')
117 form = sel(tree)[0]
118
119 # Submit #gaia_loginform
120 if form.get('method'):
50312c09 »
2010-06-02 Handle <form/> @method attribute more robustly, make uppercase
121 method = form.get('method').upper()
07c95601 »
2010-05-29 Google login now needs cookie and XSRF params
122
123 params = []
124
125 # Get params from form inputs. Override email and password.
126 sel = CSSSelector('input, textarea')
127 for input in sel(form):
128 if 'Email' == input.get('name'):
129 params.append(('Email', sys.argv[3]))
130
131 elif 'Passwd' == input.get('name'):
132 params.append(('Passwd', sys.argv[4]))
133
134 else:
135 params.append((input.get('name'), input.get('value')))
136
137 url, headers, body = encode_form(method, url, params, form)
138
139 headers['Cookie'] = cookie
140
141 conn.request(method, url, body, headers)
142 response = conn.getresponse()
143
a80fa977 »
2010-06-02 Google login now needs to update cookie after form submission
144 # Get cookie
145 cookie = response.getheader('Set-Cookie')
146
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
147 # Close Google project hosting issues
148 url = 'http://code.google.com/p/' + sys.argv[5] + '/issues/detail'
149
150 # Close issues with one connection. Add headers to make it persistent?
151 conn = http_connection(url)
152
153 for match in matches:
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
154 for match in re.findall('\\d+', match, re.I):
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
155
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
156 # Get #makechages form
157 method = 'GET'
158 url = 'http://code.google.com/p/' + sys.argv[5] + '/issues/detail'
159 params = [('id', match)]
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
160
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
161 url, headers, body = encode_params(method, url, params)
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
162
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
163 headers['Cookie'] = cookie
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
164
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
165 conn.request(method, url, body, headers)
166 response = conn.getresponse()
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
167
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
168 tree.parse(response, parser)
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
169
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
170 sel = CSSSelector('#makechanges form')
171 form = sel(tree)[0]
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
172
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
173 # Submit #makechanges form
174 if form.get('method'):
50312c09 »
2010-06-02 Handle <form/> @method attribute more robustly, make uppercase
175 method = form.get('method').upper()
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
176
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
177 params = []
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
178
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
179 # Get params from form inputs. Override comment and status.
180 sel = CSSSelector('input, textarea')
181 for input in sel(form):
182 if 'comment' == input.get('name'):
5b982426 »
2010-06-02 s/revision/commit
183 params.append(('comment', 'Fixed in commit ' + sys.argv[2]))
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
184
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
185 elif 'status' == input.get('name'):
186 params.append(('status', 'Fixed'))
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
187
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
188 else:
189 params.append((input.get('name'), input.get('value')))
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
190
b2d8a88b »
2010-05-29 Refactor form action and enctype handling into encode_form(), for reuse
191 url, headers, body = encode_form(method, url, params, form)
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
192
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
193 headers['Cookie'] = cookie
1bb4d774 »
2009-06-23 Add post-commit hook to close Google project hosting issues based on …
194
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
195 # Close issue
196 conn.request(method, url, body, headers)
9953a533 »
2009-08-25 Fix issue closing multiple issues by adding call to conn.getresponse(…
197
198 # Note that you must have read the whole response before you can send a
199 # new request to the server. Actually, you must call getresponse()
200 # before you can send a new request to the server and you must have read
201 # the whole response before you can call getresponse() again : P
202 conn.getresponse().read()
203
6329d506 »
2009-08-25 Update regex for magic words to support lists of issues, e.g. "Closes…
204 print 'Closed issue ' + match + '.'
Something went wrong with that request. Please try again.