Exemple #1
0
def report_types(group="all", months=3, start=None):
    start = start or datetime.datetime.today()
    months_ranges = month_ranges(start, months)
    rg = ReportGroup(group, Kard.objects)
    rg_cards = rg.queryset
    types = list(rg_cards.distinct('_type'))
    types.sort()

    datatable = {
        'headers': ('Month', 'Type', 'Throughput', 'Cycle Time', 'Lead Time'),
        'rows': [],
    }

    months = []
    for arange in months_ranges:
        for typ in types:
            row = []
            start, end = arange
            filtered_cards = Kard.objects.filter(done_date__gte=start,
                                                 done_date__lte=end,
                                                 _type=typ)
            rg = ReportGroup(group, filtered_cards)
            cards = rg.queryset

            if cards.count() > 0:
                month_name = start.strftime("%B")
                if month_name not in months:
                    row.append(month_name)
                    months.append(month_name)
                else:
                    row.append('')

                row.append(typ)
                row.append(cards.count())
                row.append("%d" % cards.average('_cycle_time'))
                row.append("%d" % cards.average('_lead_time'))
            if row:
                row = tuple(row)
                datatable['rows'].append(row)

    context = {
        'title': "By type",
        'updated_at': datetime.datetime.now(),
        'datatable': datatable,
        'version': VERSION,
    }

    return render_template('report-types.html', **context)
