for name in (trac_labels - gh_labels):
        try:
            color = trac_label_colors[trac_label_types[name]][name]
        except KeyError:
            color = 'e8e8e8'
        github.labels(data={
            'name': name,
            'color': color,
        })

    # == Milestone Migration ==
    # Get any existing GitHub milestones so we can merge Trac into them.
    # We need to reference them by numeric ID in tickets.
    logging.info("Getting existing GitHub milestones...")
    milestone_id = {}
    for m in github.milestones():
        milestone_id[m['title']] = m['number']
        logging.debug("milestone (open)   title={0}".format(m['title']))
    # API returns only 'open' issues by default, have to ask for closed like:
    # curl -u 'USER:PASS' https://api.github.com/repos/USERNAME/REPONAME/milestones?state=closed
    for m in github.milestones(query='state=closed'):
        milestone_id[m['title']] = m['number']
        logging.debug("milestone (closed) title={0}".format(m['title']))

    # We have no way to set the milestone closed date in GitHub.
    # The 'due' and 'completed' are long ints representing datetimes.
    logging.info("Migrating Trac milestones to GitHub...")
    milestones = trac.sql('SELECT name, description, due, completed FROM milestone')
    for name, description, due, completed in milestones:
        name = name.strip()
        if name in milestone_id:
for name, description, due, completed in milestones:
    name = name.strip()
    logging.debug("milestone name=%s due=%s completed=%s" % (name, due, completed))
    if name and name not in milestone_id:
        if completed:
            state = 'closed'
        else:
            state = 'open'
        milestone = {'title': name,
                     'state': state,
                     'description': description,
                     }
        if due:
            milestone['due_on'] = epoch_to_iso(due)
        logging.debug("milestone: %s" % milestone)
        gh_milestone = github.milestones(id_ = max(chain([0], milestone_id.values())) + 1, data=milestone)
        milestone_id[name] = gh_milestone['number']

# Copy Trac tickets to GitHub issues, keyed to milestones above

tickets = trac.sql('SELECT id, summary, description , owner, milestone, component, status, time, changetime, reporter, keywords, severity, priority, resolution, type FROM ticket ORDER BY id') # LIMIT 5
for tid, summary, description, owner, milestone, component, status, \
         created_at, updated_at, reporter, keywords, severity, priority, resolution, type in tickets:
    if options.component and options.component != component:
        continue
    logging.info("Ticket %d: %s" % (tid, summary))
    if description:
        description = description.strip()
    if milestone:
        milestone = milestone.strip()
    issue = {'title': summary}