Integrating Asana and Git

Recently we at Spaceman Labs have been testing out different tools and workflows to manage our various projects. After trying a few different packages, we’ve more or less settled on Asana as our issue tracking solution. It’s got a lot of advantages: it’s free, we can have as many projects as we want, and it’s low-friction enough that we’re likely to use it regularly.

That last one is actually the biggest feature – just as the best camera is the one you have with you, the best issue tracker is the one you’ll actually use. All the bells and whistles in the world don’t matter if you’re scared away from the core functionality. But there’s one way Asana could be even easier to use. It doesn’t have a standard way to integrate with our Git workflow. We’d like to be able to commit some code with a comment like “fixes #123” and have that fix reflected in Asana.

Fortunately, all of the groundwork has been done. Asana has a really awesome, and beautifully well-documented, API. And other developers, most notably for our purposes Bruno Costa, have taken that API and put together useful scripts.

The only thing missing from Bruno’s post-commit hook (and go back and read his blog post if you haven’t, it’s great) is the ability to run it non-interactively. Our Git workflow is built around Tower; it’s an awesome tool, but it doesn’t know how to simulate reading from /dev/tty in a hook.

So we needed to make the script non-interactive. This means it loses some potential flexibility, but on the other hand, it’s faster and has a somewhat higher “just works” quotient. Once you set up your git config variables, anyway. While we were at it, we also made it handle multiple ticket numbers per checkin, and differentiate between referencing and closing a ticket. That means you can write a commit message like

"Tweaked the widget; fixed #1, #2, and #3; references #4 and #5; oh yeah, and closes #6"

and have the right thing happen. Neat, right?

You can find the script at our GitHub page; please modify and open pull requests if you’d like to see it do more. (For instance, re-opening a closed ticket would be trivial.) V1 of the script is duplicated below. To run it, save it to your local repo’s .git/hooks/post-commit, and chmod 755 that mother. Run the git config line at the top of the script with the appropriate values, and you’re good to go.

#!/bin/bash

# modified from http://brunohq.com/journal/speed-project-git-hook-for-asana/

# -----------------------
# necessary configuration:
# git config --global user.asana-key "MY_ASANA_API_KEY" (http://app.asana.com/-/account_api)
# -----------------------

apikey=$(git config user.asana-key)
if [ $apikey == '' ] ; then exit 0; fi

# hold the closed ticket numbers
declare -a closed
# hold the ticket numbers that are not closed, just touched
declare -a referenced
# track whether we're currently closing tickets or just referencing them
closes='NO'

# regex pattern to recognize a story number
taskid_pattern='#([0-9]*)'
# regex pattern to recognize a "closing this ticket" word
closes_pattern='([Ff]ix|[Cc]lose|[Cc]losing)'
# regex pattern to recognize an "and" word (eg "fixes #1, #2, and #3")
and_pattern='([Aa]nd|&)'

# get the checkin comment for parsing
comment=$(git log --pretty=oneline -n1)

# break the commit comment down into words
IFS=' ' read -a words <<< "$comment"

for element in "${words[@]}"
do
    # if we have a task id, save it to the appropriate array
    if [[ $element =~ $taskid_pattern ]]; then
	if [ "${closes}" == "YES" ]; then
	    closed=("${closed[@]}" "${BASH_REMATCH[1]}")
	fi
	referenced=("${referenced[@]}" "${BASH_REMATCH[1]}")
    # or else if we have a "closes" word, set the tracking bool accordingly
    elif [[ $element =~ $closes_pattern ]]; then
	closes='YES'
    # and if we don't, set us back to referencing
    # (if we're an "and", don't change any state)
    elif [[ ! $element =~ $and_pattern ]]; then
	closes='NO'
    fi
done

# touch the stories we've referenced
for element in "${referenced[@]}"
do
    curl -u ${apikey}: https://app.asana.com/api/1.0/tasks/${element}/stories \
         -d "text=just committed ${comment/ / with message:%0A}" > /dev/null 2>&1
done

# close the tasks we've fixed
for element in "${closed[@]}"
do
    curl --request PUT -u ${apikey}: https://app.asana.com/api/1.0/tasks/${element} \
         -d "completed=true" > /dev/null 2>&1
done
Joel Kraut

About Joel Kraut

Developing on Apple platforms for, holy shit, over ten years now. Find me on linkedin and twitter. My personal website is foon.us.
This entry was posted in Code and tagged , , , , . Bookmark the permalink.

10 Responses to Integrating Asana and Git

  1. Vladimir Kovalskiy says:

    Thank a lot for sharing. But you are sampling ticket numbers as 1,2,3 when in real life they can not be remebered and should copy/pasted from the asana url. Cause they look like ‘4549660050096’ And if you are opening ticket to get number, why not close it?

    How do you overcome those terrible numbers issue?

    • foon says:

      Good questions. I usually have Asana open anyway, so I do copy the ticket numbers from the URL. There are several advantages over just closing the ticket from there. One, I get the commit text automatically–so the ticket isn’t just closed, but whoever reading it knows about the commit that closed it. Two, I get the commit hash as well–so I’ll know where in history to look if it breaks again, or I can cherrypick fixes for a branch. Three, I tend to do a lot of intermediate checkins like “progress on X bug; references #1234566789”. Once I’ve copied the ticket number for the first of these, the rest of the checkins are “free” as long as my git client can remember my last checkin message.

      If you want to be able to select which tickets are closed from the command line, check out Bruno Costa’s script, which is better suited to a non-gui environment.

  2. Pingback: Setting Up a Software Development Infrastructure on a Shoestring

  3. Pingback: Setting Up a Development Infrastructure on a Shoestring | Blog World

  4. Marc Boscher says:

    I guess it’s better to be late than never: I built an Asana power tools app that includes GitHub synchronization. It actually lets you sync an Asana project with the issues of a GitHub repo. You can then edit, comment, submit issues from Asana. Let me know if you find it useful.

    https://chrome.google.com/webstore/detail/crosscheck-for-asana/cbnanllnipdggjajbdceeglkiahlknfg

  5. Aaron Evans says:

    That’s great, but Asana doesn’t have #1, #2, #3 or whatever. So you have to have a commit hook that scans for

    fixes: https://app.asana.com/0/7614400166161/28383302463112

    And your script has to log into Asana to work.

  6. Grégoire Bois says:

    If you want a 2-ways Asana – Github integration, there is http://unito.io. It syncs your projects and repositories (tasks, issues, comments, etc.) automatically.
    They are in private beta, give it a try!

  7. Carielle says:

    Now that the API key is deprecated in Asana, does anyone have a version of this that uses one of the alternative forms of authentication?

Leave a Reply

Your email address will not be published. Required fields are marked *