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()
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)
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
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)
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)
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
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)
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)
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)
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)
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)
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)
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))
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
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)
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)
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
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)
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())