Created
June 20, 2013 14:14
-
-
Save schocco/5823073 to your computer and use it in GitHub Desktop.
quick and dirty script to transfer passed proposals from the iuf committee to a github repository. Requires python 2.x
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# -*- coding: <utf-8> -*- | |
import getopt | |
import sys | |
import urllib2 | |
from urllib2 import URLError, HTTPError | |
import base64 | |
import json | |
import getpass | |
from BeautifulSoup import BeautifulSoup, Tag | |
import HTMLParser | |
html_parser = HTMLParser.HTMLParser() | |
class Issue(object): | |
''' | |
Example: | |
"title": "Found a bug", | |
"body": "I'm having a problem with this.", | |
"assignee": "octocat", | |
"milestone": 1, | |
"labels": [ | |
"Label1", | |
"Label2" | |
] | |
''' | |
def __init__(self, title, body, *args, **kwargs): | |
self.title = html_parser.unescape(title) | |
self.body = html_parser.unescape(body) | |
self.labels = [] | |
self.milestone = None | |
def getHTML(url): | |
'''return html sources of a webpage''' | |
f = urllib2.urlopen(url) | |
html = f.read() | |
return html | |
def parseProposals(html): | |
''' | |
given the html parse it and extract proposal names, ids and text. | |
Return a list of proposal objects. | |
''' | |
soup = BeautifulSoup(html) | |
proposals = soup.findAll('h2') | |
issues = [] | |
for section in proposals: #proposal titles are in h2 headings | |
propnum, title = section.text.split(":", 1) | |
propurl = "http://rulebook.unicycling.org/proposals/%s" % propnum.split()[-1] | |
title = "Apply proposal: %s" % title | |
issue = Issue(title, "%s (see: %s)\n" % (propnum.strip(), propurl)) | |
issue.labels.append("committeeproposal") | |
#FIXME: miletsone number should be retrieved dynamically | |
issue.milestone = 1 | |
issues.append(issue) | |
#get first proposal node below the h2 heading | |
proposal = None | |
h3s = section.findNextSiblings("h3") | |
nextNode = h3s[3] # the proposal heading | |
while True: | |
tag_name = "" | |
nextNode = nextNode.nextSibling | |
try: | |
tag_name = nextNode.name | |
except AttributeError: | |
tag_name = "" | |
continue | |
if tag_name == "p": | |
contents = nextNode.contents | |
# join all text elements separated by newlines, ignore Tags | |
text = "\n".join([item for item in contents if not isinstance(item, Tag)]) | |
issue.body += html_parser.unescape("\n%s" % text) | |
else: | |
break | |
return issues | |
def postIssue(issue, destination, user, password): | |
'''posts the issue object serialized to json via the github api v3''' | |
headers = { | |
'Connection': 'keep-alive', | |
'User-Agent': 'IUF', | |
'Content-type': 'application/json; charset=UTF-8', | |
'Accept': 'application/json, */*', | |
} | |
data = json.dumps(issue.__dict__) | |
base64str = base64.encodestring("%s:%s" % (user, password)).replace("\n", "") | |
req = urllib2.Request(destination, data, headers) | |
req.add_header("Authorization", "Basic %s" % base64str) | |
try: | |
response = urllib2.urlopen(req) | |
return True | |
except URLError as err: | |
print err.reason | |
return False | |
except HTTPError as err: | |
print err.code | |
print err.reason | |
return False | |
def main(argv): | |
#url with passed proposals | |
url = "http://rulebook.unicycling.org/proposals/passed" | |
#get destination repository | |
destination = raw_input("destination repository in the form 'user/repository': ") | |
destination = 'https://api.github.com/repos/%s/issues' % destination | |
print destination | |
#get credentials | |
user = raw_input("username on github: ") | |
print "enter password for %s" % user | |
pw = getpass.getpass() | |
#parse proposals and post issues | |
html = getHTML(url) | |
issues = parseProposals(html) | |
failed = [] | |
for issue in issues: | |
success = postIssue(issue, destination, user, pw) | |
if(not success): | |
failed.append(issue) | |
if(len(failed) > 0): | |
print "The following proposals could not be added as issues:" | |
for issue in failed: | |
print failed.title | |
if __name__ == "__main__": | |
main(sys.argv[1:]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment