Hourly#
Hourly is a command-line time tracking tool for git projects. Hourly parses your commit messages for clock-in
and clock-out
keywords to precisely estimate work hours. Designed for developers and project managers, hourly makes it easy to see how and where you spend your time. When configured with Stripe or BTCPay, hourly can generate invoices for your specified wage.
Usage#
Work sessions#
To clock in:
hourly-in
The above command updates the header of your work log (WorkLog.md
by default) and commits it with the message "clock-in".
Stage any changes to your code base. When you are ready to commit:
hourly commit.message="my commit message"
Hourly updates the work log with your commit message. Feel free to use the work log to provide additional context. When you are finished committing other work for this session, you may clock out:
hourly-out
Again, hourly updates the work log and commits it with the message "clock-out" along with any other staged files. Read more about configuring your work log.
Timesheets#
When you are ready to generate a timesheet for your repo, run hourly from your git directory:
hourly-report
Hourly parses all the commit messages for clock in/out keywords and uses git's timestamps to determine how long each session lasted.
For example, here's what happens when you run hourly on the hourly repo itself:
hourly-report repo.start_date="2018-10-21" repo.end_date="2019-3-10" repo.ignore="pro bono" pay period: 2018-10-28 13:44:48-04:00 -> 2019-02-25 12:49:51-05:00 ignoring pro bono TimeIn LogIn TimeOut LogOut TimeDelta Hours 0 2018-10-28 13:44:48-04:00 clock in 2018-10-28 13:56:35-04:00 clock out 00:11:47 0.196389 1 2019-02-25 10:19:10-05:00 clock in T-1hr 2019-02-25 12:49:51-05:00 clock out T-5m 02:30:41 2.511389 0 days 02:42:28, 2.71 hours worked
To save the timesheet as a csv file, include an ouput prefix:
hourly-report repo.start_date="2018-10-21" repo.end_date="2019-3-10" repo.ignore="pro bono" report.filename=Pembroke pay period: 2018-10-28 13:44:48-04:00 -> 2019-02-25 12:49:51-05:00 ignoring pro bono TimeIn LogIn TimeOut LogOut TimeDelta Hours 0 2018-10-28 13:44:48-04:00 clock in 2018-10-28 13:56:35-04:00 clock out 00:11:47 0.196389 1 2019-02-25 10:19:10-05:00 clock in T-1hr 2019-02-25 12:49:51-05:00 clock out T-5m 02:30:41 2.511389 0 days 02:42:28, 2.71 hours worked writing to file Pembroke-20181028-134448_to_20190225-124951.csv
Visit the Tutorial for a detailed walk-through of how hourly generates timesheets.
Invoicing#
To generate an invoice using stripe:
hourly-report invoice=stripe repo.start_date="Jan 1, 2020" stripe.customer.email=myclient@momandpop.com
The above command generates a time sheet for this repo, calculates earnings, prepares a stripe invoice, and asks you to confirm details. After confirmation, an email will be sent from your Stripe account to myclient@momandpop.com.
The btcpay invoicing is similar:
hourly-report invoice=btcpay repo.start_date="Jan 1, 2020"
After confirmation, hourly tells your btcpay server to generate an invoice and displays the corresponding payment url. Note that BTCPay can be configured for lightning, so streaming payments are possible!
Visit the Payments section for more info.
Getting Started#
Hourly is hosted on github under the Apache 2.0 license
https://github.com/asherp/hourly
Install#
pip install hourly --upgrade
Requirements#
- pandas
- gitpython
- plotly
- hydra
- stripe (optional)
- btcpay-python (optional)
You can get these dependencies like this:
pip install pandas gitpython plotly pip install hydra-core --upgrade
For invoicing:
pip install btcpay-python pip install stripe
For hourly's docs:
pip install mkdocs mkdocs-material markdown-include mknotebooks
Tests#
For integration tests, hourly may be tested against the hourly repo.
Unit tests are based on pytest suite with pytest-cov
pip install pytest pytest-cov
To run the tests, navigate to the base of this repo, then
py.test tests.py --cov=hourly
Configuration#
Hourly
uses Hydra
for customized configuration. The full options are given by hourly's
help command:
hourly --help
A simple hour tracker for git projects This application helps users clock in and out of git repos, as well as generate timesheets for invoicing. Configure hourly to ignore commits by keyword or hashes == Configuration groups == Compose your configuration from those groups (group=option) == Config == Override anything in the config (foo.bar=value) commit: clock: null identity: - name - email message: '' tminus: null compensation: [] config_override: hourly.yaml invoice: null payment: null repo: case_sensitive: false end_date: null errant_clocks: [] gitdir: . ignore: null match_logs: false start_date: null report: currency: '' filename: null pandas: display: max_columns: 10 max_colwidth: 45 max_rows: null width: 600 timesheet: true wage: null work: false vis: frequency: 1 d plotly: figure: margin: pad: 0 plot: animation_opts: null auto_open: true auto_play: true config: null filename: hourly-work.html image: null image_filename: plot_image include_mathjax: cdn include_plotlyjs: cdn link_text: Export to plot.ly output_type: file show_link: false validate: true work_log: bullet: '*' filename: WorkLog.md header_depth: 1 Powered by Hydra (https://hydra.cc) Use --hydra-help to view Hydra specific help
Hourly's default configuration including comments can be seen here.
config_override: hourly.yaml init: false repo: gitdir: . start_date: null end_date: null errant_clocks: [] # list of commit hashes to skip case_sensitive: False # should commit message filters be case-sensitive ignore: null # ignore work containing string, ie 'pro bono' match_logs: False # should all clock-ins be paired with clock-outs report: timesheet: false # print timesheet work: false # print work log filename: '???' # csv file to save report to pandas: display: max_rows: null max_columns: 10 max_colwidth: 45 width: 600 commit: clock: '???' # 'in' will update WorkLog.md and commit with message "clock-in" tminus: null # '15m' will prepend 'T-15m' to commit message (ignored if clock is null) message: '' # 'my message' will append 'my message' to commit message identity: # how to identify contributors - name - email compensation: [] # sets wages and currency per developer work_log: filename: WorkLog.md header_depth: 1 # determines markdown header size bullet: '*' vis: # set to null to prevent plotting frequency: '1 d' # start small - experienced users can override plotly: # plotly keywords figure: hovermode: 'x' margin: pad: 0 plot: show_link: False link_text: 'Export to plot.ly' validate: True output_type: file include_plotlyjs: 'cdn' filename: hourly-work.html auto_open: True image: Null image_filename: plot_image # image_width: 800 # image_height: 600 config: Null include_mathjax: 'cdn' auto_play: True animation_opts: Null handle_errors: exit # or raise verbosity:
Each of these can be overridden at runtime. For example,
hourly commit.clock=in vis=null report.timesheet=False
This will update the WorkLog.md file and commit a clock-in message without visualizing or printing the timesheet.
Note
hourly-in
is just syntactic sugar for hourly commit.clock=in vis=null report.timesheet=False
.
But if we want to override hourly's defaults without typing them in each time,
we can specify an hourly.yaml file in our git repo. Hourly will look
for this file (via the config_override
option) and override its default configuration.
Bug
Your project's config_override
will even override command line arguments!
An example of a custom override file is found in the top-level of the hourly repo:
repo: errant_clocks: - d9ec537b36475b565df6b28d0cab6edc3a89f2da ignore: 'pro bono' work_log: header_depth: 3 commit: identity: - email vis: frequency: '1 d' plotly: # plotly keywords plot: output_type: div auto_open: false filename: docs/hourly-work.html compensation: - name: Asher Pembroke email: apembroke@gmail.com wage: pi: 1.0
A common use case would be permanently overriding the filename of the work_log you are committing against, to avoid merge conflicts if multiple developers are working on the same project.
Visualization#
The git repo for hourly has a custom configuration that allows us to embed the work hours as a graph in the mkdocs site.
If we run hourly-report
from its own git repo, the graph div gets stored in
docs/hourly-work.html
.
The graph is embedded using the markdown-include extension in mkdocs.yml
.
Then we add the following in our site page:
{! docs/hourly-work.html !}
Which embeds the graph below: