Exemple #1
0
def jira_add_team_cards(team, filter_id):
    from kardboard.tickethelpers import JIRAHelper
    from kardboard.models import States
    from kardboard.app import app

    statsd_conn = app.statsd.get_client('tasks.jira_add_team_cards')

    counter = statsd_conn.get_client(class_=statsd.Counter)
    total_timer = statsd_conn.get_client(class_=statsd.Timer)
    total_timer.start()

    logger = jira_add_team_cards.get_logger()
    logger.info("JIRA BACKLOG SYNC %s: %s" % (team, filter_id))
    states = States()
    helper = JIRAHelper(app.config, None)
    issues = helper.service.getIssuesFromFilter(helper.auth, filter_id)
    for issue in issues:
        if Kard.objects.filter(key=issue.key):
            # Card exists, pass
            pass
        else:
            logger.info("JIRA BACKLOGGING %s: %s" % (team, issue.key))
            defaults = {
                'key': issue.key,
                'title': issue.summary,
                'backlog_date': datetime.datetime.now(),
                'team': team,
                'state': states.backlog,
            }
            c = Kard(**defaults)
            c.ticket_system.actually_update(issue)
            c.save()
            counter += 1

    total_timer.stop()
Exemple #2
0
def dashboard(year=None, month=None, day=None):
    date = kardboard.util.now()
    now = kardboard.util.now()
    scope = "current"

    if year:
        date = date.replace(year=year)
        scope = "year"
    if month:
        date = date.replace(month=month)
        scope = "month"
        start, end = month_range(date)
        date = end
    if day:
        date = date.replace(day=day)
        scope = "day"

    date = make_end_date(date=date)

    wip_cards = list(Kard.in_progress(date))
    wip_cards = sorted(wip_cards, key=lambda c: c.current_cycle_time(date))
    wip_cards.reverse()

    backlog_cards = Kard.backlogged(date).order_by("key")

    metrics = [
        {"Ave. Cycle Time": Kard.objects.moving_cycle_time(year=date.year, month=date.month, day=date.day)},
        {"Done this week": Kard.objects.done_in_week(year=date.year, month=date.month, day=date.day).count()},
        {"Done this month": Kard.objects.done_in_month(year=date.year, month=date.month, day=date.day).count()},
        {"On the board": len(wip_cards) + backlog_cards.count()},
    ]

    title = "Dashboard"
    if scope == "year":
        title += " for %s"
    if scope == "month":
        title += " for %s/%s" % (date.month, date.year)
    if scope == "day" or scope == "current":
        title += " for %s/%s/%s" % (date.month, date.day, date.year)

    forward_date = date + relativedelta.relativedelta(days=1)
    back_date = date - relativedelta.relativedelta(days=1)

    if forward_date > now:
        forward_date = None

    context = {
        "forward_date": forward_date,
        "back_date": back_date,
        "scope": scope,
        "date": date,
        "title": title,
        "metrics": metrics,
        "wip_cards": wip_cards,
        "backlog_cards": backlog_cards,
        "updated_at": now,
        "version": VERSION,
    }

    return render_template("dashboard.html", **context)
Exemple #3
0
def parse_google_output(csv_filename):
    reader = csv.DictReader(open(csv_filename))
    for row in reader:

        try:
            k = Kard.objects.get(key=row['Ticket'])
        except Kard.DoesNotExist:
            k = Kard()

        try:
            k.category = row['Category']
            k.backlog_date = parse_date(row['Backlog Date'])
            k.start_date = parse_date(row['Start Date'])
            k.done_date = parse_date(row['Done Date'])
            k.key = row['Ticket']
            k.title = row['Card title']
            k.shirt_size = row['Shirt Size']
            k.save()
        except Exception, e:
            print "Error reported!"
            print row
            print str(e)
            print "============="
            print
            print
