|
#!/usr/bin/env python |
|
import os |
|
import argparse |
|
import re |
|
from datetime import datetime, timedelta |
|
from pygithub3 import Github |
|
import requests |
|
from time import sleep |
|
|
|
# Milestones are preceded by a '#' |
|
MILESTONE_RE = re.compile('^\s*#\s*(?P<text>.+)\s*$') |
|
# Issues are preceded by a '*' or '-' |
|
ISSUE_RE = re.compile('^\s*(-|\*)\s*(?P<text>.+)\s*$') |
|
# Every Friday |
|
REVIEW_DOW = 4 |
|
# 1:30pm EST |
|
REVIEW_TIME = '18:30' |
|
|
|
gh = Github(token=os.environ['GITHUB_API_TOKEN']) |
|
|
|
CACHE = dict() |
|
|
|
|
|
def main(): |
|
parser = argparse.ArgumentParser(description='Load issues into github') |
|
parser.add_argument('ticket_file', |
|
help='file with tickets') |
|
parser.add_argument('project', |
|
help='GitHub project (EX: account/project)') |
|
|
|
args = parser.parse_args() |
|
|
|
CACHE['account'], CACHE['project'] = args.project.strip().split('/') |
|
|
|
milestones = list() |
|
milestone = None |
|
issues = list() |
|
with open(args.ticket_file) as f: |
|
for line in f.readlines(): |
|
milestone_match = MILESTONE_RE.match(line) |
|
issue_match = ISSUE_RE.match(line) |
|
if milestone_match: |
|
milestone = { |
|
'title': milestone_match.group('text'), |
|
'due_on': review_day(len(milestones)).isoformat() + 'Z', |
|
'issues': list() |
|
} |
|
milestones.append(milestone) |
|
elif issue_match: |
|
issues.append(issue_match.group('text')) |
|
if milestone: |
|
milestone['issues'].append( |
|
issue_match.group('text')) |
|
|
|
try: |
|
if milestones: |
|
print "I haz %i milestones and %i issues" % ( |
|
len(milestones), len(issues)) |
|
create_milestones(milestones) |
|
elif issues: |
|
print "I haz %i issues" % len(issues) |
|
create_issues(issues) |
|
except requests.exceptions.HTTPError, ex: |
|
print ex.response.body |
|
|
|
|
|
def create_milestones(milestones): |
|
milestones.reverse() |
|
while len(milestones) > 0: |
|
milestone = milestones.pop() |
|
issues = milestone.pop('issues') |
|
milestone_id = get_or_create_milestone(milestone) |
|
create_issues(issues, milestone_id=milestone_id) |
|
|
|
|
|
def create_issues(issues, milestone_id=None): |
|
issues.reverse() |
|
while len(issues) > 0: |
|
issue = {'title': issues.pop()} |
|
if milestone_id: |
|
issue['milestone'] = int(milestone_id) |
|
get_or_create_issue(issue) |
|
|
|
|
|
def get_or_create_milestone(data): |
|
if 'milestones' not in CACHE: |
|
CACHE['milestones'] = gh.issues.milestones.list(CACHE['account'], CACHE['project']).all() |
|
sleep(1) |
|
|
|
for m in CACHE['milestones']: |
|
if m.title == data['title']: |
|
print "Found milestone \"%s\"" % data['title'] |
|
return m.number |
|
|
|
print "Create milestone \"%s\"" % data['title'] |
|
resp = gh.issues.milestones.create(data, CACHE['account'], CACHE['project']) |
|
sleep(1) |
|
CACHE['milestones'].append(resp) |
|
return resp.number |
|
|
|
|
|
def get_or_create_issue(data): |
|
if 'issues' not in CACHE: |
|
CACHE['issues'] = gh.issues.list_by_repo(CACHE['account'], CACHE['project']).all() |
|
sleep(1) |
|
|
|
for m in CACHE['issues']: |
|
if m.title == data['title']: |
|
print "Already created issue \"%s\"" % data['title'] |
|
return m.number |
|
|
|
print "Create issue \"%s\"" % data['title'] |
|
resp = gh.issues.create(data, CACHE['account'], CACHE['project']) |
|
sleep(1) |
|
CACHE['issues'].append(resp) |
|
return resp.number |
|
|
|
|
|
def review_day(weeks_from_now): |
|
now = datetime.utcnow() |
|
|
|
if now.weekday() >= REVIEW_DOW: |
|
next_day = now + timedelta(days=(7 - now.weekday() - REVIEW_DOW)) |
|
else: |
|
next_day = now + timedelta(days=(REVIEW_DOW - now.weekday())) |
|
|
|
args = list(next_day.timetuple())[:-2] |
|
(args[3], args[4]) = map(lambda x: int(x), REVIEW_TIME.split(':')) |
|
args[5] = 0 |
|
due_date = datetime(*args) |
|
|
|
return due_date + timedelta(weeks=weeks_from_now) |
|
|
|
|
|
if __name__ == '__main__': |
|
main() |