Skip to content

Commit a0e6829

Browse files
committed
Add command to create time entries
1 parent 423ce41 commit a0e6829

File tree

8 files changed

+84
-8
lines changed

8 files changed

+84
-8
lines changed

redmine/activity.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Activity:
2+
def __init__(self, **kwargs):
3+
self.id = kwargs.get("id")
4+
self.name = kwargs.get("name")
5+
6+
def __str__(self):
7+
return f"{self.id:<4} {self.name:<20}"

redmine/cli/alias.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import click
2-
32
from redmine.cli.config import Config
43

54

redmine/cli/main.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import sys
44
from collections import OrderedDict
55

6-
import click
76
from requests.exceptions import HTTPError
87

8+
import click
9+
from redmine.activity import Activity
910
from redmine.cli.alias import AliasedGroup
1011
from redmine.cli.config import Config, pass_config
1112
from redmine.cli.helpers import get_description, get_note
@@ -297,6 +298,22 @@ def priority(redmine):
297298
click.echo(Priority(**priority))
298299

299300

301+
@list.command()
302+
@click.pass_obj
303+
def activity(redmine):
304+
""" List time tracking activities """
305+
306+
try:
307+
activities = sorted(
308+
redmine.get("enumerations/time_entry_activities"), key=lambda x: x["id"]
309+
)
310+
except HTTPError as e:
311+
return click.echo(click.style(f"Fatal: {e}", fg="red"))
312+
313+
for activity in activities:
314+
click.echo(Activity(**activity))
315+
316+
300317
@list.command()
301318
@click.pass_obj
302319
def user(redmine):
@@ -406,3 +423,21 @@ def times(redmine, **kwargs):
406423

407424
for entry in entries:
408425
click.echo(Time(**entry))
426+
427+
428+
@cli.command()
429+
@click.argument("issue_id")
430+
@click.argument("hours")
431+
@click.option(OPTIONS["on"]["long"], default=None)
432+
@click.option(OPTIONS["activity"]["long"], OPTIONS["activity"]["short"], default=None)
433+
@click.option(OPTIONS["comment"]["long"], OPTIONS["comment"]["short"], default=None)
434+
@click.pass_obj
435+
def spent(redmine, issue_id, hours, **kwargs):
436+
""" Create new time entry """
437+
438+
try:
439+
redmine.create_time_entry(issue_id, hours, **kwargs)
440+
except HTTPError as e:
441+
return click.echo(click.style(f"Fatal: {e}", fg="red"))
442+
443+
click.echo(click.style("Time logged", fg="green"), err=True)

redmine/cli/options.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@
3131
"from": {"long": "--from"},
3232
"to": {"long": "--to"},
3333
"on": {"long": "--on"},
34+
"activity": {"long": "--activity", "short": "-A"},
35+
"comment": {"long": "--comment", "short": "-C"},
3436
}

redmine/issue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def get_header(self):
4242

4343
created_on = datetime.strptime(self.created_on, "%Y-%m-%dT%H:%M:%SZ")
4444
header += (
45-
f"Reported by {self.author['name']} on"
45+
f"Reported by {self.author['name']} on "
4646
f"{created_on.date()} {created_on.time()}\n\n"
4747
)
4848

redmine/redmine.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
import os
33
from urllib.parse import urljoin
44

5-
import click
65
import requests
76

7+
import click
8+
89

910
class Redmine:
1011
def __init__(
@@ -82,7 +83,7 @@ def get_users(self):
8283
memberships.extend(response["memberships"])
8384

8485
users = {}
85-
membership_types = ['user', 'group', 'group_anonymous']
86+
membership_types = ["user", "group", "group_anonymous"]
8687

8788
for m in memberships:
8889
for t in membership_types:
@@ -221,3 +222,29 @@ def create_issue(self, **kwargs):
221222
resp.raise_for_status()
222223

223224
return resp.json()["issue"]
225+
226+
def create_time_entry(self, issue_id, hours, **kwargs):
227+
fields = {
228+
"time_entry": {
229+
"issue_id": issue_id,
230+
"hours": hours,
231+
"comments": kwargs.get("comment"),
232+
}
233+
}
234+
235+
if kwargs.get("activity"):
236+
fields["time_entry"].update({"activity_id": kwargs.get("activity")})
237+
238+
if kwargs.get("on"):
239+
fields["time_entry"].update({"spent_on": kwargs.get("on")})
240+
241+
resp = requests.post(
242+
f"{self.url}/time_entries.json",
243+
json=fields,
244+
headers=self.auth_header,
245+
verify=self.ssl_verify,
246+
)
247+
248+
resp.raise_for_status()
249+
250+
return resp.json()

redmine/time.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,11 @@ def __init__(self, *args, **kwargs):
99
self.spent_on = kwargs.get("spent_on")
1010

1111
def __str__(self):
12-
return f"{self.project['name']:<21.20} {self.issue['id']:>6} {self.user['name']:<21.20} {self.activity['name']:<15.14} {self.spent_on:<11} {self.hours:>6} hours"
12+
time = f"{self.project['name']:<21.20} "
13+
time += f"{self.issue['id']:>6} "
14+
time += f"{self.user['name']:<21.20} "
15+
time += f"{self.activity['name']:<15.14} "
16+
time += f"{self.spent_on:<11} "
17+
time += f"{self.hours:>6} hours"
18+
19+
return time

setup.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
from setuptools import setup, find_packages
4-
3+
from setuptools import find_packages, setup
54

65
with open("README.md") as f:
76
readme = f.read()

0 commit comments

Comments
 (0)