Exemple #4
0
def state():
    date = datetime.datetime.now()
    date = make_end_date(date=date)

    board = DisplayBoard()  # defaults to all teams, 7 days of done

    title = app.config.get('SITE_NAME')

    wip_cards = Kard.in_progress(date)
    backlog_cards = Kard.backlogged(date)
    metrics = [
        {'Ave. Cycle Time': Kard.objects.moving_cycle_time(
            year=date.year, month=date.month, day=date.day)},
        {'Done this week': Kard.objects.done_in_week(
            year=date.year, month=date.month, day=date.day).count()},
        {'Done this month':
            Kard.objects.done_in_month(
                year=date.year, month=date.month, day=date.day).count()},
        {'On the board': wip_cards.count() + backlog_cards.count()},
    ]

    context = {
        'title': title,
        'board': board,
        'states': states,
        'metrics': metrics,
        'date': date,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    return render_template('state.html', **context)
Exemple #5
0
def jira_add_team_cards(team, filter_id):
    from kardboard.tickethelpers import JIRAHelper
    from kardboard.models import States
    from kardboard.app import app

    statsd_conn = app.statsd.get_client('tasks.jira_add_team_cards')

    counter = statsd_conn.get_client(class_=statsd.Counter)
    total_timer = statsd_conn.get_client(class_=statsd.Timer)
    total_timer.start()

    logger = jira_add_team_cards.get_logger()
    logger.info("JIRA BACKLOG SYNC %s: %s" % (team, filter_id))
    states = States()
    helper = JIRAHelper(app.config, None)
    issues = helper.service.getIssuesFromFilter(helper.auth, filter_id)
    for issue in issues:
        if Kard.objects.filter(key=issue.key):
            # Card exists, pass
            pass
        else:
            logger.info("JIRA BACKLOGGING %s: %s" % (team, issue.key))
            defaults = {
                'key': issue.key,
                'title': issue.summary,
                'backlog_date': datetime.datetime.now(),
                'team': team,
                'state': states.backlog,
            }
            c = Kard(**defaults)
            c.ticket_system.actually_update(issue)
            c.save()
            counter += 1

    total_timer.stop()
Exemple #6
0
def state():
    date = datetime.datetime.now()
    date = make_end_date(date=date)

    board = DisplayBoard()  # defaults to all teams, 7 days of done

    title = app.config.get("SITE_NAME")

    wip_cards = Kard.in_progress(date)
    backlog_cards = Kard.backlogged(date)
    metrics = [
        {"Ave. Cycle Time": Kard.objects.moving_cycle_time(year=date.year, month=date.month, day=date.day)},
        {"Done this week": Kard.objects.done_in_week(year=date.year, month=date.month, day=date.day).count()},
        {"Done this month": Kard.objects.done_in_month(year=date.year, month=date.month, day=date.day).count()},
        {"On the board": wip_cards.count() + backlog_cards.count()},
    ]

    context = {
        "title": title,
        "board": board,
        "states": states,
        "metrics": metrics,
        "date": date,
        "updated_at": datetime.datetime.now(),
        "version": VERSION,
    }

    return render_template("team.html", **context)
Exemple #7
0
def main():
    states = States()

    backlogged_states = []
    for k in Kard.backlogged():
        if k.state not in states:
            if k.state not in backlogged_states:
                backlogged_states.append(k.state)
            k.state = states.backlog
            k.save()

    start_states = []
    for k in Kard.in_progress():
        if k.state not in states:
            if k.state not in start_states:
                start_states.append(k.state)
            k.state = states.start
            k.save()

    print "Valid states"
    print states

    print "Backlogged states that went away"
    print backlogged_states

    print "Start states that went away"
    print start_states
Exemple #8
0
def team_backlog(team_slug=None):
    if request.method == "POST":
        if kardboard.auth.is_authenticated() is False:
            abort(403)

        start = time.time()
        card_key_list = request.form.getlist('card[]')
        counter = 1
        for card_key in card_key_list:
            Kard.objects(
                key=card_key.strip()
            ).only('priority').update_one(set__priority=counter)
            counter +=1

        elapsed = (time.time() - start)
        return jsonify(message="Reordered %s cards in %.2fs" % (counter, elapsed))

    teams = _get_teams()
    team = _find_team_by_slug(team_slug, teams)
    exclude_classes = _get_excluded_classes()
    team_stats = teams_service.TeamStats(team.name, exclude_classes)
    lead_time = team_stats.lead_time(weeks=12)
    weekly_throughput = team_stats.weekly_throughput_ave(weeks=12)

    backlog = Kard.objects.filter(
        team=team.name,
        state=States().backlog,
    ).exclude('_ticket_system_data').order_by('priority')

    backlog_markers = _make_backlog_markers(
        lead_time,
        weekly_throughput,
        backlog
    )

    title = "%s backlog" % team.name

    context = {
        'title': title,
        'team_slug': team_slug,
        'team': team,
        'backlog': backlog,
        'backlog_markers': backlog_markers,
        'weekly_throughput': weekly_throughput,
        'updated_at': datetime.datetime.now(),
        'teams': teams,
        'version': VERSION,
        'authenticated': kardboard.auth.is_authenticated(),
    }

    return render_template('team-backlog.html', **context)
Exemple #9
0
def funnel(state_slug):
    states = States()
    try:
        state = states.find_by_slug(state_slug)
        funnel = Funnel(state, app.config.get('FUNNEL_VIEWS', {})[state])
    except KeyError:
        abort(404)

    cards = funnel.ordered_cards()

    funnel_auth = False
    if kardboard.auth.is_authenticated() is True:
        funnel_auth = funnel.is_authorized(session.get('username', ''))

    if request.method == "POST":
        if kardboard.auth.is_authenticated() is False or funnel_auth is False:
            abort(403)

        start = time.time()
        card_key_list = request.form.getlist('card[]')

        counter = 1
        for card_key in card_key_list:
            Kard.objects(key=card_key.strip()).only('priority').update_one(
                set__priority=counter)
            counter += 1

        elapsed = (time.time() - start)
        return jsonify(message="Reordered %s cards in %.2fs" %
                       (counter, elapsed))

    title = "%s: All boards" % state

    funnel_markers = funnel.markers()

    context = {
        'title': title.replace("Backlog",
                               "Ready: Elabo").replace("OTIS", "TIE"),
        'state': state,
        'state_slug': state_slug,
        'cards': cards,
        'times_in_state': funnel.times_in_state(),
        'funnel_throughput': funnel.throughput,
        'funnel_markers': funnel_markers,
        'funnel_auth': funnel_auth,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
        'authenticated': kardboard.auth.is_authenticated(),
    }

    return render_template('funnel.html', **context)
Exemple #10
0
def funnel(state_slug):
    states = States()
    try:
        state = states.find_by_slug(state_slug)
        funnel = Funnel(state, app.config.get('FUNNEL_VIEWS', {})[state])
    except KeyError:
        abort(404)

    cards = funnel.ordered_cards()

    funnel_auth = False
    if kardboard.auth.is_authenticated() is True:
        funnel_auth = funnel.is_authorized(session.get('username', ''))

    if request.method == "POST":
        if kardboard.auth.is_authenticated() is False or funnel_auth is False:
            abort(403)

        start = time.time()
        card_key_list = request.form.getlist('card[]')

        counter = 1
        for card_key in card_key_list:
            Kard.objects(
                key=card_key.strip()
            ).only('priority').update_one(set__priority=counter)
            counter += 1

        elapsed = (time.time() - start)
        return jsonify(message="Reordered %s cards in %.2fs" % (counter, elapsed))

    title = "%s: All boards" % state

    funnel_markers = funnel.markers()

    context = {
        'title': title.replace("Backlog", "Ready: Elabo").replace("OTIS", "TIE"),
        'state': state,
        'state_slug': state_slug,
        'cards': cards,
        'times_in_state': funnel.times_in_state(),
        'funnel_throughput': funnel.throughput,
        'funnel_markers': funnel_markers,
        'funnel_auth': funnel_auth,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
        'authenticated': kardboard.auth.is_authenticated(),
    }

    return render_template('funnel.html', **context)
Exemple #11
0
def team_backlog(team_slug=None):
    if request.method == "POST":
        if kardboard.auth.is_authenticated() is False:
            abort(403)

        start = time.time()
        card_key_list = request.form.getlist('card[]')
        counter = 1
        for card_key in card_key_list:
            Kard.objects(key=card_key.strip()).only('priority').update_one(
                set__priority=counter)
            counter += 1

        elapsed = (time.time() - start)
        return jsonify(message="Reordered %s cards in %.2fs" %
                       (counter, elapsed))

    teams = _get_teams()
    team = _find_team_by_slug(team_slug, teams)
    weeks = 4

    backlog = Kard.objects.filter(
        team=team.name,
        state=States().backlog,
    ).exclude('_ticket_system_data').order_by('priority')

    backlog_marker_data, backlog_markers = _team_backlog_markers(
        team, backlog, weeks)

    backlog_without_order = [k for k in backlog if k.priority is None]
    backlog_with_order = [k for k in backlog if k.priority is not None]
    backlog_with_order.sort(key=lambda k: k.priority)
    backlog = backlog_with_order + backlog_without_order

    title = "%s" % team.name

    context = {
        'title': title,
        'team_slug': team_slug,
        'team': team,
        'backlog': backlog,
        'backlog_markers': backlog_markers,
        'backlog_marker_data': backlog_marker_data,
        'updated_at': datetime.datetime.now(),
        'teams': teams,
        'version': VERSION,
        'authenticated': kardboard.auth.is_authenticated(),
    }

    return render_template('team-backlog.html', **context)
Exemple #12
0
def team_backlog(team_slug=None):
    if request.method == "POST":
        if kardboard.auth.is_authenticated() is False:
            abort(403)

        start = time.time()
        card_key_list = request.form.getlist('card[]')
        counter = 1
        for card_key in card_key_list:
            Kard.objects(
                key=card_key.strip()
            ).only('priority').update_one(set__priority=counter)
            counter += 1

        elapsed = (time.time() - start)
        return jsonify(message="Reordered %s cards in %.2fs" % (counter, elapsed))

    teams = _get_teams()
    team = _find_team_by_slug(team_slug, teams)
    weeks = 4

    backlog = Kard.objects.filter(
        team=team.name,
        state=States().backlog,
    ).exclude('_ticket_system_data').order_by('priority')

    backlog_marker_data, backlog_markers = _team_backlog_markers(team, backlog, weeks)

    backlog_without_order = [k for k in backlog if k.priority is None]
    backlog_with_order = [k for k in backlog if k.priority is not None]
    backlog_with_order.sort(key=lambda k: k.priority)
    backlog = backlog_with_order + backlog_without_order

    title = "%s" % team.name

    context = {
        'title': title,
        'team_slug': team_slug,
        'team': team,
        'backlog': backlog,
        'backlog_markers': backlog_markers,
        'backlog_marker_data': backlog_marker_data,
        'updated_at': datetime.datetime.now(),
        'teams': teams,
        'version': VERSION,
        'authenticated': kardboard.auth.is_authenticated(),
    }

    return render_template('team-backlog.html', **context)
Exemple #13
0
def funnel(state_slug):
    states = States()
    try:
        state = states.find_by_slug(state_slug)
        funnel = Funnel(state, app.config.get("FUNNEL_VIEWS", {})[state])
    except KeyError:
        abort(404)

    cards = funnel.ordered_cards()

    funnel_auth = False
    if kardboard.auth.is_authenticated() is True:
        funnel_auth = funnel.is_authorized(session.get("username", ""))

    if request.method == "POST":
        if kardboard.auth.is_authenticated() is False or funnel_auth is False:
            abort(403)

        start = time.time()
        card_key_list = request.form.getlist("card[]")

        counter = 1
        for card_key in card_key_list:
            Kard.objects(key=card_key.strip()).only("priority").update_one(set__priority=counter)
            counter += 1

        elapsed = time.time() - start
        return jsonify(message="Reordered %s cards in %.2fs" % (counter, elapsed))

    title = "%s: All boards" % state

    funnel_markers = funnel.markers()

    context = {
        "title": title,
        "state": state,
        "state_slug": state_slug,
        "cards": cards,
        "times_in_state": funnel.times_in_state(),
        "funnel_throughput": funnel.throughput,
        "funnel_markers": funnel_markers,
        "funnel_auth": funnel_auth,
        "updated_at": datetime.datetime.now(),
        "version": VERSION,
        "authenticated": kardboard.auth.is_authenticated(),
    }

    return render_template("funnel.html", **context)
Exemple #14
0
def card_add():
    f = _init_new_card_form(request.values)
    card = Kard()
    f.populate_obj(card)

    if request.method == "POST":
        if f.key.data and not f.title.data:
            try:
                f.title.data = card.ticket_system.get_title(key=f.key.data)
            except Exception, e:
                log_exception(e, "Error getting card title via helper")
                pass

        if f.validate():
            # Repopulate now that some data may have come from the ticket
            # helper above
            f.populate_obj(card)
            card.save()
            flash("Card %s successfully added" % card.key)
            return redirect(url_for("card", key=card.key))
Exemple #15
0
def card_add():
    f = _init_new_card_form(request.values)
    card = Kard()
    f.populate_obj(card)

    if request.method == "POST":
        if f.key.data and not f.title.data:
            try:
                f.title.data = card.ticket_system.get_title(key=f.key.data)
            except Exception, e:
                log_exception(e, "Error getting card title via helper")
                pass

        if f.validate():
            # Repopulate now that some data may have come from the ticket
            # helper above
            f.populate_obj(card)
            card.save()
            flash("Card %s successfully added" % card.key)
            return redirect(url_for("card", key=card.key))
Exemple #16
0
def team_backlog(team_slug=None):
    if request.method == "POST":
        if kardboard.auth.is_authenticated() is False:
            abort(403)

        start = time.time()
        card_key_list = request.form.getlist("card[]")
        counter = 1
        for card_key in card_key_list:
            Kard.objects(key=card_key.strip()).only("priority").update_one(set__priority=counter)
            counter += 1

        elapsed = time.time() - start
        return jsonify(message="Reordered %s cards in %.2fs" % (counter, elapsed))

    teams = _get_teams()
    team = _find_team_by_slug(team_slug, teams)
    weeks = 12

    backlog = (
        Kard.objects.filter(team=team.name, state=States().backlog).exclude("_ticket_system_data").order_by("priority")
    )

    backlog_marker_data, backlog_markers = _team_backlog_markers(team, backlog, weeks)

    title = "%s backlog" % team.name

    context = {
        "title": title,
        "team_slug": team_slug,
        "team": team,
        "backlog": backlog,
        "backlog_markers": backlog_markers,
        "backlog_marker_data": backlog_marker_data,
        "updated_at": datetime.datetime.now(),
        "teams": teams,
        "version": VERSION,
        "authenticated": kardboard.auth.is_authenticated(),
    }

    return render_template("team-backlog.html", **context)
    def calculate(cls, group="all"):
        from kardboard.models import Kard
        from kardboard.models import ReportGroup

        try:
            record = cls.objects.get(group=group)
        except cls.DoesNotExist:
            record = cls()
            record.group = group
            record.data = {}

        kards = ReportGroup(group, Kard.in_progress())
        record.data = report_on_cards(list(kards.queryset))
        record.save()
        return record
    def calculate(cls, group="all"):
        from kardboard.models import Kard
        from kardboard.models import ReportGroup

        try:
            record = cls.objects.get(
                group=group,
            )
        except cls.DoesNotExist:
            record = cls()
            record.group = group
            record.data = {}

        kards = ReportGroup(group, Kard.in_progress())
        record.data = report_on_cards(list(kards.queryset))
        record.save()
        return record
Exemple #19
0
def blocked(group="all", months=3, start=None):
    start = start or datetime.datetime.today()
    months_ranges = month_ranges(start, months)

    start = months_ranges[0][0]
    end = months_ranges[-1][-1]

    rg = ReportGroup(group, Kard.objects())
    blocked_cards = rg.queryset

    blocked_cards = blocked_cards.filter(start_date__gte=start,
        start_date__lte=end, blocked_ever=True).order_by('-start_date')

    context = {
        'title': "Blocked",
        'cards': blocked_cards,
        'start': start,
        'end': end,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    return render_template('blocked.html', **context)
Exemple #20
0
def blocked(group="all", months=3, start=None):
    start = start or datetime.datetime.today()
    months_ranges = month_ranges(start, months)

    start = months_ranges[0][0]
    end = months_ranges[-1][-1]

    rg = ReportGroup(group, Kard.objects())
    blocked_cards = rg.queryset

    blocked_cards = blocked_cards.filter(
        start_date__gte=start, start_date__lte=end,
        blocked_ever=True).order_by('-start_date')

    context = {
        'title': "Blocked",
        'cards': blocked_cards,
        'start': start,
        'end': end,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    return render_template('blocked.html', **context)
Exemple #21
0
def parse_google_output(csv_filename):
    reader = csv.DictReader(open(csv_filename))
    for row in reader:

        try:
            k = Kard.objects.get(key=row['Ticket'])
        except Kard.DoesNotExist:
            k = Kard()

        try:
            k.category = row['Category']
            k.backlog_date = parse_date(row['Backlog Date'])
            k.start_date = parse_date(row['Start Date'])
            k.done_date = parse_date(row['Done Date'])
            k.key = row['Ticket']
            k.title = row['Card title']
            k.shirt_size = row['Shirt Size']
            k.save()
        except Exception, e:
            print "Error reported!"
            print row
            print str(e)
            print "============="
            print
            print
Exemple #22
0
def parse_kardboard_output(csv_filename):
    reader = csv.DictReader(open(csv_filename))
    for row in reader:

        try:
            k = Kard.objects.get(key=row['key'])
        except Kard.DoesNotExist:
            k = Kard()

        try:
            k.category = row['category']
            k.backlog_date = parse_date(row['backlog_date'])
            k.start_date = parse_date(row['start_date'])
            k.done_date = parse_date(row['done_date'])
            k.key = row['key']
            k.title = row['title']
            k.state = row['state']
            if k.state == "Unknown":
                k.state = "Done"
            k.save()
        except Exception, e:
            print "Error reported!"
            print row
            print str(e)
            print "============="
            print
            print
Exemple #23
0
def dashboard(year=None, month=None, day=None):
    date = kardboard.util.now()
    now = kardboard.util.now()
    scope = 'current'

    if year:
        date = date.replace(year=year)
        scope = 'year'
    if month:
        date = date.replace(month=month)
        scope = 'month'
        start, end = month_range(date)
        date = end
    if day:
        date = date.replace(day=day)
        scope = 'day'

    date = make_end_date(date=date)

    wip_cards = list(Kard.in_progress(date))
    wip_cards = sorted(wip_cards, key=lambda c: c.current_cycle_time(date))
    wip_cards.reverse()

    backlog_cards = Kard.backlogged(date).order_by('key')

    metrics = [
        {'Ave. Cycle Time': Kard.objects.moving_cycle_time(
            year=date.year, month=date.month, day=date.day)},
        {'Done this week': Kard.objects.done_in_week(
            year=date.year, month=date.month, day=date.day).count()},
        {'Done this month':
            Kard.objects.done_in_month(
                year=date.year, month=date.month, day=date.day).count()},
        {'On the board': len(wip_cards) + backlog_cards.count()},
    ]

    title = "Dashboard"
    if scope == 'year':
        title += " for %s"
    if scope == 'month':
        title += " for %s/%s" % (date.month, date.year)
    if scope == 'day' or scope == 'current':
        title += " for %s/%s/%s" % (date.month, date.day, date.year)

    forward_date = date + relativedelta.relativedelta(days=1)
    back_date = date - relativedelta.relativedelta(days=1)

    if forward_date > now:
        forward_date = None

    context = {
        'forward_date': forward_date,
        'back_date': back_date,
        'scope': scope,
        'date': date,
        'title': title,
        'metrics': metrics,
        'wip_cards': wip_cards,
        'backlog_cards': backlog_cards,
        'updated_at': now,
        'version': VERSION,
    }

    return render_template('dashboard.html', **context)
Exemple #24
0
from kardboard.models import Kard
from kardboard.tasks import force_update_ticket

for k in Kard.in_progress():
    force_update_ticket.delay(k.id)
print "Queued updates for %s WIP cards" % (Kard.in_progress().count())

for k in Kard.backlogged():
    force_update_ticket.delay(k.id)
print "Queued updates for %s backlogged cards" % (Kard.backlogged().count())

for k in Kard.objects.done():
    force_update_ticket.delay(k.id)
print "Queued updates for %s done cards" % (Kard.objects.done().count())
Exemple #25
0
def parse_kardboard_output(csv_filename):
    reader = csv.DictReader(open(csv_filename))
    for row in reader:

        try:
            k = Kard.objects.get(key=row['key'])
        except Kard.DoesNotExist:
            k = Kard()

        try:
            k.category = row['category']
            k.backlog_date = parse_date(row['backlog_date'])
            k.start_date = parse_date(row['start_date'])
            k.done_date = parse_date(row['done_date'])
            k.key = row['key']
            k.title = row['title']
            k.state = row['state']
            if k.state == "Unknown":
                k.state = "Done"
            k.save()
        except Exception, e:
            print "Error reported!"
            print row
            print str(e)
            print "============="
            print
            print