I keep track of different things I'm working on using a combination of Orgmode for Emacs and Request Tracker (or RT). Although Orgmode can track things like attachments and email, I find it easiest to leave that sort of thing for RT; I use Orgmode to track completion and the time spent on a task. The result of all of this is that I'll often create a ticket for something even when I'm the only one who's involved. RT makes that easy, of course: just send an email, and you've got a new ticket; send an email with a subject line that has the ticket number, and RT attaches it to the ticket. As a result of all this, I've got a fair number of functions and shortcuts in Emacs and Mutt to help speed things up.
One of the things I use is an Emacs package called RT-liberation, which uses the rt CLI tool to search, browse and examine tickets. Here's a function which adds a ticket at point to my Org file:
(defun x-hugh-insert-rt-ticket-into-org (&optional point arg)
"A Small but Useful(tm) function to insert an RT ticket into Org.
If POINT is nil then called on (point). If called with arg, check in
as well."
(interactive "P")
(when (not point)
(setq point (point)))
(setq point (point))
(let ((ticket (get-text-property point 'rt-ticket)))
(setq subject (cdr (assoc "Subject" ticket)))
(setq id (rt-liber-browser-ticket-id-at-point))
(save-excursion
(set-buffer (find-file-noselect "/home/hugh/all.org"))
(goto-char (point-min))
(if (search-forward-regexp (format "^\\*\\* .*RT #%s.*$" id)
(point-max) t)
(message "Already in org!")
(progn
(goto-char (point-max))
(if (bolp)
()
(insert "\n"))
(insert (format "** RT #%s -- %s\n" id subject))))
(if arg
(org-clock-in)))))
It's not wonderful, but it does the trick. It does have some important assumptions, though:
Okay, so now I've added a ticket to Org and I've clocked in. Let's say I'm going to make a change to a Cfengine file and commit in Git. I want to include a reference to the ticket, so I use this Emacs function:
(defun x-hugh-insert-rt-ticket-commit-comment ()
"A Small but Useful(tm) function to insert a comment referencing an
RT ticket.
Uses the currently-clocked in task as default."
(interactive)
(insert-string (format "see %s for details."
(x-hugh-clocked-into-rt-ticket))))
I've got that bound to a keyboard shortcut, so I'll type something like:
Get Cf3 to check that foo is set;
then type my shortcut (C-cos), and I get:
Get Cf3 to check that foo is set; see RT #1234 for details.
The Emacs functions to see what ticket I'm checked into:
(defun x-hugh-clocked-into-rt-ticket ()
"A Small but Useful(tm) function to see if I'm clocked into an RT
ticket.
Depends on regular expressions, which of course puts me in a state of
sin."
(interactive)
(if (equal nil org-clock-current-task)
()
(when (string-match "\\(RT #[0-9]+\\)" org-clock-current-task)
(eval (format "%s" (match-string 1 org-clock-current-task))))))
As it says, it depends on regular expressions -- but that works okay for now.
(defun x-hugh-insert-rt-ticket-into-org-from-rt-email (&optional arg)
"Insert an RT ticket into Org while editing a reply to that email.
Faster than waiting for rt-browser to update."
(interactive "P")
(save-excursion
(goto-char (point-min))
(search-forward "Subject: ")
(if (search-forward-regexp "\\[rt.example.com #\\([0-9]+\\)\\]\\(.*\\)$" (line-end-position) t)
(progn
(let ((id (match-string 1))
(subject (match-string 2)))
(save-excursion
(set-buffer (find-file-noselect "/home/hugh/all.org"))
(goto-char (point-min))
(if (search-forward-regexp (format "^\\*\\* .*RT #%s.*$" id) (point-max) t)
(message "Already in org!")
(progn
(goto-char (point-max))
(if (bolp)
()
(insert "\n"))
(insert (format "** RT #%s --%s\n" id subject))))
(unless arg
(org-clock-in))))))))
So all that's good, but I have to be editing an email in Emacs to do this -- say, by hitting "Reply" to check in. Which is fine, but I'd like it to be faster. I can take advantage of the fact that I have Emacs running in daemon mode all the time, and that it loads my Org file on startup, to try checking in just by piping the email to emacsclient. So here's the shell script:
#!/bin/bash
# We have to save to a temp file because, unlike the main "emacs"
# binary, "emacsclient" will *not* deal with stdin.
T=$(/bin/mktemp /tmp/org-clockin.XXXXX)
cat - | tee $T >/dev/null
emacsclient \
--eval "(progn
(add-to-list 'load-path (expand-file-name \"~/.emacs.d/org/lisp/\"))
(add-to-list 'load-path (expand-file-name \"~/.emacs.d/org/contrib/lisp/\" t))
(require 'org)
(load-file (expand-file-name \"~/.emacs.d/x-hugh-org.el\"))
(find-file \"$T\")
(x-hugh-insert-rt-ticket-into-org-from-rt-email)
(kill-buffer))"
rm $T
Finally, the Mutt macro:
macro index ,a "|/home/hugh/bin/org-clockin.sh\n"
And now I can clock in right from the Mutt index view.