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