Contributor guide

New contributors are always welcome in the hledger project. Jump in! Or ask us to help you find a task.

Get started as a...

Funder

Become a financial backer to sustain and grow this project, increase your influence, express gratitude, build prosperity consciousness, and help transform world finance!

Tester

When reporting bugs, don't forget to search the tracker for a similar bug report. Otherwise, open a new bug by clicking "New issue", or http://bugs.hledger.org/new.

Enhancement requests are sometimes added to the tracker,but for these consider using the IRC channel and mail list (see Getting help). Both are archived and linkable, so the idea won't be lost. There is also a collection of wishes at the old trello board.

Developer

Review code

Build hledger

  1. get stack and (except on Windows, where stack provides it) git, then:
  2. git clone http://github.com/simonmichael/hledger hledger && cd hledger && stack install

In more detail:

1. Get tools

stack is the recommended tool for building hledger. You can use cabal-install if you prefer, but that requires more expertise; the hledger docs assume stack.

git is the version control tool needed to fetch the hledger source and submit changes. On Windows, stack will install this as well.

2. Get the source

$ git clone http://github.com/simonmichael/hledger hledger   # or git:

3. Build/install

$ cd hledger
$ stack install

This builds all the hledger packages, and installs executables in $HOME/.local/bin/ (or the Windows equivalent), which you should add to your $PATH.

This can take a while! To save time, you can build fewer packages, eg just the CLI:

$ stack install hledger

You can also build and run in place, without installing executables:

$ stack build; stack exec -- hledger [ARGS]

Note stack fetches most required dependencies automatically, but not C libraries such as curses or terminfo, which you might need to install yourself, using your system's package manager. In case of trouble, see download.

Use GHCI

These all work from the main hledger source directory (at least).

First, ensure all required dependencies are installed with these commands. (You might also need to install some system libs like terminfo or curses.)

$ stack test
$ stack bench

Get a GHCI prompt for hledger-lib:

$ cd hledger-lib; stack ghci hledger-lib

Changing into the package directory isn't actually needed, but it enables a custom .ghci script which sets a more useful short prompt.

Get a GHCI prompt for hledger:

$ cd hledger; stack ghci hledger

Get a GHCI prompt for hledger-ui:

$ cd hledger-ui; stack ghci hledger-ui

Get a GHCI prompt for hledger-web:

$ cd hledger-web; stack ghci hledger-web

hledger-web also needs to find some things in its current directory (like the static/ directory). This normally just works, if not please send details.

Add a test

Fix a bug or add a feature

Get your changes accepted

Follow the usual github workflow:

If you're new to this process, help.github.com may be useful.

Add yourself to the contributor list

Technical Writer

Graphics Designer

Communicator

Marketing and market understanding is vital.

Maintainer

Help with issue management

Help with packaging

Help with project management

Do a major release

Do a minor release

