legume is a minimialist, distributed, code comments-based issue tracker
Add link to the end-user ticket tracker
Add kakoune keyboard mapping example.

heads

tip
browse log
v1.2.8
browse .tar.gz

clone

read-only
https://hg.sr.ht/~ser/legume
read/write
ssh://hg@hg.sr.ht/~ser/legume

#legume

Legume is a distributed issue tracker, and can be used along side other, more formal, issue trackers as an intra-developer tracking mechanism. I also tend to use it, rather than a web-based ticket tracker, on small, single-file scripts.

Legume leverages the developer tradition of using code comments to make notes about things that need to be addressed. Notes of this sort retain locality; they are reminders for code browsers, and contain meta-data about where to start looking when addressing an issue. They integrate naturally with whatever VCS the developer is using, and make it easy for a developer to remember to remove the comment when the topic is addressed. They require no extra external database.

Legume is developer oriented. Submit issues with the end-user Legume tracker.

#Features

The biggest selling feature of legume is that issues are embedded in code. This has a number of benefits:

  • Issues can be place-marks for where developers think things are happening.
  • Commenting code with TODO and FIXME comments is a decades-old traditional developer habit
  • Integrated with version control at an intuitive level, reducing cognitive load. No external integration with VCS necessary.
  • No external DB for tickets. TODOs and FIXMEs are still relevant even if you stop using legume. Which also means...
  • legume is not strictly necessary for working with issues. It's a convenience tool. This means you don't have to build your workflow around legume, and nobody in your team needs to install legume. You can find and grep your way through issues.

Legume will also address other, non-developer, use cases by recognizing a todo.txt file in the directory of execution. Legume will assume every line is a separate TODO. This allows easy integration with todo.txt, but also provides a place for sticking issues that either aren't linked to source, or come from a source other than a developer (e.g., web app). todo.txt syntax is also supported in comments.

  • (A) priorities
  • 2017-03-20 "created" dates
  • due:2017-03-20 "tagged" dates
  • *@contexts_
  • +projects
  • key:value tags
  • Multi-line issues (new issue, blank line, or non-comment breaks issue)

#Limitations

The trade-offs, which may or may not be considered limitations, include:

  • No unique IDs, which can make referencing tickets difficult or cumbersome
  • Very simple tickets. No attachments, no cross-references or dependencies, no robust commenting; history tracking limited to what's available in the VCS.
  • Efficiency. In a pure state, collating tickets requires walking directory trees and parsing source files. This is addressed by caching, but caches introduce opportunities for sync errors; it's a necessary wart on an otherwise elegant and simple solution.

#Usage

