A simple Harvest client.
While there is already an Emacs Harvest client it might not be to everybodys liking:
- It primary uses Hydra and Ivy for its user interface.
- It fetches data from Harvest on each interaction.
- It uses the Harvest V1 API, which is deprecated and unsupported.
Reaper on the other hand:
- Uses a tabulated-list-mode buffer and completing-read (which Ivy can still override).
- Only fetch time entries when starting up, when you ask it to and when changing something. Yet it still displays the proper time for a running timer.
- Uses the Harvest V2 API.
Either using package.el to install from MELPA or:
(use-package reaper
:ensure t ; If using package.el, alternatively :straight t.
:bind ("C-c h" . reaper))
Create a personal access token at https://id.getharvest.com/developers
and use Emacs customization interface to set reaper-api-key
to the
given value. On the same page at Harvest you should be able to see the
account id you'll need for reaper-account-id
.
Use M-x reaper
to open the buffer (or whatever key sequence you've bound it to).
Bindings in the buffer:
n/p
- next/previous entry.q
- bury buffer. It can be recalled with thereaper
command.g
- refresh the list.d
- change date. Supply a date in Y-M-D or Y.M.D format. Year or year and month may be left out. +D or -D to go forward/back days from currently displayed.f/b
- Go to next/previous day.SPC
- restart the timer at point.RET
- restart the timer at point and bury buffer.c
- start a new timer.s
- stop running timer.k/DEL
- delete the entry at point.e e
- edit project, task and note of entry at point.e p
- edit project of entry at point.e t
- edit task of entry at point.e d
- edit note of entry at point.t
- edit time for entry at point (even works for running timers). Supports+
and-
calculations.Q
- to kill reaper buffer. Stops timers and clears all local data.!
- To clear the project/task cache and refresh from Harvest.
With reaper-autofile-functions
, project and task can be derived from
the note text. This is handy if ticket ids maps to projects, or to
match some description to the same project/task. For instance:
(defun xen-reaper-autofile-function (notes)
(cond
((string-match (rx "IA-" num) notes)
(cons 308078 262899))
((string-match (rx string-start "Ill" string-end) notes)
(cons 308078 276083))))
(add-hook 'reaper-autofile-functions 'xen-reaper-autofile-function)
Would automatically file entries mentioning "IA-" tickets on "Internal affairs - Code", while notes that only contain "Ill" will be filed under "Internal affairs - sick leave".
The functions reaper-insert-project-id
and reaper-insert-task-id
makes it easier to insert the proper project and task ids.
Harvest was obviously taken. Reaper alludes to Grim Reaper which I sorta have the same kind of relationship with. You know he's there, you know he's unavoidable, but that doesn't mean you have to like him.
Thanks to Kosta Harlan for Harvest.el which served as inspiration and initial bootstrapping.
This project is released under the GPL v3 license. See GPL
for
details.