{"id":21338258,"url":"https://github.com/smlx/jiratime","last_synced_at":"2025-07-12T13:30:31.421Z","repository":{"id":37201145,"uuid":"387527148","full_name":"smlx/jiratime","owner":"smlx","description":"Submit timesheets to Jira from the command line","archived":false,"fork":false,"pushed_at":"2024-11-13T00:07:18.000Z","size":553,"stargazers_count":11,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-13T01:18:10.294Z","etag":null,"topics":["go","hacktoberfest","jira"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smlx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-19T16:24:10.000Z","updated_at":"2024-11-13T00:07:21.000Z","dependencies_parsed_at":"2023-10-11T21:00:08.600Z","dependency_job_id":"234af163-822e-4a5b-96de-3f52bbd27e97","html_url":"https://github.com/smlx/jiratime","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smlx%2Fjiratime","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smlx%2Fjiratime/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smlx%2Fjiratime/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smlx%2Fjiratime/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smlx","download_url":"https://codeload.github.com/smlx/jiratime/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225820242,"owners_count":17529143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","hacktoberfest","jira"],"created_at":"2024-11-22T00:12:13.800Z","updated_at":"2024-11-22T00:12:14.385Z","avatar_url":"https://github.com/smlx.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JiraTime\n\n![Tag and Release](https://github.com/smlx/jiratime/workflows/Tag%20and%20Release/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/smlx/jiratime/badge.svg?branch=main)](https://coveralls.io/github/smlx/jiratime?branch=main)\n[![Go Report Card](https://goreportcard.com/badge/github.com/smlx/jiratime)](https://goreportcard.com/report/github.com/smlx/jiratime)\n\n\u003cimg align=\"left\" src=\"jiratime.jpg\"\u003e\n\n`jiratime` makes it easy to submit worklog records to Jira quickly from the command line.\nIt 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.\n\n`jiratime` only works with Atlassian Cloud hosted Jira, and does not support the deprecated self-hosted Jira server.\n\n\u003cbr clear=\"left\" /\u003e\n\n## Get it\n\nDownload the latest [release](https://github.com/smlx/jiratime/releases) on github, or:\n\n```\ngo install github.com/smlx/jiratime/cmd/jiratime@latest\n```\n\n## How it works\n\n### Configuration\n\n`jiratime` reads configuration from [`$XDG_CONFIG_HOME`](https://github.com/adrg/xdg#xdg-base-directory)`/jiratime/config.yml`.\nThis example `config.yml` has a list of regular expressions for implicitly identifying issues, and another list for matching timesheet entries to be ignored.\n\n```\njiraURL: https://example.atlassian.net/\nissues:\n- id: XYZ-1\n  defaultComment: email / slack\n  regexes:\n  - ^admin( .+)?$\n- id: ABC-2\n  defaultComment: Primary On-call\n  regexes:\n  - ^pd$\nignore:\n- ^lunch$\n```\n\n### Timesheet format\n\nThe timesheet format is minimal and opinionated.\n\n#### Sample timesheet\n\n```\n0900-0945\nadmin - TPS report cover sheet\n0945-1100\nXYZ-123 - fighting fires\n1100-1200\nadmin\n1200-1300\nlunch\n1300-1400\nABC-987\n- more meetings after...\nlunch\n1400-1430\nABC-988\nwill the meetings\never stop?\n```\n\n#### Features\n\n* Each entry begins with a duration written as a 24-hour time range.\n* 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.\n* Comment lines are trimmed of spaces and hyphens before being added to the comment body.\n* Jira issues may be identified explicitly by putting the name of the issue at the start of the first line of the comment body.\n* Jira issues may be identified implicitly by matching the first line against a configured list of regular expressions.\n* Regular expressions for implicitly identifying issues may have a capture group. In that case the capture group becomes part of the comment body.\n* Timesheet entries may be ignored by matching the first line against a configured list of regular expressions.\n* 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.\n\n#### Timesheet entry processing examples\n\nEach row in this table shows:\n\n1. a single timesheet entry\n2. configuration involved in processing the entry\n3. the worklog record generated by the entry\n\n```\n| Timesheet Entry                | Configuration                 | Jira Worklog Record              |\n| ---                            | ---                           | ---                              |\n| 0900-0945                      | issues:                       | Issue:    XYZ-1                  |\n| admin - TPS report cover sheet | - id: XYZ-1                   | Start:    0900 (local TZ)        |\n|                                | defaultComment: email / slack | Duration: 45 minutes             |\n|                                | regexes:                      | Comment:  TPS report cover sheet |\n|                                | - ^admin( .+)?$               |                                  |\n| ---                            | ---                           | ---                              |\n| 0945-1100                      | n/a (explicit issue)          | Issue:    XYZ-123                |\n| XYZ-123 - fighting fires       |                               | Start:    0945 (local TZ)        |\n|                                |                               | Duration: 1 hour, 15 minutes     |\n|                                |                               | Comment:  fighting fires         |\n| ---                            | ---                           | ---                              |\n| 1100-1200                      | issues:                       | Issue:    XYZ-1                  |\n| admin                          | - id: XYZ-1                   | Start:    1100 (local TZ)        |\n|                                | defaultComment: email / slack | Duration: 1 hour                 |\n|                                | regexes:                      | Comment:  email / slack          |\n|                                | - ^admin( .+)?$               |                                  |\n| ---                            | ---                           | ---                              |\n| 1200-1300                      | ignore:                       | n/a (this entry is skipped)      |\n| lunch                          | - ^lunch$                     |                                  |\n| ---                            | ---                           | ---                              |\n| 1300-1400                      | n/a (explicit issue)          | Issue:    ABC-987                |\n| ABC-987                        |                               | Start:    1300 (local TZ)        |\n| - more meetings after...       |                               | Duration: 1 hour                 |\n| lunch                          |                               | Comment:  more meetings after... |\n|                                |                               |           lunch                  |\n| ---                            | ---                           | ---                              |\n| 1400-1430                      | n/a (explicit issue)          | Issue:    ABC-988                |\n| ABC-988                        |                               | Start:    1400 (local TZ)        |\n| will the meetings              |                               | Duration: 30 minutes             |\n| ever stop?                     |                               | Comment:  will the meetings      |\n|                                |                               |           ever stop?             |\n```\n\n### Design Philosophy\n\n`jiratime` tries hard to submit timesheets atomically.\nThat is, either all worklog records are submitted, or none are.\nIt does this by checking that all issues identified are valid Jira issues before submitting any worklogs.\nUnfortunately there is no transactional batch API for Jira worklogs.\n\n`jiratime` exits with a return code of zero and no output on success.\nOn failure it will exit with a non-zero return code and a message on standard error.\n\n## Authorization Setup\n\n`jiratime` authentication requires a one-time initial setup.\n\n`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).\n\n### OAuth2\n\n#### Configure jiratime app in Jira cloud\n\n1. Visit Atlassian's [developer console](https://developer.atlassian.com/console/myapps/), and log in.\n2. Create a new \"OAuth 2.0 integration\".\n3. Name the app `jiratime`, and agree to Atlassian's T\u0026Cs.\n\n##### Scopes\n\n1. Select \"Permissions\", then \"Add\", and \"Configure\" the \"Jira platform REST API\".\n2. Ensure these scopes are selected:\n   * `read:jira-work`\n   * `write:jira-work`\n\n##### Authorization callback URL\n\n1. Select \"Authorization\", then \"Configure\" the \"OAuth 2.0 (3LO)\" authorization type.\n2. Set the callback URL to `http://localhost:8080/oauth/redirect`\n\n##### Gather app Credentials\n\n1. Select \"Settings\".\n2. In \"Authentication details\", copy the \"Client ID\" and \"Secret\" values.\n\n#### Complete OAuth2 authorization flow\n\nCreate `$XDG_CONFIG_HOME/jiratime/auth.yml` and add your app credentials:\n\n```yaml\noauth2:\n  clientID: chiYahchob7xoThahvohH5quae6Di0Ee\n  secret: HxHOiN3bD5l93X3qugp9bHI8EKEJ7xVV4vcj6tG3vr7GFqxtxruMrkLcgtZAOPrZ\n```\n\nRun `jiratime authorize` and open the generated URL in your browser.\nOnce you click \"Accept\", you should see this message in your browser:\n\n```\nAuthorization successful. You may now close this page.\n```\n\n`$XDG_CONFIG_HOME/jiratime/auth.yml` now contains a token that `jiratime` will use and automatically refresh as required.\n\n### Basic Auth\n\n1. Visit Atlassian's [developer console](https://developer.atlassian.com/console/myapps/), and log in.\n2. Create a new API Key.\n3. Add the credentials to `$XDG_CONFIG_HOME/jiratime/basicauth.yml`.\n\nExample:\n\n```yaml\nuser: my.name@example.com\napiKey: SZ8411BnS9dKw2FDArWAe9eYiToNTx6ugtCzR2UTtaSFmXnw16bYcBuiLFYuqSffnFEzdXti8HcVRWPaLjPxFaOx7KVlckD2amFoxiiwK2hTBlfYU62CrJJ3VfZprwf3\n```\n\n## Usage\n\n### Timesheet submission\n\nOnce configured and authorized, calling `jiratime` parses and submits timesheets read from standard input.\nIt assumes all times are from the current local day.\n\nCommand line:\n\n```\n$ jiratime \u003c timesheet\n```\n\n`vim` visual selection:\n\n![animation demonstrating visual selection](visual-selection.gif)\n\n```\n:'\u003c,'\u003e!jiratime\n```\n\n`vim` line selection:\n\n![animation demonstrating line selection](line-selection.gif)\n\n```\n:130,135!jiratime\n```\n\n## FAQ\n\n### Why does Tempo not show all the entries submitted by jiratime?\n\nIt seems to sometimes take a while for worklog entries submitted via API to show up in Tempo.\nTry refreshing after a few minutes.\n\n### Why do the entries have a weird time offset?\n\n`jiratime` submits all times in your local timezone.\nJira has a single timezone that it uses to display worklogs regardless of localisation settings.\nI can't see this timezone displayed anywhere in the UI, but you can see it via the API.\nUse `scripts/check-worklog.sh` to dump issue worklogs, including timezone.\n\n### How do I submit timesheets for yesterday?\n\n```\njiratime submit --day-offset=\"-1\" \u003c timesheet\n```\n\n## Options\n\nRun `jiratime --help` to discover the command line options and contextual help.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmlx%2Fjiratime","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmlx%2Fjiratime","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmlx%2Fjiratime/lists"}