Skip to content

smlx/jiratime

Repository files navigation

JiraTime

Tag and Release Coverage Status Go Report Card

jiratime makes it easy to submit worklog records to Jira quickly from the command line. It accepts timesheets on standard input so works well with any editor that lets you pipe chunks of text to external commands, such as (neo)vim.

jiratime only works with Atlassian Cloud hosted Jira, and does not support the deprecated self-hosted Jira server.


Get it

Download the latest release on github, or:

go install github.com/smlx/jiratime/cmd/jiratime@latest

How it works

Configuration

jiratime reads configuration from $XDG_CONFIG_HOME/jiratime/config.yml. This example config.yml has a list of regular expressions for implicitly identifying issues, and another list for matching timesheet entries to be ignored.

jiraURL: https://example.atlassian.net/
issues:
- id: XYZ-1
  defaultComment: email / slack
  regexes:
  - ^admin( .+)?$
- id: ABC-2
  defaultComment: Primary On-call
  regexes:
  - ^pd$
ignore:
- ^lunch$

Timesheet format

The timesheet format is minimal and opinionated.

Sample timesheet

0900-0945
admin - TPS report cover sheet
0945-1100
XYZ-123 - fighting fires
1100-1200
admin
1200-1300
lunch
1300-1400
ABC-987
- more meetings after...
lunch
1400-1430
ABC-988
will the meetings
ever stop?

Features

  • Each entry begins with a duration written as a 24-hour time range.
  • The comment body of a timesheet entry is anything on the first line following an issue match, and any lines below before the next duration or end of the timesheet.
  • Comment lines are trimmed of spaces and hyphens before being added to the comment body.
  • Jira issues may be identified explicitly by putting the name of the issue at the start of the first line of the comment body.
  • Jira issues may be identified implicitly by matching the first line against a configured list of regular expressions.
  • Regular expressions for implicitly identifying issues may have a capture group. In that case the capture group becomes part of the comment body.
  • Timesheet entries may be ignored by matching the first line against a configured list of regular expressions.
  • Implicitly matched issues can have a default comment configured which will be automatically added to the Jira worklog record if no comment is defined in the timesheet.

Timesheet entry processing examples

Each row in this table shows:

  1. a single timesheet entry
  2. configuration involved in processing the entry
  3. the worklog record generated by the entry
| Timesheet Entry                | Configuration                 | Jira Worklog Record              |
| ---                            | ---                           | ---                              |
| 0900-0945                      | issues:                       | Issue:    XYZ-1                  |
| admin - TPS report cover sheet | - id: XYZ-1                   | Start:    0900 (local TZ)        |
|                                | defaultComment: email / slack | Duration: 45 minutes             |
|                                | regexes:                      | Comment:  TPS report cover sheet |
|                                | - ^admin( .+)?$               |                                  |
| ---                            | ---                           | ---                              |
| 0945-1100                      | n/a (explicit issue)          | Issue:    XYZ-123                |
| XYZ-123 - fighting fires       |                               | Start:    0945 (local TZ)        |
|                                |                               | Duration: 1 hour, 15 minutes     |
|                                |                               | Comment:  fighting fires         |
| ---                            | ---                           | ---                              |
| 1100-1200                      | issues:                       | Issue:    XYZ-1                  |
| admin                          | - id: XYZ-1                   | Start:    1100 (local TZ)        |
|                                | defaultComment: email / slack | Duration: 1 hour                 |
|                                | regexes:                      | Comment:  email / slack          |
|                                | - ^admin( .+)?$               |                                  |
| ---                            | ---                           | ---                              |
| 1200-1300                      | ignore:                       | n/a (this entry is skipped)      |
| lunch                          | - ^lunch$                     |                                  |
| ---                            | ---                           | ---                              |
| 1300-1400                      | n/a (explicit issue)          | Issue:    ABC-987                |
| ABC-987                        |                               | Start:    1300 (local TZ)        |
| - more meetings after...       |                               | Duration: 1 hour                 |
| lunch                          |                               | Comment:  more meetings after... |
|                                |                               |           lunch                  |
| ---                            | ---                           | ---                              |
| 1400-1430                      | n/a (explicit issue)          | Issue:    ABC-988                |
| ABC-988                        |                               | Start:    1400 (local TZ)        |
| will the meetings              |                               | Duration: 30 minutes             |
| ever stop?                     |                               | Comment:  will the meetings      |
|                                |                               |           ever stop?             |