Comments must always start with a keyword, TODO,FIXME,BUG, orXXX`. These key words are case sensitive. After that, todo.txt formats are allowed. Example:

    // TODO 2017-03-20 (A) @con_example +proj_example due:2018-03-22 key:value Priorities, contexts, projects, created & due dates, and key/value pairs

Use the built-in help for options. One workflow is:

$ leg       # to list all todo/fixmes in a project
$ leg -d 5  # to list the details of item # 5

Filtering changes indexing. Because there is no canonical item numbering, any filters that produce a list must be also used when using -d (details). For example,

$ leg -P test       # to ignore all files in the test/ directory
$ leg -P test -d 3  # to get item #3 from the previous list

Legume assumes that if the data source is a pipe (STDIN), that it's seeing a diff. In this mode, Legume counts any add (+) tickets as new, and any removed (-) tickets as closed, and reports them this way. For example, on the Legume repository itself:

➜  legume hg diff -r 4:98 | leg  -
  1 REQ    NEW Include the time stamp in the report; removed use old version, add use new
  2 REQ    NEW filter on priority, category, and project; use meta-tags and -t
  3 BUG    NEW catch string lit escapes
  4 REQ CLOSED Support for STDIN
  5 REQ CLOSED Config file
  6 REQ CLOSED Support for unified diff
  7 REQ CLOSED Add test cases.
  8 REQ CLOSED Add test cases.
  9 REQ CLOSED Add test cases.
 10 REQ    NEW Add unit tests for Alias [component:ui]
 11 REQ    NEW Implement & add unit tests for Keywords [component:ui]
 12 REQ CLOSED Add test cases.
 13 REQ CLOSED Add test cases.
 14 REQ CLOSED Add test cases.
 15 REQ    NEW Parsing diffs seems to be broken
 16 REQ CLOSED Add test cases.
 17 INF    NEW refactor parsing to "consume-to-end"

Obvious limitations result from how diff reports information; a changed line is reported as a combination delete + add, which looks to Legume like a close + open. In practice and over short spans, it works pretty well.

#Install

legume build status Binaries for OSX, Linux, and Windows are here, and are signed with the GPG key 5E0D7ABD6668FDD1 (available from hkp://hkps.pool.sks-keyservers.net).

If you want to build it yourself, you can either go get the package, or clone it and compile it manually.

   go get -u repos.ser1.net/legume/cmd/leg

#vim

A super-simple vim script is available; to install, copy the contents of legume.vim into your vimrc. It binds <leader>lg to execute legume with the -f vim option and open the quickfix buffer.

#kakoune

drawing

The kakfile can be put in your $XDG_CONFIG_HOME/kak/autoload directory, and exposes some make-like functions & functionality. Kakoune's CWD should be the project directory.

  • leg opens a buffer list of the issues
  • leg-next-todo jumps to the next issue
  • leg-previous-todo jumps to the previous

If you want, map these to shortcuts as you would for make, for example:

declare-user-mode leg
map global leg n ": leg-next-todo<ret>" -docstring "go to next issue"
map global leg p ": leg-previous-todo<ret>" -docstring "go to previous issue"
hook global BufCreate \*leg\* %{
    map global user g ": enter-user-mode leg<ret>" -docstring "legume issues"
}
hook global BufClose \*leg\* %{
    unmap global user g 
}

#Performance samples

Legume has already satisfied the basic performance requirement; small projects have sub-second parse times. A future version may implement caching to bring larger projects to this benchmark.

Project with 108 files, 14k lines, 15 todos:

leg .  0.04s user 0.03s system 81% cpu 0.090 total

Project with 992 files, 564k lines, 244 todos:

leg .  1.34s user 0.07s system 95% cpu 1.464 total

The Linux 5.7 kernel source tree, 64,309 files, 28,136,537 lines, 9,697 todos:

leg .  49.60s user 0.96s system 99% cpu 50.713 total

#Caveats

Legume is intended for a narrow problem space. Large projects, such as the Linux kernel (and certainly the boundary is much lower than that) are certainly better served by a "real" issue tracking system. For large code bases, any tool that parses the entire code base on every invocation will be too slow, even if a tool like legume didn't lack most of the features of a sophisticated isuse tracking system.

Testing on languages other than Go has been limited. Testing on Windows is non-existent.

The diff feature absolutely has a number of limitations; diffs containing multi-line TODOs where a line other than the first changed will be missed; similarly, lines where only the first line changed will report partial descriptions. There's simply a limit to how much meta-information can be interpreted from a diff.

At the time of this writing, despite the version number this legume is young and I'm the only user I know of. There will be bugs. Sorry about that.

#Prior Art

Legume was inspired by lentil and follows the philosophy of todo.txt. Legume has goals beyond merely duplicating lentil:

  • Accept diffs & STDIN. This allows some ability to track history by using the output of a VCS. E.g., hg diff -r <histnode> \| leg would produce a list of all issues added and resolved, using diff markup (+/-) to indicate opened/closed
  • Improve performance.
  • Support todo.txt syntax (priorities, dates, etc)

Below are some other distributed ticketing systems, many of which I've tried. If legume isn't your cup of tea, maybe one of the ones listed below will be more suitable for your workflow.

  • lentil, discussed below.
  • Artemis. Separate bug DB (maildir); integrated with VCS (Mercurial, beta git support). Supports more traditional ticketing features, such as attachments and comments. Only slightly younger than BugsEverywhere, the first commit was in 2007.
  • b. Separate bug DB. Tightly coupled with Mercurial -- implemented as an HG extension. Supports more traditional ticketing features, such as assigning tickets to people.
  • BugsEverywhere. Separate bug DB. Lots of features, including a web interface, email ticket communication, supporting multiple VSes, and most traditional ticketing features. The grand-daddy of distributed ticketing systems; first commit was 2005!
  • git-bug, tightly coupled to git.
  • The one with my favorite name, ScmBug
  • Fossil, which is a kitchen-sink project; the VCS & bug tracker are very tightly coupled, but it does have a distributed ticketing system, so it makes the list.
  • SD, which has integration with git and darcs, and keeps bugs in a SQLite database.
  • ditz, which I used quite a bit way back when I was using Darcs (a predecessor to both git & Mercurial).
  • ticgit, now unmaintained.
  • ditrack; the web site appears to have reverted to the domain name provider.

And numerous discussions and blogs:

Most of these keep bug data in a separate database that's version tracked alongside the code. One of my requirements is to leverage code comments, and Lentil is the only tracker I found that does that. Some trackers keep bugs in a database that are one or more text files, which is OK because the VCS will be able to diff them efficiently; any tracker that keeps bugs in a binary DB (like SQLite) that requires checking into the VCS is, IMO, a non-starter.

Lentil is written in Haskell, and although I do like Haskell, I wanted something lower-impact to compile than Haskell. The core Haskell stack on Arch Linux, including common libraries, is 183 packages and 1.9GB. This is a heavy lift for small systems.

Additionally, I'm less fluent these days in Haskell than Go, and one of the issues I have with Lentil is performance. I'm not advanced enough with Haskell to be able to easily performance tune somebody else's code, and getting better at performance tuning Haskell was not my main objective for this project; I just wanted better speed and some additional functionality, and to get to the functionality I'd have to have solved the performance issues first... it was simply easier to implement a new tool.

// vim: set ft=pandoc