Source code for trello_release_notes.trello_release_notes
# -*- coding: utf-8 -*-
"""Main module."""
from datetime import date
from trello import TrelloClient
from loguru import logger
from functools import lru_cache
"""
# given a list of boards
# for each board
# given a "done" list
# given a "released" list
# if there are items in the done list,
create a release card for this date in the releases list
# for each item in the done list
# get the release card for this date
# append the title as list item to the description of the release card
# add the title and details as a comment on the release card
# archive the done item
# post process - send an email or do something with the release detail
"""
[docs]class Trellist(object):
"""The main object - initialize and use run()
:param apikey: Your api-key.
:param apisecret: Your api secret token. Get it from a protected file that you don't commit. Keep it secret!
:param boardname: Name of the board to work on.
:param done_list_name: The name of the done list on your board. Only one.
:param releases_list_name: The name of the list to put release cards on.
:param create_comments: True by default. Create a comment on the release card for each done card
:param create_release_if_zero_done: If nothing is done, should you make a sad empty release card?
"""
def __init__(
self,
apikey,
apisecret,
boardname,
done_list_name="done",
releases_list_name="releases",
create_release_if_zero_done=False,
create_comments=True,
):
self.client = TrelloClient(api_key=apikey, api_secret=apisecret)
self.board = self.get_board(boardname)
self.done = self.get_list_by_name(done_list_name)
self.releases = self.get_list_by_name(releases_list_name)
self.release_template = "{date} release: {count} done"
self.card_summary_template = "- {card.name} {card.members_initials}"
self.create_release_if_zero_done = create_release_if_zero_done
self.create_comment_per_item = create_comments
[docs] def run(self):
"""Runs through all the methods to perform the work"""
logger.info(f"get all cards in the done board: {self.done.name}")
cards = self.get_done_cards()
logger.info(f"got {len(cards)} cards")
if cards or self.create_release_if_zero_done:
release_card = self.create_release_card(
cards, self.release_template, self.card_summary_template
)
for card in cards:
if self.create_comment_per_item:
self.add_comment_to_release(release_card, card)
card.set_closed(True)
logger.info("finished run")
[docs] def get_board(self, board_name):
"""Gets the open board object by a name, otherwise raises an Error to
let you know we don't have that board
:param board_name: actual name of a board you have access to
"""
board = self.first(
self.client.list_boards(), lambda b: b.name == board_name and not b.closed
)
if board:
return board
raise ValueError(
(
"Couldn't find an open board named '{}'. Check the name in your"
" trello - are there extra quote marks in this message?"
).format(board_name)
)
[docs] def get_list_by_name(self, name):
"""Iterate lists and get the first one matching the name passed in
:param name: Name of a list on the board you've passed in
"""
trello_list = self.first(self.board.list_lists(), lambda l: l.name == name)
if trello_list:
return trello_list
raise ValueError(
(
"Couldn't find a list named '{}'. Check the name in your trello"
" - are there extra quote marks in this message?"
).format(name)
)
[docs] def get_card_members(self, card):
"""Return an array of Trello.Member objects of this card
:param card:
"""
return [self.get_member(member_id) for member_id in card.member_id]
[docs] @lru_cache()
def get_member(self, member_id):
"""Get a member. We only use our own function so that we can cache calls
:param member_id:
"""
return self.client.get_member(member_id)
[docs] def first(self, iterable, condition):
"""Iterates an iterable and returns the first item that meets a condition or None
:param iterable: An iterable to fetch the first itemm that meets condition
:param condition: The condition to evaluate per item
"""
return next((i for i in iterable if condition(i)), None)
[docs] def get_done_cards(self):
"""Get every card from the done list"""
return self.done.list_cards()
[docs] def prep_card(self, card):
"""Take the card and add arrays of all member initials, full_names and usernames for use in templates
:param card: a card to modify with extra information
"""
card.members = self.get_card_members(card)
card.members_initials = ""
card.members_full_names = ""
card.members_usernames = ""
if len(card.members):
card.members_initials = [member.initials for member in card.members]
card.members_full_names = [member.full_name for member in card.members]
card.members_usernames = [member.username for member in card.members]
return card
[docs] def summarize_these(self, cards, template, prep_function):
"""Run a list of cards through a template and return those joined by newlines
The template can reference any part of a Trello.card as well as 3 handy arrays
- members_initials
- members_full_names
- members_usernames
These will either have an empty string or an array of strings that show up nicely
in string.format
:param cards: Card objects to summarize
:param template: A template for each card. We pass the full card to format
:param prep_function: A function that will add make the card more friendly to format
"""
summary = "\n".join(
[self.summarize_this(card, template, prep_function) for card in cards]
)
return summary
[docs] def summarize_this(self, card, template, prep_function):
"""Summarize a card by passing it to a template after prepping it with values from a prep_function
:param card: a Card to summarize
:param template: a string template. We'll call format and pass in a prepped Card
:param prep_function: use this to add extra information to the card
"""
card = prep_function(self, card)
summary = template.format(card=card)
return summary
[docs] def create_release_card(self, cards, release_template, card_summary_template):
"""Returns a new release card, with a title from template and description based on a summary of the cards
:param cards: Cards in this release
:param release_template: A format string for release card name that we pass in date and length of cards
:param card_summary_template: A string we format with per each card
"""
release_card_name = release_template.format(date=date.today(), count=len(cards))
# turn list of names of cards into a summary
summary = self.summarize_these(
cards, template=card_summary_template, prep_function=self.prep_card
)
logger.info(f"{summary}")
release_card = self.releases.add_card(release_card_name, summary)
return release_card