jira-time-tracker 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 codeonym-oss
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21
+ OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: jira-time-tracker
3
+ Version: 0.1.0
4
+ Summary: Track how much estimated work (story points, hours, days…) came into being in a Jira project over a period, per issue and per person.
5
+ Keywords: jira,atlassian,story-points,estimates,time-tracking,cli
6
+ Author: codeonym-oss
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Information Technology
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Office/Business
22
+ Classifier: Topic :: Software Development :: Bug Tracking
23
+ Classifier: Typing :: Typed
24
+ Requires-Dist: keyring>=24
25
+ Requires-Dist: platformdirs>=4
26
+ Requires-Dist: requests>=2.31
27
+ Requires-Dist: rich>=13
28
+ Requires-Dist: typer>=0.12
29
+ Requires-Python: >=3.10
30
+ Project-URL: Homepage, https://github.com/codeonym-oss/jira-time-tracker
31
+ Project-URL: Repository, https://github.com/codeonym-oss/jira-time-tracker
32
+ Project-URL: Issues, https://github.com/codeonym-oss/jira-time-tracker/issues
33
+ Project-URL: Changelog, https://github.com/codeonym-oss/jira-time-tracker/blob/main/CHANGELOG.md
34
+ Description-Content-Type: text/markdown
35
+
36
+ # jira-time-tracker
37
+
38
+ `jtt` answers one question about a Jira Cloud project: **how much estimated work
39
+ came into being over a period, on which issues, and by whom?**
40
+
41
+ The estimate is whatever field your organisation tracks. That could be story
42
+ points, an hours or days custom field, or Jira's own original estimate or time
43
+ spent. You pick the field once per project.
44
+
45
+ ```
46
+ $ jtt contributions --from 2026-09-24 --to 2026-09-30 --by day
47
+ ╭─ Contributions · DEMO ─────────────────────────────────────────────────────────╮
48
+ │ Field Story point estimate (customfield_10016, points) │
49
+ │ Period Thu 24 Sep 2026 included → Wed 30 Sep 2026 excluded · 6 days │
50
+ │ Credit each change goes to whoever held the issue when it happened │
51
+ ╰───────────────────────────────────────────────────────────────────────────────╯
52
+ Person Net SP Added Share Issues Created Done
53
+ ─────────────────────────────────────────────────────────────────────────────────
54
+ Alice Martin +16 SP 16 SP 100% 3 4 (2 SP) 2 (8 SP) ████████
55
+
56
+ Per day
57
+ When Net SP
58
+ ─────────────────────────────────────────
59
+ Thu 24 Sep +5 SP ██████████████████
60
+ Fri 25 Sep +8.5 SP ██████████████████████████████
61
+ Sat 26 Sep ±0
62
+ …
63
+ ╭─ Statistics ───────────────────────────────────────────────────────────────────╮
64
+ │ Net added +16 SP │
65
+ │ Per changed issue 5.33 SP average over 3 │
66
+ │ Biggest DEMO-729 +8 SP Share a published report through a public link │
67
+ │ Done in period 2 issues (8 SP) │
68
+ │ Daily trend ▅█ ▂ │
69
+ │ Busiest day Fri 25 Sep (8.5 SP, 3 active days) │
70
+ ╰────────────────────────────────────────────────────────────────────────────────╯
71
+ ```
72
+
73
+ ## Install
74
+
75
+ It needs Python 3.10 or newer and works the same on Linux, macOS and Windows.
76
+
77
+ ```sh
78
+ uv tool install git+https://github.com/codeonym/jira-time-tracker # or: pipx install git+…
79
+ jtt --help
80
+ ```
81
+
82
+ To install from a local checkout, run `uv tool install .` or `pipx install .`.
83
+
84
+ ## Getting started
85
+
86
+ ```sh
87
+ jtt login # site URL, account email, API token (typed hidden)
88
+ jtt init # for each project: choose the field that holds the estimate, and its unit
89
+ jtt calculate --period last-week
90
+ ```
91
+
92
+ 1. **`jtt login`** checks the token against Jira before storing it. Create a
93
+ token at <https://id.atlassian.com/manage-profile/security/api-tokens>. To
94
+ switch account or rotate the token, run `jtt logout` first, then `jtt login`
95
+ again.
96
+ 2. **`jtt init`** walks through every project you can see and lists its numeric
97
+ fields. A ★ marks the fields on the project's create screens, and those come
98
+ first. You pick one and say what its numbers mean: points, seconds, minutes,
99
+ hours, days or weeks. For time units you also pick the unit reports should
100
+ show. Jira's built-in time tracking fields always hold seconds, so the tool
101
+ sets that unit for you. Your last choice is offered as the default for the
102
+ next project. Type `s` to skip a project or `q` to stop; progress is saved
103
+ after each project.
104
+
105
+ To skip the questions, pass everything as options:
106
+ `jtt init -p DEMO --field customfield_10016 --unit points`.
107
+
108
+ ## Commands
109
+
110
+ | Command | What it does |
111
+ |---|---|
112
+ | `login` / `logout [--purge]` / `whoami [--check]` | Manage the account. `logout` keeps project settings; `--purge` forgets them too |
113
+ | `init [-p KEY…] [--reconfigure]` | Choose each project's tracked field and unit |
114
+ | `config show \| path \| default KEY \| set KEY … \| remove KEY \| calendar …` | Inspect or edit settings without re-running `init` |
115
+ | `projects [--configured]` | Projects you can see and what each one tracks |
116
+ | `fields [-p KEY] [--counts]` | A project's numeric fields, optionally with how many issues hold a value |
117
+ | `fetch` | Issues touched in a period, with their current value (`--json` for raw output) |
118
+ | `calculate` | Net amount per issue for the whole project or one person, at four levels of detail |
119
+ | `collaborators` | People who can be assigned to the project, with their current open, in-progress and done issues |
120
+ | `contributions [--by day\|week]` | Per-person net, added, removed, share, issues created and issues finished, plus statistics and a daily trend |
121
+ | `export -o FILE [-k issues\|changes\|contributions\|daily]` | Write CSV (opens in Excel), JSON or Markdown |
122
+
123
+ Every report takes `-p KEY` (default: the project set by `init`), a period, and
124
+ `--as hours|days|…` to show time amounts in another unit.
125
+
126
+ ### Periods
127
+
128
+ Periods are **half-open: the start day is included and the end day is
129
+ excluded.** `--from 2026-09-01 --to 2026-10-01` is all of September. Leave out
130
+ `--to` and the period runs through today.
131
+
132
+ You can also use a named period instead:
133
+ `--period today | yesterday | this-week | last-week | this-month | last-month | this-quarter | last-quarter | this-year | last-7-days | last-30-days`.
134
+ Weeks start on Monday.
135
+
136
+ Days are the calendar days Jira shows in *your* Jira profile's time zone, which
137
+ is also how Jira reads dates in queries. The tool never works out time zone
138
+ offsets itself, because local time zone data can disagree with Jira's. For
139
+ example, tzdata 2026d keeps Morocco at +00 after Ramadan 2026, while Jira still
140
+ shows +01.
141
+
142
+ ### Choosing whose work to count (`--user`)
143
+
144
+ `--user` accepts `me`, an account id, or part of a name or email.
145
+
146
+ - `calculate --user X` (the default, `--attribution was`) counts every change
147
+ made in the period on issues X held at some point in the period.
148
+ - `--attribution holder` only counts changes made while X held the issue.
149
+ - `contributions` always credits each change to whoever held the issue when it
150
+ happened. The value an issue was created with goes to the first person
151
+ assigned to it. That way the per-person totals add up to the project total.
152
+
153
+ ### Levels of detail
154
+
155
+ `-v`, `-vv` (or `--vv`) and `-vvv` (or `--vvv`) work on `calculate` and
156
+ `contributions`:
157
+
158
+ - **`-v`** adds current value, type, status and current assignee (↪ marks a
159
+ task that has since moved to someone else), and where each amount came from.
160
+ - **`-vv`** also lists issues with no change, and adds a per-issue timeline of
161
+ each change: when it happened, the value before and after, and who made it.
162
+ - **`-vvv`** also shows the query sent to Jira, a trace of every API request,
163
+ and changes outside the period (struck through).
164
+
165
+ ## How the delta is computed
166
+
167
+ For each issue touched in the period, the tool reads its full change history
168
+ from Jira and adds up the changes to the tracked field that happened inside the
169
+ period. Two Jira behaviours shape this:
170
+
171
+ - **The query can't use "last updated" as an end date.** Jira only records when
172
+ an issue was *last* updated. An issue edited inside the period and again
173
+ afterwards would drop out of a query ending at the period's end. So the query
174
+ only filters on that date from below, and the change history decides what
175
+ falls inside the period.
176
+ - **A value entered when an issue is created leaves no history entry.** Jira's
177
+ history starts at the first edit. For an issue created inside the period, the
178
+ tool adds back the value it was created with. That value is the "before" side
179
+ of its first later change, or its current value if the field was never
180
+ edited.
181
+
182
+ Dates in queries are always sent with an explicit `00:00`. Tested on a live
183
+ site, bare dates did not give exact bounds: `assignee WAS X DURING ("2026-09-24",
184
+ "2026-09-25")` matched issues first assigned in the afternoon of the 25th, and
185
+ `DURING ("2026-09-25", "2026-09-25")` matched nothing.
186
+
187
+ ## Where things are kept
188
+
189
+ | What | Where |
190
+ |---|---|
191
+ | Settings (site, projects, fields, units) | `config.json` in the user config directory; `jtt config path` prints it. On Linux: `~/.config/jira-time-tracker`, macOS: `~/Library/Application Support/jira-time-tracker`, Windows: `%LOCALAPPDATA%\jira-time-tracker` |
192
+ | API token | The system keyring: Windows Credential Manager, macOS Keychain, or Secret Service (GNOME Keyring / KWallet) on Linux. Where no keyring is available (headless servers, WSL, containers), it goes in `credentials.json` next to the settings, created **0600** inside a **0700** directory |
193
+
194
+ The token is never written to `config.json` or printed.
195
+
196
+ Environment overrides:
197
+ - `JTT_CREDENTIAL_BACKEND=file|keyring` forces where the token is stored.
198
+ - `JTT_API_TOKEN` supplies a token for CI; it is never stored.
199
+ - `JTT_CONFIG_DIR` moves the settings directory.
200
+
201
+ ## Development
202
+
203
+ ```sh
204
+ uv sync
205
+ uv run pytest
206
+ ```
207
+
208
+ The tests run the real CLI and HTTP client against a local fake Jira that
209
+ replays issue data captured from a live site.
210
+
211
+ `legacy/jira_tasks.py` is the single-file script this project grew from, kept
212
+ unchanged.
@@ -0,0 +1,177 @@
1
+ # jira-time-tracker
2
+
3
+ `jtt` answers one question about a Jira Cloud project: **how much estimated work
4
+ came into being over a period, on which issues, and by whom?**
5
+
6
+ The estimate is whatever field your organisation tracks. That could be story
7
+ points, an hours or days custom field, or Jira's own original estimate or time
8
+ spent. You pick the field once per project.
9
+
10
+ ```
11
+ $ jtt contributions --from 2026-09-24 --to 2026-09-30 --by day
12
+ ╭─ Contributions · DEMO ─────────────────────────────────────────────────────────╮
13
+ │ Field Story point estimate (customfield_10016, points) │
14
+ │ Period Thu 24 Sep 2026 included → Wed 30 Sep 2026 excluded · 6 days │
15
+ │ Credit each change goes to whoever held the issue when it happened │
16
+ ╰───────────────────────────────────────────────────────────────────────────────╯
17
+ Person Net SP Added Share Issues Created Done
18
+ ─────────────────────────────────────────────────────────────────────────────────
19
+ Alice Martin +16 SP 16 SP 100% 3 4 (2 SP) 2 (8 SP) ████████
20
+
21
+ Per day
22
+ When Net SP
23
+ ─────────────────────────────────────────
24
+ Thu 24 Sep +5 SP ██████████████████
25
+ Fri 25 Sep +8.5 SP ██████████████████████████████
26
+ Sat 26 Sep ±0
27
+ …
28
+ ╭─ Statistics ───────────────────────────────────────────────────────────────────╮
29
+ │ Net added +16 SP │
30
+ │ Per changed issue 5.33 SP average over 3 │
31
+ │ Biggest DEMO-729 +8 SP Share a published report through a public link │
32
+ │ Done in period 2 issues (8 SP) │
33
+ │ Daily trend ▅█ ▂ │
34
+ │ Busiest day Fri 25 Sep (8.5 SP, 3 active days) │
35
+ ╰────────────────────────────────────────────────────────────────────────────────╯
36
+ ```
37
+
38
+ ## Install
39
+
40
+ It needs Python 3.10 or newer and works the same on Linux, macOS and Windows.
41
+
42
+ ```sh
43
+ uv tool install git+https://github.com/codeonym/jira-time-tracker # or: pipx install git+…
44
+ jtt --help
45
+ ```
46
+
47
+ To install from a local checkout, run `uv tool install .` or `pipx install .`.
48
+
49
+ ## Getting started
50
+
51
+ ```sh
52
+ jtt login # site URL, account email, API token (typed hidden)
53
+ jtt init # for each project: choose the field that holds the estimate, and its unit
54
+ jtt calculate --period last-week
55
+ ```
56
+
57
+ 1. **`jtt login`** checks the token against Jira before storing it. Create a
58
+ token at <https://id.atlassian.com/manage-profile/security/api-tokens>. To
59
+ switch account or rotate the token, run `jtt logout` first, then `jtt login`
60
+ again.
61
+ 2. **`jtt init`** walks through every project you can see and lists its numeric
62
+ fields. A ★ marks the fields on the project's create screens, and those come
63
+ first. You pick one and say what its numbers mean: points, seconds, minutes,
64
+ hours, days or weeks. For time units you also pick the unit reports should
65
+ show. Jira's built-in time tracking fields always hold seconds, so the tool
66
+ sets that unit for you. Your last choice is offered as the default for the
67
+ next project. Type `s` to skip a project or `q` to stop; progress is saved
68
+ after each project.
69
+
70
+ To skip the questions, pass everything as options:
71
+ `jtt init -p DEMO --field customfield_10016 --unit points`.
72
+
73
+ ## Commands
74
+
75
+ | Command | What it does |
76
+ |---|---|
77
+ | `login` / `logout [--purge]` / `whoami [--check]` | Manage the account. `logout` keeps project settings; `--purge` forgets them too |
78
+ | `init [-p KEY…] [--reconfigure]` | Choose each project's tracked field and unit |
79
+ | `config show \| path \| default KEY \| set KEY … \| remove KEY \| calendar …` | Inspect or edit settings without re-running `init` |
80
+ | `projects [--configured]` | Projects you can see and what each one tracks |
81
+ | `fields [-p KEY] [--counts]` | A project's numeric fields, optionally with how many issues hold a value |
82
+ | `fetch` | Issues touched in a period, with their current value (`--json` for raw output) |
83
+ | `calculate` | Net amount per issue for the whole project or one person, at four levels of detail |
84
+ | `collaborators` | People who can be assigned to the project, with their current open, in-progress and done issues |
85
+ | `contributions [--by day\|week]` | Per-person net, added, removed, share, issues created and issues finished, plus statistics and a daily trend |
86
+ | `export -o FILE [-k issues\|changes\|contributions\|daily]` | Write CSV (opens in Excel), JSON or Markdown |
87
+
88
+ Every report takes `-p KEY` (default: the project set by `init`), a period, and
89
+ `--as hours|days|…` to show time amounts in another unit.
90
+
91
+ ### Periods
92
+
93
+ Periods are **half-open: the start day is included and the end day is
94
+ excluded.** `--from 2026-09-01 --to 2026-10-01` is all of September. Leave out
95
+ `--to` and the period runs through today.
96
+
97
+ You can also use a named period instead:
98
+ `--period today | yesterday | this-week | last-week | this-month | last-month | this-quarter | last-quarter | this-year | last-7-days | last-30-days`.
99
+ Weeks start on Monday.
100
+
101
+ Days are the calendar days Jira shows in *your* Jira profile's time zone, which
102
+ is also how Jira reads dates in queries. The tool never works out time zone
103
+ offsets itself, because local time zone data can disagree with Jira's. For
104
+ example, tzdata 2026d keeps Morocco at +00 after Ramadan 2026, while Jira still
105
+ shows +01.
106
+
107
+ ### Choosing whose work to count (`--user`)
108
+
109
+ `--user` accepts `me`, an account id, or part of a name or email.
110
+
111
+ - `calculate --user X` (the default, `--attribution was`) counts every change
112
+ made in the period on issues X held at some point in the period.
113
+ - `--attribution holder` only counts changes made while X held the issue.
114
+ - `contributions` always credits each change to whoever held the issue when it
115
+ happened. The value an issue was created with goes to the first person
116
+ assigned to it. That way the per-person totals add up to the project total.
117
+
118
+ ### Levels of detail
119
+
120
+ `-v`, `-vv` (or `--vv`) and `-vvv` (or `--vvv`) work on `calculate` and
121
+ `contributions`:
122
+
123
+ - **`-v`** adds current value, type, status and current assignee (↪ marks a
124
+ task that has since moved to someone else), and where each amount came from.
125
+ - **`-vv`** also lists issues with no change, and adds a per-issue timeline of
126
+ each change: when it happened, the value before and after, and who made it.
127
+ - **`-vvv`** also shows the query sent to Jira, a trace of every API request,
128
+ and changes outside the period (struck through).
129
+
130
+ ## How the delta is computed
131
+
132
+ For each issue touched in the period, the tool reads its full change history
133
+ from Jira and adds up the changes to the tracked field that happened inside the
134
+ period. Two Jira behaviours shape this:
135
+
136
+ - **The query can't use "last updated" as an end date.** Jira only records when
137
+ an issue was *last* updated. An issue edited inside the period and again
138
+ afterwards would drop out of a query ending at the period's end. So the query
139
+ only filters on that date from below, and the change history decides what
140
+ falls inside the period.
141
+ - **A value entered when an issue is created leaves no history entry.** Jira's
142
+ history starts at the first edit. For an issue created inside the period, the
143
+ tool adds back the value it was created with. That value is the "before" side
144
+ of its first later change, or its current value if the field was never
145
+ edited.
146
+
147
+ Dates in queries are always sent with an explicit `00:00`. Tested on a live
148
+ site, bare dates did not give exact bounds: `assignee WAS X DURING ("2026-09-24",
149
+ "2026-09-25")` matched issues first assigned in the afternoon of the 25th, and
150
+ `DURING ("2026-09-25", "2026-09-25")` matched nothing.
151
+
152
+ ## Where things are kept
153
+
154
+ | What | Where |
155
+ |---|---|
156
+ | Settings (site, projects, fields, units) | `config.json` in the user config directory; `jtt config path` prints it. On Linux: `~/.config/jira-time-tracker`, macOS: `~/Library/Application Support/jira-time-tracker`, Windows: `%LOCALAPPDATA%\jira-time-tracker` |
157
+ | API token | The system keyring: Windows Credential Manager, macOS Keychain, or Secret Service (GNOME Keyring / KWallet) on Linux. Where no keyring is available (headless servers, WSL, containers), it goes in `credentials.json` next to the settings, created **0600** inside a **0700** directory |
158
+
159
+ The token is never written to `config.json` or printed.
160
+
161
+ Environment overrides:
162
+ - `JTT_CREDENTIAL_BACKEND=file|keyring` forces where the token is stored.
163
+ - `JTT_API_TOKEN` supplies a token for CI; it is never stored.
164
+ - `JTT_CONFIG_DIR` moves the settings directory.
165
+
166
+ ## Development
167
+
168
+ ```sh
169
+ uv sync
170
+ uv run pytest
171
+ ```
172
+
173
+ The tests run the real CLI and HTTP client against a local fake Jira that
174
+ replays issue data captured from a live site.
175
+
176
+ `legacy/jira_tasks.py` is the single-file script this project grew from, kept
177
+ unchanged.
@@ -0,0 +1,156 @@
1
+ [project]
2
+ name = "jira-time-tracker"
3
+ version = "0.1.0"
4
+ description = "Track how much estimated work (story points, hours, days…) came into being in a Jira project over a period, per issue and per person."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.10"
9
+ dependencies = [
10
+ "keyring>=24",
11
+ "platformdirs>=4",
12
+ "requests>=2.31",
13
+ "rich>=13",
14
+ "typer>=0.12",
15
+ ]
16
+ keywords = [
17
+ "jira",
18
+ "atlassian",
19
+ "story-points",
20
+ "estimates",
21
+ "time-tracking",
22
+ "cli",
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 3 - Alpha",
26
+ "Environment :: Console",
27
+ "Intended Audience :: Developers",
28
+ "Intended Audience :: Information Technology",
29
+ "Operating System :: OS Independent",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3 :: Only",
32
+ "Programming Language :: Python :: 3.10",
33
+ "Programming Language :: Python :: 3.11",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
36
+ "Programming Language :: Python :: 3.14",
37
+ "Topic :: Office/Business",
38
+ "Topic :: Software Development :: Bug Tracking",
39
+ "Typing :: Typed",
40
+ ]
41
+
42
+ [[project.authors]]
43
+ name = "codeonym-oss"
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/codeonym-oss/jira-time-tracker"
47
+ Repository = "https://github.com/codeonym-oss/jira-time-tracker"
48
+ Issues = "https://github.com/codeonym-oss/jira-time-tracker/issues"
49
+ Changelog = "https://github.com/codeonym-oss/jira-time-tracker/blob/main/CHANGELOG.md"
50
+
51
+ [project.scripts]
52
+ jtt = "jira_time_tracker.cli:app"
53
+ jira-time-tracker = "jira_time_tracker.cli:app"
54
+
55
+ [build-system]
56
+ requires = ["uv_build>=0.8.22,<0.13"]
57
+ build-backend = "uv_build"
58
+
59
+ [dependency-groups]
60
+ test = [
61
+ "pytest>=8",
62
+ "pytest-cov>=7",
63
+ ]
64
+ dev = [
65
+ { include-group = "test" },
66
+ "commitizen>=4.8",
67
+ "pre-commit>=4.3",
68
+ "pyright>=1.1.400",
69
+ "ruff>=0.16",
70
+ "types-requests>=2.31",
71
+ ]
72
+
73
+ [tool.ruff]
74
+ line-length = 100
75
+ target-version = "py310"
76
+ extend-exclude = ["legacy"]
77
+
78
+ [tool.ruff.lint]
79
+ select = [
80
+ "E",
81
+ "W",
82
+ "F",
83
+ "I",
84
+ "B",
85
+ "UP",
86
+ "SIM",
87
+ "RUF",
88
+ "C4",
89
+ "PT",
90
+ "PIE",
91
+ "RET",
92
+ "TC",
93
+ "PERF",
94
+ "N",
95
+ "D",
96
+ ]
97
+ ignore = [
98
+ "D100",
99
+ "D104",
100
+ "D105",
101
+ "D107",
102
+ "D203",
103
+ "D213",
104
+ "RUF001",
105
+ "RUF002",
106
+ "RUF003",
107
+ ]
108
+
109
+ [tool.ruff.lint.per-file-ignores]
110
+ "tests/**" = ["D"]
111
+ "src/jira_time_tracker/cli.py" = ["TC"]
112
+
113
+ [tool.commitizen]
114
+ name = "cz_conventional_commits"
115
+ allowed_prefixes = [
116
+ "Merge",
117
+ "Revert",
118
+ "fixup!",
119
+ "squash!",
120
+ ]
121
+
122
+ [tool.pyright]
123
+ include = [
124
+ "src",
125
+ "tests",
126
+ "scripts",
127
+ ]
128
+ pythonVersion = "3.10"
129
+ typeCheckingMode = "standard"
130
+
131
+ [tool.pytest.ini_options]
132
+ addopts = [
133
+ "--strict-markers",
134
+ "--strict-config",
135
+ "-ra",
136
+ "--cov",
137
+ "--cov-report=term-missing",
138
+ ]
139
+ testpaths = ["tests"]
140
+ xfail_strict = true
141
+ filterwarnings = ["error"]
142
+
143
+ [tool.coverage.run]
144
+ source = ["jira_time_tracker"]
145
+ branch = true
146
+
147
+ [tool.coverage.report]
148
+ fail_under = 80
149
+ show_missing = true
150
+ skip_covered = true
151
+ exclude_also = [
152
+ "if TYPE_CHECKING:",
153
+ "@overload",
154
+ "raise NotImplementedError",
155
+ "if __name__ == .__main__.:",
156
+ ]
@@ -0,0 +1,110 @@
1
+ [project]
2
+ name = "jira-time-tracker"
3
+ version = "0.1.0"
4
+ description = "Track how much estimated work (story points, hours, days…) came into being in a Jira project over a period, per issue and per person."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "codeonym-oss" }]
9
+ requires-python = ">=3.10"
10
+ dependencies = [
11
+ "keyring>=24",
12
+ "platformdirs>=4",
13
+ "requests>=2.31",
14
+ "rich>=13",
15
+ "typer>=0.12",
16
+ ]
17
+ keywords = ["jira", "atlassian", "story-points", "estimates", "time-tracking", "cli"]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Environment :: Console",
21
+ "Intended Audience :: Developers",
22
+ "Intended Audience :: Information Technology",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3 :: Only",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Programming Language :: Python :: 3.14",
31
+ "Topic :: Office/Business",
32
+ "Topic :: Software Development :: Bug Tracking",
33
+ "Typing :: Typed",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/codeonym-oss/jira-time-tracker"
38
+ Repository = "https://github.com/codeonym-oss/jira-time-tracker"
39
+ Issues = "https://github.com/codeonym-oss/jira-time-tracker/issues"
40
+ Changelog = "https://github.com/codeonym-oss/jira-time-tracker/blob/main/CHANGELOG.md"
41
+
42
+ [project.scripts]
43
+ jtt = "jira_time_tracker.cli:app"
44
+ jira-time-tracker = "jira_time_tracker.cli:app"
45
+
46
+ [build-system]
47
+ requires = ["uv_build>=0.8.22,<0.13"]
48
+ build-backend = "uv_build"
49
+
50
+ [dependency-groups]
51
+ test = [
52
+ "pytest>=8",
53
+ "pytest-cov>=7",
54
+ ]
55
+ dev = [
56
+ {include-group = "test"},
57
+ "commitizen>=4.8",
58
+ "pre-commit>=4.3",
59
+ "pyright>=1.1.400",
60
+ "ruff>=0.16",
61
+ "types-requests>=2.31",
62
+ ]
63
+
64
+ [tool.ruff]
65
+ line-length = 100
66
+ target-version = "py310"
67
+ # The pre-project script, kept verbatim.
68
+ extend-exclude = ["legacy"]
69
+
70
+ [tool.ruff.lint]
71
+ select = [
72
+ "E", "W", "F", "I", "B", "UP", "SIM", "RUF", "C4", "PT", "PIE", "RET",
73
+ "TC", "PERF", "N", "D",
74
+ ]
75
+ ignore = [
76
+ "D100", "D104", "D105", "D107", # module/package/magic/__init__ docstrings
77
+ "D203", "D213", # pick D211 + D212 (summary on the first line)
78
+ "RUF001", "RUF002", "RUF003", # the terminal UI deliberately uses →, ×, ±, ★ and friends
79
+ ]
80
+
81
+ [tool.ruff.lint.per-file-ignores]
82
+ "tests/**" = ["D"]
83
+ # Typer reads the command signatures' annotations at runtime, so their imports must stay real.
84
+ "src/jira_time_tracker/cli.py" = ["TC"]
85
+
86
+ [tool.commitizen]
87
+ # Only used to validate messages (commit-msg hook + CI); versions and changelog are release-please's job.
88
+ name = "cz_conventional_commits"
89
+ allowed_prefixes = ["Merge", "Revert", "fixup!", "squash!"]
90
+
91
+ [tool.pyright]
92
+ include = ["src", "tests", "scripts"]
93
+ pythonVersion = "3.10"
94
+ typeCheckingMode = "standard"
95
+
96
+ [tool.pytest.ini_options]
97
+ addopts = ["--strict-markers", "--strict-config", "-ra", "--cov", "--cov-report=term-missing"]
98
+ testpaths = ["tests"]
99
+ xfail_strict = true
100
+ filterwarnings = ["error"]
101
+
102
+ [tool.coverage.run]
103
+ source = ["jira_time_tracker"]
104
+ branch = true
105
+
106
+ [tool.coverage.report]
107
+ fail_under = 80
108
+ show_missing = true
109
+ skip_covered = true
110
+ exclude_also = ["if TYPE_CHECKING:", "@overload", "raise NotImplementedError", "if __name__ == .__main__.:"]