Design Philosophy

jiratime tries hard to submit timesheets atomically. That is, either all worklog records are submitted, or none are. It does this by checking that all issues identified are valid Jira issues before submitting any worklogs. Unfortunately there is no transactional batch API for Jira worklogs.

jiratime exits with a return code of zero and no output on success. On failure it will exit with a non-zero return code and a message on standard error.

Authorization Setup

jiratime authentication requires a one-time initial setup.

jiratime can authenticate using OAuth2 (more secure, more complex setup, the default), or using an API Key and HTTP Basic Auth (less secure, but simpler).

OAuth2

Configure jiratime app in Jira cloud

  1. Visit Atlassian's developer console, and log in.
  2. Create a new "OAuth 2.0 integration".
  3. Name the app jiratime, and agree to Atlassian's T&Cs.
Scopes
  1. Select "Permissions", then "Add", and "Configure" the "Jira platform REST API".
  2. Ensure these scopes are selected:
    • read:jira-work
    • write:jira-work
Authorization callback URL
  1. Select "Authorization", then "Configure" the "OAuth 2.0 (3LO)" authorization type.
  2. Set the callback URL to http://localhost:8080/oauth/redirect
Gather app Credentials
  1. Select "Settings".
  2. In "Authentication details", copy the "Client ID" and "Secret" values.

Complete OAuth2 authorization flow

Create $XDG_CONFIG_HOME/jiratime/auth.yml and add your app credentials:

oauth2:
  clientID: chiYahchob7xoThahvohH5quae6Di0Ee
  secret: HxHOiN3bD5l93X3qugp9bHI8EKEJ7xVV4vcj6tG3vr7GFqxtxruMrkLcgtZAOPrZ

Run jiratime authorize and open the generated URL in your browser. Once you click "Accept", you should see this message in your browser:

Authorization successful. You may now close this page.

$XDG_CONFIG_HOME/jiratime/auth.yml now contains a token that jiratime will use and automatically refresh as required.

Basic Auth

  1. Visit Atlassian's developer console, and log in.
  2. Create a new API Key.
  3. Add the credentials to $XDG_CONFIG_HOME/jiratime/basicauth.yml.

Example:

user: my.name@example.com
apiKey: SZ8411BnS9dKw2FDArWAe9eYiToNTx6ugtCzR2UTtaSFmXnw16bYcBuiLFYuqSffnFEzdXti8HcVRWPaLjPxFaOx7KVlckD2amFoxiiwK2hTBlfYU62CrJJ3VfZprwf3

Usage

Timesheet submission

Once configured and authorized, calling jiratime parses and submits timesheets read from standard input. It assumes all times are from the current local day.

Command line:

$ jiratime < timesheet

vim visual selection:

animation demonstrating visual selection

:'<,'>!jiratime

vim line selection:

animation demonstrating line selection

:130,135!jiratime

FAQ

Why does Tempo not show all the entries submitted by jiratime?

It seems to sometimes take a while for worklog entries submitted via API to show up in Tempo. Try refreshing after a few minutes.

Why do the entries have a weird time offset?

jiratime submits all times in your local timezone. Jira has a single timezone that it uses to display worklogs regardless of localisation settings. I can't see this timezone displayed anywhere in the UI, but you can see it via the API. Use scripts/check-worklog.sh to dump issue worklogs, including timezone.

How do I submit timesheets for yesterday?

jiratime submit --day-offset="-1" < timesheet

Options

Run jiratime --help to discover the command line options and contextual help.