A CLI for quickly summarizing story points in Trello lists.
card-counter 1.0.0 Justin Barclay <justincbarclay@gmail.com> A CLI for quickly summarizing story points in Trello lists USAGE: card-counter [FLAGS] [OPTIONS] [SUBCOMMAND] FLAGS: -c, --compare Compares the current trello board with a previous entry -h, --help Prints help information -V, --version Prints version information OPTIONS: -b, --board-id <ID> The ID of the board where the cards are meant to be counted from -d, --database <DATABASE> Choose the database you want to save current request in [possible values: local, aws, azure] -f, --filter <FILTER> Filters out all lists with a name that contains the substring FILTER -k, --kanban <KANBAN> The kanban API to get your board and card information from [possible values: jira, trello] -s, --save <SAVE> Save the current entry in the database [default: true] [possible values: true, false] SUBCOMMANDS: burndown Parses data for a board and prints out data to be piped to gnuplot config Edit properties associated with card-counter. help Prints this message or the help of the given subcommand(s)
Before you can even think about getting started, you will need a Trello account. If you don’t have a Trello account, go get one. Use it for a while. But not just use it, breathe it, live it, feel it deep down in your meat covered bones. Once your entire being is permeated with Trello, you are ready to start tracking the progress you make in sprints.
Finally, you’ve got a Trello account and you’ve created some boards. Within those boards, you’ve created stacks of lists of cards. And within each card, you’ve scoped out the work and given it a score.
Great! You’ve got the theory down. I decree that you are an official agile scrum master. I even made a certificate for you.
Finally, finally, we’re ready to get started.
You can begin thinking about getting started with card-counter
now. But before you can start thinking about card-counter itself, however, you will need to take some steps to retrieve and save information from Trello:
- Get your API key
- Generate a Trello API token by going to
https://trello.com/1/authorize?expiration=1day&name=card-counter&scope=read&response_type=token&key=<your-key-here>
- Save these:
- As an environment variable:
export TRELLO_API_KEY=<your API key> export TRELLO_API_TOKEN=<your API token>
- Or in the config file:
card-counter config
There! We’re done thinking about getting started. card-counter now knows enough about you to start talking to the Trello API.
- Generate an API token for your user
- Save the token, url, and username:
- As an environment variable:
export JIRA_USERNAME=<your username> export JIRA_API_TOKEN=<your API token> export JIRA_URL=<your Jira URL>
- Or in the config file:
card-counter config
If you’re curious about what information card-counter stores, you can find the config file and local database in $HOME/.card-counter/
. If you have privacy concerns about what card-counter is doing with your information, don’t worry about it. card-counter pulls down your data from the Trello API, processes it, and stores it all locally on your machine.
Now that you understand the theory, we are ready to set up our boards to be processed by card-counter. Luckily, preparing your board for card-counter is simple. You just put in some numbers and you are set. Ok, it’s not quite that simple, but it’s close.
card-counter tracks the estimated and actual effort a card has taken. It does this by using numbers inside of parentheses – ()
– and square brackets – []
– within the card’s title. If the title only has a number in parentheses, it acts as both the “actual” and “estimated” effort. However, suppose there are numbers in parentheses and in square brackets in the title. In that case, the number in the square brackets will count as the “actual” effort taken and the number in the parentheses will act as the “estimated” effort. In short, numbers in square brackets are only counted as corrective numbers.
It’s hard to see what this means so let’s walk through an example:
Sally has a list, “This Sprint”, which has a singled card titled “Write docs for card-counter”. They have done their homework and they know that the documentation for card-counter is lacking. They estimate that this is going to be an effort of 2. Sally updates the card’s name to “Write docs for card-counter (2)”.
If Sally ran card-counter
, it would report:
List | Cards | Score | Estimated | Unscored |
---|---|---|---|---|
This Sprint | 1 | 2 | 2 | 0 |
After completing the task, Sally had learned that card-counter’s docs were in a much graver state than she had estimated. So she updates the card’s title to “(2)[4] Write docs for card-counter”.
Now, if Sally ran card-counter
, it would report:
List | Cards | Score | Estimated | Unscored |
---|---|---|---|---|
This Sprint | 1 | 4 | 2 | 0 |
If you have a boss, you know how much they like images. Images are great communication tools. They are easy to understand and they have pretty colours. card-counter can help produce burn down charts for you. You need to do two things to facilitate this process: One, have a board that has “Done” somewhere in the name. Two, run card-counter
regularly to produce a reasonable amount of data for that board (daily).
When you first run card-counter
on a new machine, you can run the config command. This allows card-counter to capture important pieces of information, like how to access your Trello data and your preferred database.
card-counter config
After that, you can run the command itself.
card-counter
This will bring up a list of boards you have access to and get you to choose what board you want to run the command on.
If you know that you will be running card-counter on the same board all the time, you can use the -b
(--board-id
) option and set the board-id
. You can find the board-id in the URL for your board.
A typical Trello board URL looks like:
https://trello.com/b/<board-id>/<your-board>
For example: if you want to use the Trello board-id for card-counter, https://trello.com/b/wtPNQDEV/card-counter, you would use “wtPNQDEV” as the board-id.
card-counter --board-id wtPNQDEV
If you have a board that is a little noisy, you can filter out lists that you don’t want to track. You can do this by using the -f
(--filter
) option. If you add a substring to the list(s), such as [ignore], card-counter can filter out these lists for you. Be careful, however, the filter option is case sensitive.
card-counter --board-id wtPNQDEV --filter ignore
If you’d like to generate a burndown chart for your boss or because you like graphs, there is the burndown
command. It will output comma-separated values that you can feed to your graphing library of choice. For this example, we’ll have gnuplot generate a graph for us.
First, we’ll need to set-up a gnuplot script to parse the data for us. Save the following example in a file titled “burndown.gp”.
set datafile separator ',' set xdata time set timefmt '%d-%m-%y' set format x "%d %b" set autoscale x plot for[col=2:3] "burndown.csv" u 1:col title columnheader(col) with lines
The burndown
command requires -s
(--start
) and -e
(--end
) options to run. They represent the start and end dates you wish to generate the burndown chart. These dates are formatted as the string “year-month-day” for example: “2020-04-14”. Additionally, we’ll pass in filter and board-id options. Finally, we’ll save the output to a file and tell gnuplot to process it for us.
card-counter burndown --board-id wtPNQDEV --start 2020-04-01 --end 2020-04-14 -f NoBurn > burndown.csv && gnuplot burndown.gp -p
Similarly to Trello, Jira stores the board-id in the URL as well
<your based url>/jira/software/projects/CC/boards/<board-id>
So for example, to extract the information from your Jira board url https://card-counter.atlassian.net/jira/software/projects/CC/boards/1, the base URL would be “https://card-counter.atlassian.net” and the board-id would be “1”.
export JIRA_URL=https://card-counter.atlassian.net
card-counter --board-id 1
If you don’t want to use gnuplot or some other sort of graphing library, I’ve helpfully decided to implement both svg
or ascii
graphs.
For ascii output you pass in the option --output ascii
card-counter burndown --board-id wtPNQDEV --start 2020-04-01 --end 2020-04-14 -f NoBurn --output ascii
… and for svg output you pass in the option --output svg
card-counter burndown --board-id wtPNQDEV --start 2020-04-01 --end 2020-04-14 -f NoBurn --output svg
Like csv
both of these options print to the terminal.
Are you forced to collaborate with others? Weirder yet, do you like to collaborate with others? Or do you just demand that everything needs to be in the cloud? If any 3 of those are correct, but especially if ALL of them are, I have the solution for you. It’s card-counter cloud edition! Where we allow you to store your data in DynamoDB or CosmosDB.
To start with you’ll need to ask your administrator to give you read/write access to Dynamo or Cosmos. This process can take anywhere from 3 weeks to 4 months.
Did you return with the correct AWS permissions? That’s great! I’m assuming in the interceding 3 months that you’ve become familiar with the AWS CLI. If so, this suggests your credentials are set somewhere. You probably don’t need to do anything. If you have rushed into this, and it is your first time using AWS, you can start reading Amazon’s documentation to find out what you need to set.
card-counter will check several locations for your AWS credentials and Region.
In order, the locations are:
- Environment Variables
- Credential Files
- IAM ECS Container Profile
- IAM EC2 Instance Profile
You can tell card-counter you want to use AWS as your database (instead of the local database) in two ways:
- As an option through the CLI
card-counter --database aws
- Select the
aws
option in your config filecard-counter config
For those of you who want to avoid doing as much work as possible, card-counter can create the necessary table in DynamoDB for you. When you run card-counter
for the first time, with AWS as your database, it will ask for permission to create the “card-counter” table.
If you’re a control freak (or worse yet, if you like config files everywhere), you can manage the database yourself. I’ve provided the terraform
below to help you create the “card-counter” table.
resource "aws_dynamodb_table" "card-counter-table" {
name = "card-counter"
billing_mode = "PROVISIONED"
read_capacity = 1
write_capacity = 1
hash_key = "board_id"
range_key = "time_stamp"
attribute {
name = "board_id"
type = "S"
}
attribute {
name = "time_stamp"
type = "N"
}
tags = {
Name = "dynamodb-table-1"
Environment = "production"
}
}
Did your administrator give you access? Bless their heart, they trusted you!
Before card-counter can talk to the all mighty Azure we need you to set some environment variables:
export COSMOS_ACCOUNT=<your azure account name>
export COSMOS_MASTER_KEY=<what a tasteless name, but it's what Azure calls it and it goes here>
You can tell card-counter to use CosmosDB as the backend in two ways:
- As an option through the CLI
card-counter --database azure
- Select the
azure
option in your config file and set the database name and container namecard-counter config
Like with DynamoDB card-counter
can create the CosmosDB for you, I mean, if you’re lazy and trust me. If you don’t trust me but are still kind of lazy, here’s where I create stuff.
But we all know you’re a control freak and that you’ve fallen in love with IaaC, but have managed to stay away from the dreaded ARM templates. So let me throw more terraform in your lap to manage.
data "azurerm_cosmosdb_account" "example" {
name = "tfex-cosmosdb-account"
resource_group_name = "tfex-cosmosdb-account-rg"
}
resource "azurerm_cosmosdb_sql_database" "example" {
name = "card-counter"
resource_group_name = data.azurerm_cosmosdb_account.example.resource_group_name
account_name = data.azurerm_cosmosdb_account.example.name
throughput = 400
}
resource "azurerm_cosmosdb_sql_container" "example" {
name = "card-counter"
resource_group_name = azurerm_cosmosdb_account.example.resource_group_name
account_name = azurerm_cosmosdb_account.example.name
database_name = azurerm_cosmosdb_sql_database.example.name
partition_key_path = "/board_id"
partition_key_version = 1
throughput = 400
indexing_policy {
indexing_mode = "Consistent"
included_path {
path = "/*"
}
}
unique_key {
paths = ["/board_id"]
}
}
Don’t trust the binaries I provided? I have an easy solution for you. Build it from source. (Easy if you already have rust and cargo installed)
git clone https://github.com/justinbarclay/card-counter.git
cd card-counter
cargo install --path ./card-counter/cli
Fin, finally.
As a bonus treat for those of you dealing with corporate overlords and Slack, if you’re so inclined you could create a Slack Slash command to send. I’ve created an outline, or a sketch, of how your could this here.