Exemple #2
0
def value_txt_report(year_number, month_number, group="all"):
    start_date = munge_date(year=year_number, month=month_number, day=1)
    start_date = make_start_date(date=start_date)

    start_date, end_date = month_range(start_date)

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

    cards = done.filter(done_date__gte=start_date,
                        done_date__lte=end_date).order_by('-done_date')

    cards = [c for c in cards if c.is_card]

    context = {
        'title': "Completed Value Cards",
        'cards': cards,
        'start_date': start_date,
        'end_date': end_date,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    response = make_response(render_template('done-report.txt', **context))
    response.headers['Content-Type'] = "text/plain"
    return response
Exemple #3
0
def report_assignee(group="all"):
    states = States()
    states_of_interest = [s for s in states if s not in (states.backlog, states.done)]
    # ReportGroup of WIP
    rg = ReportGroup(group, Kard.objects.filter(state__in=states_of_interest))

    distro = {}
    for k in rg.queryset.all():
        assignee = k._assignee or "Unassigned"
        distro.setdefault(assignee, 0)
        distro[assignee] += 1

    total = 0
    total = float(sum(distro.values()))

    distro = distro.items()
    distro.sort(key=lambda x: x[1])
    distro.reverse()

    percentages = [(x[0], (x[1] / total)) for x in distro]
    percentages = [(x[0], round(x[1], 2)) for x in percentages]

    chart = {}
    chart['data'] = percentages

    context = {
        'data': distro,
        'chart': chart,
        'total': total,
        'title': "Assignee breakdown",
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }
    return render_template('report-assignee.html', **context)
Exemple #4
0
def std_dev(start, stop):
    start = make_start_date(date=start)
    stop = make_end_date(date=stop)

    rg = ReportGroup('dev', Kard.objects.filter(done_date__gte=start, done_date__lte=stop))

    cards = [c for c in rg.queryset if c.is_card]
    cycle_times = [c.cycle_time for c in cards]

    over_21 = [c for c in cycle_times if c > 21]
    over_21_pct = float(len(over_21)) / len(cycle_times)

    print "%s -- %s" % (start, stop)
    print "\t Sample: %s" % len(cards)
    print "\t Over 21: %s / %s" % (len(over_21), over_21_pct * 100)
    print "\t Ave: %s" % average(cycle_times)
    print "\t Stdev: %s" % standard_deviation(cycle_times)
    ct, pct = percentile(.8, cycle_times)
    print "\t 80pct: %s / %s" % (ct, pct * 100)

    cards_by_class = {}
    for c in cards:
        cards_by_class.setdefault(c.service_class['name'], [])
        cards_by_class[c.service_class['name']].append(c)

    for sclass, cards in cards_by_class.items():
        cycle_times = [c.cycle_time for c in cards]

        print "\t ## %s" % (sclass)
        print "\t\t Sample: %s" % len(cards)
        print "\t\t Ave: %s" % average(cycle_times)
        print "\t\t Stdev: %s" % standard_deviation(cycle_times)
    def calculate(cls, start_date, end_date, group="all"):
        from kardboard.models import Kard
        from kardboard.models import ReportGroup

        start_date = make_start_date(date=start_date)
        end_date = make_end_date(date=end_date)

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

        kards = ReportGroup(group,
            Kard.objects.filter(
                done_date__gte=start_date,
                done_date__lte=end_date,
            )
        )
        record.data = report_on_cards(list(kards.queryset))
        record.save()
        return record
Exemple #6
0
def find_value_cards(year):
    start = make_start_date(year, 1, 1)
    end = make_end_date(year, 12, 31)

    query = Kard.objects.filter(done_date__gte=start, done_date__lte=end)
    rg = ReportGroup('dev', query)

    cards = [c for c in rg.queryset if c.is_card]
    return cards
Exemple #7
0
def report_throughput(group="all", months=3, start=None):
    start = start or datetime.datetime.today()
    months_ranges = month_ranges(start, months)
    defect_types = app.config.get('DEFECT_TYPES', None)
    with_defects = defect_types is not None

    month_counts = []
    for arange in months_ranges:
        start, end = arange
        filtered_cards = Kard.objects.filter(done_date__gte=start,
            done_date__lte=end)
        rg = ReportGroup(group, filtered_cards)
        cards = rg.queryset

        if with_defects:
            counts = {'card': 0, 'defect': 0}
            for card in cards:
                if card.type.strip() in defect_types:
                    counts['defect'] += 1
                else:
                    counts['card'] += 1
            month_counts.append((start.strftime("%B"), counts))
        else:
            num = cards.count()
            month_counts.append((start.strftime("%B"), num))

    chart = {}
    chart['categories'] = [c[0] for c in month_counts]

    if with_defects:
        chart['series'] = [
            {
                'data': [c[1]['card'] for c in month_counts],
                'name': 'Cards'
            },
            {
                'data': [c[1]['defect'] for c in month_counts],
                'name': 'Defects'
            }
        ]
    else:
        chart['series'] = [{
            'data': [c[1] for c in month_counts],
            'name': 'Cards',
        }]

    context = {
        'title': "How much have we done?",
        'updated_at': datetime.datetime.now(),
        'chart': chart,
        'month_counts': month_counts,
        'version': VERSION,
        'with_defects': with_defects,
    }

    return render_template('report-throughput.html', **context)
def daily_throughput_average(report_group_slug, stop, weeks=4):
    start = (stop - relativedelta(days=weeks * 7)) + relativedelta(days=1)
    start = make_start_date(date=start)

    query = Kard.objects.filter(
        done_date__gte=start,
        done_date__lte=stop,)

    kards = list(ReportGroup(report_group_slug, query).queryset)
    return len(kards) / float(weeks * 7)
Exemple #9
0
def report_leaderboard(group="all",
                       months=3,
                       person=None,
                       start_month=None,
                       start_year=None):
    start = datetime.datetime.today()
    if start_month and start_year:
        start = start.replace(month=start_month, year=start_year)
    months_ranges = month_ranges(start, months)

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

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

    cards = done.filter(done_date__gte=start, done_date__lte=end)

    people = {}
    for card in cards:
        try:
            devs = card.ticket_system_data['developers']
            for d in devs:
                p = people.get(d, PersonCardSet(d))
                p.add_card(card)
                people[d] = p
        except KeyError:
            pass

    if person:
        person = people.get(person, None)
        people = []
        if not person:
            abort(404)
    else:
        people = people.values()
        people.sort(reverse=True)

    context = {
        'people': people,
        'person': person,
        'months': months,
        'group': group,
        'start': start,
        'end': end,
        'start_month': start_month,
        'start_year': start_year,
        'title': "Developer Leaderboard",
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }
    if person:
        context['title'] = "%s: %s" % (person.name, context['title'])

    return render_template('leaderboard.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
Exemple #11
0
def moving_data(report_group_slug, start, stop):
    query = Kard.objects.filter(
        done_date__gte=start,
        done_date__lte=stop,
    )

    kards = list(ReportGroup(report_group_slug, query).queryset)

    bad_kards = [k for k in kards if k.cycle_time is None]
    print "Bad cards"
    print "*" * 10
    print[k.key for k in bad_kards]

    features = [k for k in kards if k.is_card]
    defects = [k for k in kards if not k.is_card]
    over_sla = [k for k in kards if k.cycle_time > k.service_class['upper']]
    card_cycle_ave = average([k.cycle_time for k in kards]) or 0
    card_stddev = standard_deviation([k.cycle_time for k in kards]) or 0

    wip = find_wip(report_group_slug, stop)
    tpa = daily_throughput_average(report_group_slug, stop)

    try:
        little_law = int(round(wip / float(tpa)))
    except:
        little_law = ""

    cycle_time_ave = find_cycle_time_ave(report_group_slug, stop)

    data = {
        'start': start,
        'stop': stop,
        'features': len(features),
        'bugfixes': len(defects),
        'little_law': little_law,
        'cycle_time_ave': int(round(cycle_time_ave)),
        'wip': wip,
        'cycle_average': int(round(card_cycle_ave)),
        'stddev': int(round(card_stddev)),
        'over_sla': len(over_sla),
    }
    return data
Exemple #12
0
def done(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.done())
    done = rg.queryset

    cards = done.filter(done_date__gte=start,
                        done_date__lte=end).order_by('-done_date')

    context = {
        'title': "Completed Cards",
        'cards': cards,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    return render_template('done.html', **context)
Exemple #13
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 #14
0
def report_cycle_distribution(group="all", months=3, limit=None):
    from kardboard.services.reports import CycleTimeDistribution

    defects_only, cards_only = False, False
    if limit == 'cards':
        cards_only = True
    if limit == 'defects':
        defects_only = True

    today = datetime.datetime.today()
    start_day = today - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=today)

    context = {
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day)
    if defects_only:
        query = query & Q(_type__in=app.config.get('DEFECT_TYPES', []))
    elif cards_only:
        query = query & Q(_type__nin=app.config.get('DEFECT_TYPES', []))
    rg = ReportGroup(group, Kard.objects.filter(query))

    cards = list(rg.queryset)

    total = len(cards)
    if total == 0:
        context = {
            'error':
            "Zero cards were completed in the past %s months" % months,
        }
        return render_template('report-cycle-distro.html', **context)

    cdr = CycleTimeDistribution(cards=cards)

    chart = {}
    chart['categories'] = cdr.days()
    chart['series'] = []

    service_class_series = cdr.service_class_series()
    sclasses = service_class_series.keys()
    sclasses.sort()

    for sclass in sclasses:
        seri = service_class_series[sclass]
        chart['series'].append(dict(name=sclass, data=seri))

    context = {
        'histogram_data': cdr.histogram(),
        'chart': chart,
        'title': "How quick can we do it?",
        'months': months,
        'total': total,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }
    if defects_only:
        context['title'] = "Defects: %s" % (context['title'])
        context['card_type'] = 'defects'
    elif cards_only:
        context['title'] = "Cards: %s" % (context['title'])
        context['card_type'] = 'cards'
    else:
        context['title'] = "All: %s" % (context['title'])
        context['card_type'] = 'cards and defects'

    return render_template('report-cycle-distro.html', **context)
Exemple #15
0
def report_cycle_distribution(group="all", months=3, limit=None):
    defects_only, cards_only = False, False
    if limit == 'cards':
        cards_only = True
    if limit == 'defects':
        defects_only = True

    ranges = (
        (0, 4, "Less than 5 days"),
        (5, 10, "5-10 days"),
        (11, 15, "11-15 days"),
        (16, 20, "16-20 days"),
        (21, 25, "21-25 days"),
        (
            26,
            30,
            "26-30 days",
        ),
        (31, 9999, "> 30 days"),
    )
    today = datetime.datetime.today()
    start_day = today - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=today)

    context = {
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day)
    if defects_only:
        query = query & Q(_type__in=app.config.get('DEFECT_TYPES', []))
    elif cards_only:
        query = query & Q(_type__nin=app.config.get('DEFECT_TYPES', []))
    rg = ReportGroup(group, Kard.objects.filter(query))

    total = rg.queryset.count()
    if total == 0:
        context = {
            'error': "Zero cards were completed in the past %s months" % months
        }
        return render_template('report-cycle-distro.html', **context)

    distro = []
    for row in ranges:
        lower, upper, label = row
        query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day) & \
            Q(_cycle_time__gte=lower) & Q(_cycle_time__lte=upper)
        if defects_only:
            query = query & Q(_type__in=app.config.get('DEFECT_TYPES', []))
        else:
            query = query & Q(_type__nin=app.config.get('DEFECT_TYPES', []))
        pct = ReportGroup(
            group, Kard.objects.filter(query)).queryset.count() / float(total)
        pct = round(pct, 2)
        distro.append((label, pct))

    chart = {}
    chart['data'] = distro

    context = {
        'data': distro,
        'chart': chart,
        'title': "How quick can we do it?",
        'months': months,
        'total': total,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }
    if defects_only:
        context['title'] = "Defects: %s" % (context['title'])
        context['card_type'] = 'defects'
    elif cards_only:
        context['title'] = "Cards: %s" % (context['title'])
        context['card_type'] = 'cards'
    else:
        context['title'] = "All: %s" % (context['title'])
        context['card_type'] = 'cards and defects'

    return render_template('report-cycle-distro.html', **context)