Differences from a major release: work in a release branch, set PACKAGES only to the affected package(s), don't run make setversion.

  1. cleanup
    • review working copies (laptop, server, website) & branches, commit pending changes
  2. document
    • */*.cabal for affected package(s) (descriptions, tested-with, files..)
    • */CHANGES for affected package(s)
    • site/release-notes.md
    • site/manual.md (commands, options, --help, ledger compatibility..)
    • site/step-by-step.md
    • site/how-to-*
  3. test
    • make unittest
    • make functest
    • make haddocktest
  4. branch
    • switch to release branch (git checkout X.Y)
  5. version
    • edit .version (don't make setversion)
    • manually bump version for affected package(s): cabal files, manual..
  6. package
    • set Makefile's PACKAGES to affected package(s)
    • make cabalsdist
  7. test
    • install from tarball(s) into a clean directory
  8. tag
    • make tagrelease
  9. push
    • git push --tags
  10. upload
    • make cabalupload
  11. announce
    • [email hledger]
    • [tweet]

More about...

Project

Mission

Why was hledger created ?

Mainly:

Also:

What is the hledger project's current mission ?

  1. Provide peace of mind: bring clarity, relief, and peace of mind to folks stressed, confused, overwhelmed by finances.
  2. Educate and empower: help individuals and communities achieve clarity, accountability and mastery with money and time.

Roles and activities

Issue tracking

The hledger project's issue tracker is on github. It contains:

Use these shortcut urls for quick access:

Labels are used to categorise:

Clicking blue topic labels is a good way to review issues in a topic you're interested in.

In 2017, milestones are not used much. Projects are being used to organise the roadmap.

You might see some experiments in estimate tracking, where some issue names might have a suffix noting estimated and spent time. Basic format: [ESTIMATEDTOTALTASKTIME|TIMESPENTSOFAR]. Examples:

[2]       two hours estimated, no time spent
[..]      half an hour estimated (a dot is ~a quarter hour, as in timedot format)
[1d]      one day estimated (a day is ~4 hours)
[1w]      one week estimated (a week is ~5 days or ~20 hours)
[3|2]     three hours estimated, about two hours spent so far  
[1|1w|2d] first estimate one hour, second estimate one week, about two days spent so far 

Estimates are always for the total time cost (not time remaining). Estimates are not usually changed, a new estimate is added instead. Numbers are very approximate, but better than nothing.

The trello board (trello.hledger.org) is a categorised collection of wishlist items, this should probably be considered deprecated.

Make

A Makefile is provided to make common developer tasks easy to remember, and to insulate us a little from the ever-evolving Haskell tools ecosystem. Using it is entirely optional, but recommended. You'll need GNU Make installed.

The Makefile is self-documenting. Run make to see a list of the main make rules:

$ make
Makefile:37: -------------------- hledger make rules --------------------
Makefile:39: make [help] -- list documented rules in this makefile. make -n RULE shows more detail.
Makefile:204: (INSTALLING:)
Makefile:206: make install -- download dependencies and install hledger executables to ~/.local/bin or equivalent (with stack)
Makefile:231: (BUILDING:)
Makefile:235: make build -- download dependencies and build hledger executables (with stack)
Makefile:304: make hledgerdev -- quickly build the hledger executable (with ghc and -DDEVELOPMENT)
...

To see what a make rule will do without actually doing it, use the -n flag:

$ make build -n
stack build
$ make test -n
(stack test \
		&& echo pkgtest PASSED) || echo pkgtest FAILED
(stack exec hledger test \
		&& echo builtintest PASSED) || echo builtintest FAILED
(COLUMNS=80 PATH=`pwd`/bin:/home/simon/src/hledger/bin:/home/simon/.local/bin:/home/simon/.cabal/bin:/opt/ghc/7.10.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/var/lib/gems/1.9.1/bin stack exec -- shelltest --execdir -- -j16 --hide-successes tests \
		&& echo functest PASSED) || echo functest FAILED

Shake

Shake.hs in the top directory complements the Makefile; it is used for some more complex scripts relating to documentation.

Tests

Run the package tests of all (or selected) packages. Does not include hledger's functional tests.

$ stack test [PKG]

Run some hledger unit tests via a built-in hledger command:

$ [stack exec] hledger test

Run hledger's functional tests:

$ stack install shelltestrunner
$ make functest

Run both unit and functional tests:

$ make test

Test generation of haddock docs:

$ make haddocktest

Benchmarking

Benchmarks are standard performance measurements, which we define using bench declarations in cabal files. There is one in hledger.cabal, with related code and data files in hledger/bench/.

To run the standard hledger benchmark, use stack bench hledger. This installs haskell dependencies (but not system dependencies) and rebuilds as needed, then runs hledger/bench/bench.hs, which by default shows quick elapsed-time measurements for several operations on a standard data file:

$ stack bench hledger
NOTE: the bench command is functionally equivalent to 'build --bench'
...
hledger-0.27: benchmarks
Running 1 benchmarks...
Benchmark bench: RUNNING...
Benchmarking hledger in /Users/simon/src/hledger/hledger with timeit
read bench/10000x1000x10.journal        [1.57s]
print                                   [1.29s]
register                                [1.92s]
balance                                 [0.21s]
stats                                   [0.23s]
Total: 5.22s
Benchmark bench: FINISH

bench.hs has some other modes, which you can use by compiling and running it directly. --criterion reports more detailed and dependable measurements, but takes longer:

$ cd hledger; stack exec -- ghc -ibench bench/bench && bench/bench --criterion
...
Linking bench/bench ...
Benchmarking hledger in /Users/simon/src/hledger/hledger with criterion
benchmarking read bench/10000x1000x10.journal
time                 1.414 s    (1.234 s .. 1.674 s)
                     0.996 R²   (0.989 R² .. 1.000 R²)
mean                 1.461 s    (1.422 s .. 1.497 s)
std dev              59.69 ms   (0.0 s .. 62.16 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking print
time                 1.323 s    (1.279 s .. 1.385 s)
                     1.000 R²   (0.999 R² .. 1.000 R²)
mean                 1.305 s    (1.285 s .. 1.316 s)
std dev              17.20 ms   (0.0 s .. 19.14 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking register
time                 1.995 s    (1.883 s .. 2.146 s)
                     0.999 R²   (0.998 R² .. NaN R²)
mean                 1.978 s    (1.951 s .. 1.995 s)
std dev              25.09 ms   (0.0 s .. 28.26 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking balance
time                 251.3 ms   (237.6 ms .. 272.4 ms)
                     0.998 R²   (0.997 R² .. 1.000 R²)
mean                 260.4 ms   (254.3 ms .. 266.5 ms)
std dev              7.609 ms   (3.192 ms .. 9.638 ms)
variance introduced by outliers: 16% (moderately inflated)

benchmarking stats
time                 325.5 ms   (299.1 ms .. 347.2 ms)
                     0.997 R²   (0.985 R² .. 1.000 R²)
mean                 329.2 ms   (321.5 ms .. 339.6 ms)
std dev              11.08 ms   (2.646 ms .. 14.82 ms)
variance introduced by outliers: 16% (moderately inflated)

--simplebench shows a table of elapsed-time measurements for the commands defined in bench/default.bench. It can also show the results for multiple h/ledger executables side by side, if you tweak the bench.hs code. Unlike the other modes, it does not link with the hledger code directly, but runs the "hledger" executable found in $PATH (so ensure that's the one you intend to test).

$ cd hledger; stack exec -- ghc -ibench bench/bench && bench/bench --simplebench
Benchmarking /Users/simon/.local/bin/hledger in /Users/simon/src/hledger/hledger with simplebench and shell
Using bench/default.bench
Running 4 tests 1 times with 1 executables at 2015-08-23 16:58:59.128112 UTC:
1: hledger -f bench/10000x1000x10.journal print	[3.27s]
1: hledger -f bench/10000x1000x10.journal register	[3.65s]
1: hledger -f bench/10000x1000x10.journal balance	[2.06s]
1: hledger -f bench/10000x1000x10.journal stats	[2.13s]

Summary (best iteration):

+-----------------------------------------++---------+
|                                         || hledger |
+=========================================++=========+
| -f bench/10000x1000x10.journal print    ||    3.27 |
| -f bench/10000x1000x10.journal register ||    3.65 |
| -f bench/10000x1000x10.journal balance  ||    2.06 |
| -f bench/10000x1000x10.journal stats    ||    2.13 |
+-----------------------------------------++---------+

bench's --simplebench mode is based on a standalone tool, tools/simplebench.hs. simplebench.hs is a generic benchmarker of one or more executables (specified on the command line) against one or more sets of command-line arguments (specified in a file). It has a better command-line interface than bench.hs, so you may find it more convenient for comparing multiple hledger versions, or hledger and ledger. Eg:

$ stack exec -- ghc tools/simplebench
[1 of 1] Compiling Main             ( tools/simplebench.hs, tools/simplebench.o )
Linking tools/simplebench ...
$ tools/simplebench -h
tools/simplebench -h
simplebench: at least one executable needed
bench [-f testsfile] [-n iterations] [-p precision] executable1 [executable2 ...]

Run some functional tests with each of the specified executables,
where a test is "zero or more arguments supported by all executables",
and report the best execution times.

  -f testsfile   --testsfile=testsfile    file containing tests, one per line, default: bench.tests
  -n iterations  --iterations=iterations  number of test iterations to run, default: 2
  -p precision   --precision=precision    show times with this precision, default: 2
  -v             --verbose                show intermediate results
  -h             --help                   show this help

Tips:
- executables may have arguments if enclosed in quotes
- tests can be commented out with #
- results are saved in benchresults.{html,txt}
cd hledger; $ ../tools/simplebench -f bench/default.bench hledger ledger
Using bench/default.bench
Running 4 tests 2 times with 2 executables at 2015-08-24 04:24:37.257068 UTC:

Summary (best iteration):

+-----------------------------------------++---------+--------+
|                                         || hledger | ledger |
+=========================================++=========+========+
| -f bench/10000x1000x10.journal print    ||    3.24 |   0.43 |
| -f bench/10000x1000x10.journal register ||    3.80 |   3.48 |
| -f bench/10000x1000x10.journal balance  ||    2.05 |   0.18 |
| -f bench/10000x1000x10.journal stats    ||    2.10 |   0.19 |
+-----------------------------------------++---------+--------+

Finally, for quick, fine-grained performance measurements when troubleshooting or optimising, I use dev.hs.

Sample journal files

Synthetic data files like examples/100x100x10.journal are useful for benchmarks and testing. The numbers describe the number of transactions, number of accounts, and maximum account depth respectively. They are generated by tools/generatejournal.hs. They should get built automatically as needed, if not you can use make samplejournals:

$ make samplejournals
ghc tools/generatejournal.hs
[1 of 1] Compiling Main             ( tools/generatejournal.hs, tools/generatejournal.o )
Linking tools/generatejournal ...
tools/generatejournal 100 100 10 >examples/100x100x10.journal
tools/generatejournal 1000 1000 10 >examples/1000x1000x10.journal
tools/generatejournal 1000 10000 10 >examples/1000x10000x10.journal
tools/generatejournal 10000 1000 10 >examples/10000x1000x10.journal
tools/generatejournal 10000 10000 10 >examples/10000x10000x10.journal
tools/generatejournal 100000 1000 10 >examples/100000x1000x10.journal
tools/generatejournal 3 5 5 >examples/ascii.journal
tools/generatejournal 3 5 5 --chinese >examples/chinese.journal
tools/generatejournal 3 5 5 --mixed >examples/mixed.journal

Documentation

Project documentation lives in a number of places:

How to prepare changelogs & release notes

Draft:

Changelogs:

Release notes:

Code

hledger is a suite of applications, tools and libraries. The main hledger code repository is github.com/simonmichael/hledger (aka code.hledger.org). There are also various hledger addons maintained as separate projects with their own repos.

Within the main repo, there are a number of separate cabal packages, making it easier to pick and choose parts of hledger to install or to package. They are:

hledger-lib

package, exported modules, code

Core data models, parsing, standard reports, and utilities. Most data types are defined in Hledger.Data.Types, while functions that operate on them are defined in Hledger.Data.TYPENAME. Under Hledger.Read are parsers for the supported input formats. Data files are parsed into a Journal, which contains a list of Transactions, each containing multiple Postings of some MixedAmount (multiple single-CommoditySymbol Amounts) to some AccountName. When needed, the Journal is further processed to derive a Ledger, which contains summed Accounts. In Hledger.Reports there are standard reports, which extract useful data from the Journal or Ledger.

Here's a diagram of the main data model:

diagram

hledger

package, exported modules, code, manual

hledger's command line interface, and command line options and utilities for other hledger tools.

Try tracing the execution of a hledger command:

  1. Hledger.Cli.Main:main parses the command line to select a command, then
  2. gives it to Hledger.Cli.Utils:withJournalDo, which runs it after doing all the initial parsing.
  3. Parsing code is under hledger-lib:Hledger.Read, eg Hledger.Read.JournalReader.
  4. Commands extract useful information from the parsed data model using hledger-lib:Hledger.Reports, and
  5. render in plain text for console output (or another output format, like CSV).
  6. Everything uses the data types and utilities from hledger-lib:Hledger.Data and hledger-lib:Hledger.Utils.

hledger-ui

package, code, manual

A curses-style text interface.

hledger-web

package, exported modules, code, manual

A web interface. hledger-web starts a web server built with the yesod framework, and (by default) opens a web browser view on it. It reads the journal file(s) at startup and again whenever they change. It can also write (append) new transactions to the journal file.

There are two main views, which can be filtered with queries:

There is also:

Most of the action is in

Handler module and function names end with R, like the yesod-generated route type they deal with.

Dynamically generated page content is mostly inline hamlet. Lucius/Julius files and widgets generally are not used, except for the default layout.

Here are some ways to run it during development:

hledger-api

package, code, manual

A web API server. Uses the servant framework.

Quality

Relevant tools include:

Code review

IRC Join #hledger (chat log; see also #ledger)
Mail list list.hledger.org (Gmane)
Twitter #hledger, see also #ledgercli, #plaintextaccounting, @LedgerTips
hledger-web demo   demo.hledger.org
hledger-api demo demo.hledger.org/api, in swagger editor
Trello old backlog/wishlist planning board
Github simonmichael/hledger (alias: code.hledger.org), forks
commits, COMMITS!
open bugs, open wishes, open unknowns, open pull requests, all issues
issues with bounty tag, bountysource bounties, codemill bounties, codefund bounties
stars: (#99 of ~30k starred haskell projects in 2016/04, #71 in 2016/12, #65 in 2017/3, #64 in 2017/5)
Throughput Graph
Travis CI travis ubuntu build status
Appveyor CI appveyor windows build status latest developer builds
Hackage packages: hledger-lib, hledger, hledger-ui, hledger-web, hledger-api, hledger-diff, hledger-interest, hledger-irr, *hledger*
reverse deps: hledger-lib, hledger, hledger-ui, hledger-web, hledger-api
Stackage build-constraints.yaml, open hledger-related issues
Debian source packages: haskell-hledger-lib, bugs, haskell-hledger, bugs, haskell-hledger-ui, bugs, haskell-hledger-web, bugs
binary packages:
 stable hledger, bugs, hledger-web, bugs
 testing hledger, bugs, hledger-web, bugs
 unstable hledger, bugs, hledger-ui, bugs, hledger-web, bugs
 experimental hledger, bugs, hledger-ui, bugs, hledger-web, bugs
 all *hledger*
popularity stats: hledger, hledger-ui, hledger-web
PTS help
Ubuntu source packages: haskell-hledger-lib, bugs, haskell-hledger, bugs, haskell-hledger-ui, bugs, haskell-hledger-web, bugs
binary packages: *hledger*
Gentoo hledger, hledger-web, *hledger*
Fedora hledger, *hledger*, hledger (package db), Haskell SIG
Void Linux hledger*
Nix *hledger*
Homebrew hledger
Sandstorm hledger web app & reviews, issues
Reference GHC Can I Use