Skip to content

Instantly share code, notes, and snippets.

@schocco
Created June 20, 2013 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schocco/5823073 to your computer and use it in GitHub Desktop.
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
#!/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