pivotalcli/commands/_stories_info.py

152 lines
4.5 KiB
Python

import re
import sys
from datetime import datetime
from typing import Any, Dict
from consolemd import Renderer
import base32_crockford as base32
import api.stories
from config import Config
from util import print_wrap
from . import COLOR_HEADER, COLOR_TITLE, COLOR_WHITE, _format_state, _get_persons
def __print_story(story: Dict[str, Any]) -> None:
"""
Prints the title, the current state and the estimate of the story, if
available.
TODO: Split up in functions.
"""
COLOR_TITLE.print(story["name"])
print(story["url"], end="\n\n")
if "current_state" in story:
state = _format_state(story["current_state"])
COLOR_HEADER.print("State:", state, end="")
if story["current_state"] == "accepted":
print(f" (at {story['accepted_at']})", end="")
print(end="\n\n")
if "estimate" in story:
COLOR_HEADER.print("Estimate: ", end="")
print(story["estimate"], "points", end="")
if len(story.get("owner_ids", [])) > 1:
points = story["estimate"] / len(story["owner_ids"])
print(f" ({points} each)", end="")
print(end="\n\n")
def __print_owners(story: Dict[str, Any], persons: Dict[int, Any]) -> None:
"""Prints the owners of the story, if available."""
if story.get("owner_ids"):
COLOR_HEADER.print("Owners:")
owners = []
for owner_id in story["owner_ids"]:
name = persons[owner_id]["name"]
initials = persons[owner_id]["initials"]
owners.append(f" - {name} ({initials})")
print("\n".join(owners), end="\n\n")
def __print_description(story: Dict[str, Any]) -> None:
"""Prints the description of the story, if available."""
COLOR_HEADER.print("Description:")
if "description" in story:
description = story["description"].strip()
Renderer().render(description, width=80)
print()
else:
print(" (No description)", end="\n\n")
def __print_labels(story: Dict[str, Any]) -> None:
"""Prints the labels of the story, if available."""
if not story.get("labels"):
return
COLOR_HEADER.print("Labels:")
template = "\033[97;48;5;22m {} \033[0m"
labels = " ".join(template.format(label["name"]) for label in story["labels"])
print(f" {labels}", end="\n\n")
def __print_tasks(project_id: int, story_id: int) -> None:
"""Prints the tasks of the story, if available."""
tasks = api.stories.get_tasks(project_id, story_id)
if tasks:
COLOR_HEADER.print("Tasks:")
for task in tasks:
print(end=" ")
print("[X]" if task["complete"] else "[ ]", end=" \033[34m")
print(base32.encode(task["id"]), end=":\033[0m ")
print(task["description"])
print()
def __print_comments(
project_id: int, story_id: int, persons: Dict[int, Dict[str, Any]]
) -> None:
"""Prints the comments on the story, if available."""
comments = api.stories.get_comments(project_id, story_id)
if comments:
COLOR_HEADER.print("Comments:")
for comment in comments:
text = comment.get("text", "[Empty comment]").strip()
print_wrap(text, indent=" ")
person_id = comment["person_id"]
name = persons[person_id]["name"]
COLOR_WHITE.print(" -", name, end=" ")
date = datetime.strptime(comment["created_at"], "%Y-%m-%dT%H:%M:%SZ")
date_str = date.strftime("on %a %Y-%m-%d at %H:%M")
print(date_str, end="\n\n")
def __print_blockers(project_id: int, story_id: int) -> None:
"""Prints the stories that block this story, if available."""
blockers = api.stories.get_blockers(project_id, story_id)
if blockers:
COLOR_HEADER.print("Blockers:")
def blocker_repl(matchgroup: Any) -> str:
id = int(matchgroup.group(1))
code = base32.encode(id)
return COLOR_HEADER.format(code)
pattern = re.compile(r"#(\d+)")
for blocker in blockers:
resolved = "X" if blocker["resolved"] else " "
desc = pattern.sub(blocker_repl, blocker["description"])
print(f" [{resolved}] {desc}")
def stories_info(story_b32: str) -> None:
story_id = base32.decode(story_b32)
story = api.stories.get(story_id)
project_id = story["project_id"]
persons = _get_persons(project_id)
__print_story(story)
__print_owners(story, persons)
__print_description(story)
__print_labels(story)
__print_tasks(project_id, story_id)
__print_comments(project_id, story_id, persons)
__print_blockers(project_id, story_id)