nextbigsoundinc/Sprintly-GitHub — pull request #16 by tremby (2014-01-17 05:50:28+00:00)
Title: Use setuptools, store config in git configuration files, multi project support, and more

With the extent of refactoring I wanted to do there was no chance of separate feature branches for everything here.

- Installation is now via setuptools. I have removed the update and install functions since in my opinion they didn't do anything useful.
- The binary and commit hook are now very short scripts which call functionality from the main module, `sprintly.py`. Setuptools installs the commit hook alongside the module, and it can be found there to be symlinked to.
- Installation and uninstallation of the git hook can now be done from any directory within the git repository.
- There is now no ~/.sprintly/sprintly.config file. Instead all configuration is stored in the Git configuration files (whether global or repository-specific). Only the bare minimum is stored there: email and API key, product ID (which obviously is generally going to be set locally for each repository), plus some hook-specific ones I'll get to later.
- To easily get those config values I'm using the dulwich library. That makes it easy to save the config back, too.
- I took out the functionality to prompt for the Sprintly email and API key. This tool is aimed at developers. We know how to edit config files or use `git config`. So let's get rid of the unnecessary handholding. Since it is useful to give a choice of product IDs, on the other hand, I have left that functionality in.
- We exit without a stack trace on KeyboardInterrupt, so we can control-C out when it's asking for the item number/product ID if we realize we've forgotten something, and not get an ugly error.
- I've added more consistent output colouring. Yellow for warnings, red for errors, green for success. I may not have been 100% consistent.
- Options are parsed in a separate method, which allows the main functionality to be called programatically without there having been any command line arguments (as will be the case in the commit hook).
- I've upgraded from optparse to argparse, which makes a few things easier.
- The only reference to subprocess is now calling an original git hook, if it exists. Everything else can be done in pure Python by referencing the sprintly.py module.
- On `--uninstall-hook` a `commit-msg.original` file is now moved back to `commit-msg`, otherwise it'd stop functioning.
- I've refactored `--install-hook` and `--uninstall-hook` to be much more robust. It will now move rather than obliterate a symlink to some other hook -- before it was assuming any symlink was our symlink. And the same for uninstall -- it won't delete a symlink if that symlink doesn't point to our hook.
- The commit hook now supports Sprintly's alternate ticket syntax (`ticket:44`, `issue:44` etc) as well as the normal `#44`.
- Instead of typing 0 for no reference to a ticket, just press enter. 0 was confusing.
- Multiple item numbers are allowed in the shortcut beginning-of-commit-message syntax if they are comma separated (but no whitespace except trailing after the last number).
- Configurable commit message template and item keyword. So instead of forcing `References #44` to the start of the commit message it can be at the start or end, have newlines etc around it, any other surrounding text. The item keyword can be changed from `#` too, which in my case is good because otherwise Github will pick up on it and get confused thinking it's talking about a pull request. So for instance the template string for the old-style commit message would be `References %(items)s %(messages)s`, my default is `%(message)s; references %(items)s` (much tidier at the end in my opinion) and for the projects I'm working on nowadays I am setting it to `%(message)s\n\nReferences %(items)s` with `sprintly.itemkeyword` set to `item:` so that I end up with things like

Commit message blah blah

References item:2, item:3
- There's a `--cache` argument which will pull the info from the cache rather than the internet. This is kinda buggy with the other new arguments...
- `--self` (default) grabs your own tickets but labels those belonging to other people (parents of your tickets), `--anyone` grabs everyone's tickets (including unassigned) and labels the assignee of each, `--unassigned` grabs just unassigned tickets (and labels those which *are* assigned -- stories which are parents of unassigned).

Caveats:

- Running update on the old version will just not work, since that only downloaded one file and there are now more major files.
- The configuration obviously totally changed, so you will need to reconfigure username, API key and product ID. No big deal.
- `$PATH` isn't preserved for git hooks, so if your normal Python environment (and that with which the module was installed) is not in /usr/bin or /bin the module will not be found. In my case on my work machine I have Homebrew Python installed in /usr/local/Cellar/... and the only workaround I could find in a hurry was to move the original /usr/bin/python out of the way and put a symlink in pointing to Homebrew Python. I'd welcome a better solution.
- The `--cached` option isn't very good -- since different queries are now possible (for unassigned tickets, and for everyone's tickets, plus tickets from all products vs just the current one) only the last query is cached, so when using `--cached` with different options from when the cache was written the output will not make sense. Suggestions welcome.