Every few years I tweak my task management strategy. My latest approach leverage's Trello's card & list model. Or, as the industry likes to call it, the Kanban board.
My 'system' works like this: I've got a Trello board with 7 lists: one named On Deck, one for each day of the week minus Saturday.
Every task I need to accomplish is either in the queue (i.e., On Deck) or assigned to a specific day of the week. On Sunday evening, I can plan out my week by moving cards to specific days. Of course, the week never goes as planned and I can adjust cards on the fly.
To pretty things up, each customer gets their own color coded label, which is attached to their cards. Besides giving me a visual cue, the labels let me filter the board to one customer's perspective.
Here's what a board looks like (with the texted blurred out, of course):
Let's Automate This
While this is all working well, I noticed one interaction I could optimize. Nearly all my clients have some task tracking system of their own, so adding tasks to my On Deck list can be automated.
Consider a fake client named FooCo that uses Jira to track their tasks. When I'm assigned the ticket FC-103 to work on, I do the following:
- Look up the summary of FC-103. For our example, let's assume that the summary is "Implement bitcoin payment method."
- Create a new card with the title: FC-103: Implement bitcoin payment method.
- Add the label fooco to the card.
- Attach the URL https://fooco.atlassian.net/browse/FC-103 to the card.
Given only the bug URL, https://fooco.atlassian.net/browse/FC-103, I can derive the customer, ticket ID, label and ticket summary. The latter value is retrieved using a simple jira command line utility. Once I have the fields, I can use the Trello API to issue a POST to create a new On Deck card.
Here's how this looks in practice:
$ trelloassist -a auto-add -u 'https://fooco.atlassian.net/browse/FC-103' 623b77da1675766212b46454
This process is powered by a shell script named trelloassist. See below for the source code. trelloassist supports querying and creating cards by making simple curl requests to the Trello API.
The magic of the trelloassist's auto-add functionality is the bash function named do_auto_add:
do_auto_add() {
url=$1 ; shift
list=<the default destination list>
case "$url" in
# for customers who store tasks in Jira
*.atlassian.net/browse/*)
ticket=$(basename $url)
domain=$(echo $url | sed -e 's|https://||' -e 's|.atlassian.*||')
title=$(jiraassist -p $domain -a get -k $ticket | cut -d'|' -f4)
label=$domain
name="$ticket - $title"
;;
# for customers who store tasks in DoneDone
*.mydonedone.com/issuetracker/*/issues/*)
label=scra
domain=$(echo $url | sed -e 's|https://||' -e 's|.mydonedone.*||')
title=$(donedoneassist -a title -i $ticket)
name="DD:$ticket - $title"
;;
...
*)
echo "Don't know how to auto-add: $url"
exit 2
;;
esac
}
This function peels off whatever information it can from the URL and then calls an external script (jiraassist and donedoneassist) for additional details. The variables list, label, name and url must be set to sane values when this function completes.
After do_auto_add a call to trelloassist's new-card action is made and the card is added to the board.
do_auto_add "$url"
if [ -z "$name" -o -z "$label" ] ; then
echo "Refusing to auto-add a card without a name or label"
exit 4
fi
trelloassist -a new-card -i "$list" -n "$name" -d "$description" -u "$url" -l "$label"
Thinking of cognitive friction I've smoothed out brings a smile to my face. The Trello API underscores what a flexible tool it is, and why I expect it'll be my Task Manager choice for quite some time.
The Code
Here's the trelloassist script:
#!/bin/bash
profile=i2x
usage() {
cmd=$(basename $0)
echo "Usage: $cmd [-p profile] -a boards"
echo "Usage: $cmd [-p profile] -a lists -i <board-id>"
echo "Usage: $cmd [-p profile] -a cards -i <list-id>"
echo "Usage: $cmd [-p profile] -a org -i <id>"
echo "Usage: $cmd [-p profile] -a mine [-n <name>]"
echo "Usage: $cmd [-p profile] -a labels -i <board-id>"
echo "Usage: $cmd [-p profile] -a label-id -n <name>"
echo "Usage: $cmd [-p profile] -a new-card -i <list-id> -n <name> [ -d <description> ] [ -l <label> ] [ -u <url-attachement> ]"
echo "Usage: $cmd [-p profile] -a auto-add -u url"
exit 1
}
api() {
method=$1 ; shift
path=$1 ; shift
curl -s \
--request $method \
--header 'Accept: application/json' \
"$@" \
"https://api.trello.com/1/$path?key=$KEY&token=$TOKEN"
}
scrub() {
if [ "$verbose" = "yes" ] ; then
jq .
else
jq "$@"
fi
}
named_list() {
name=$1 ; shift
for known in $MINE ; do
known_id=$(echo $known | cut -d ':' -f1)
known_name=$(echo $known | cut -d ':' -f2)
if [ "$known_name" = "$name" ] ; then
echo $known_id
break
fi
done
}
while getopts ":a:b:l:i:n:u:d:hp:v" o; do
case "$o" in
n) name=$OPTARG ;;
a) action=$OPTARG ;;
i) id=$OPTARG ;;
l) label=$OPTARG ;;
d) description=$OPTARG ;;
u) url=$OPTARG ;;
v) verbose=yes ;;
p) profile=$OPTARG ;;
*|h) usage ;;
esac
done
if [ -f $HOME/.config/trelloassist/$profile.config ] ; then
. $HOME/.config/trelloassist/$profile.config
else
echo "Profile config doesn't exist: $profile"
exit 3
fi
case "$action" in
org)
if [ -z "$id" ] ; then
usage
fi
api GET organizations/$id | scrub '{slug: .name, name: .displayName}'
;;
boards)
api GET members/$USER/boards | scrub -r '.[] | .id + "|" + .name + "|" + .idOrganization'
;;
lists)
if [ -z "$id" ] ; then
usage
fi
api GET boards/${id}/lists | scrub -r '.[] | .id + "|" + .name'
;;
cards)
if [ -z "$id" ] ; then
usage
fi
api GET lists/${id}/cards | scrub -r '.[] | .id + "|" + .name + "|" + (if (.labels | length) > 0 then .labels | map(.name) | join(",") else "" end) + "|" + .url'
;;
mine)
for m in $MINE ; do
id=$(echo $m | cut -d: -f1)
slug=$(echo $m | cut -d: -f2)
if [ -z "$name" ] ; then
echo $slug
elif [ "$name" = "$slug" ] ; then
trelloassist -a cards -i $id
fi
done
;;
labels)
if [ -z "$id" ] ; then
usage
fi
api GET "/boards/$id/labels" | scrub -r '.[] | .id + "|" + .name'
;;
label-id)
if [ -z "$name" ] ; then
usage
fi
trelloassist -a labels -i $DEFAULT_BOARD | grep "$name" | head -1 | cut -d'|' -f1
;;
new-card)
if [ -z "$id" -o -z "$name" ] ; then
usage
fi
if [ -z "$label" ] ; then
label_id=""
else
label_id=$(trelloassist -a label-id -n "$label")
fi
known_id=$(named_list $id)
if [ -n "$known_id" ] ; then
id=$known_id
fi
id=$(api POST "/cards" \
--data-urlencode "name=$name" --data-urlencode "desc=$description" \
-d "pos=top" -d "idLabels=$label_id" \
-d "idList=$id" | scrub -r '.id')
if [ -n "$url" ] ; then
api POST "/cards/$id/attachments" --data-urlencode url="$url" > $HOME/.trelloassist.add.attachment
fi
echo $id
;;
auto-add)
if [ -z "$url" ] ; then
usage
fi
name=""
list=""
description=""
label=""
do_auto_add "$url"
if [ -z "$name" -o -z "$label" ] ; then
echo "Refusing to auto-add a card without a name or label"
exit 4
fi
trelloassist -a new-card -i "$list" -n "$name" -d "$description" -u "$url" -l "$label"
;;
*)
usage
;;
esac
Here's the shape of the profile config file which is found in $HOME/.config/trelloassist/$profile.config:
KEY=[your api key goes here]
TOKEN=[your api token goes here]
USER=[your default user goes here]
DEFAULT_BOARD=[id of your default board]
MINE="
[list_id]:[list_alias]
...
"
do_auto_add() {
... see above ...
}
No comments:
Post a Comment