diff --git a/redmine/activity.py b/redmine/activity.py new file mode 100644 index 0000000..8663531 --- /dev/null +++ b/redmine/activity.py @@ -0,0 +1,7 @@ +class Activity: + def __init__(self, **kwargs): + self.id = kwargs.get("id") + self.name = kwargs.get("name") + + def __str__(self): + return f"{self.id:<4} {self.name:<20}" diff --git a/redmine/cli/alias.py b/redmine/cli/alias.py index f455771..322f85c 100644 --- a/redmine/cli/alias.py +++ b/redmine/cli/alias.py @@ -1,5 +1,4 @@ import click - from redmine.cli.config import Config diff --git a/redmine/cli/main.py b/redmine/cli/main.py index b99aedc..9a67300 100644 --- a/redmine/cli/main.py +++ b/redmine/cli/main.py @@ -3,9 +3,10 @@ import sys from collections import OrderedDict -import click from requests.exceptions import HTTPError +import click +from redmine.activity import Activity from redmine.cli.alias import AliasedGroup from redmine.cli.config import Config, pass_config from redmine.cli.helpers import get_description, get_note @@ -297,6 +298,22 @@ def priority(redmine): click.echo(Priority(**priority)) +@list.command() +@click.pass_obj +def activity(redmine): + """ List time tracking activities """ + + try: + activities = sorted( + redmine.get("enumerations/time_entry_activities"), key=lambda x: x["id"] + ) + except HTTPError as e: + return click.echo(click.style(f"Fatal: {e}", fg="red")) + + for activity in activities: + click.echo(Activity(**activity)) + + @list.command() @click.pass_obj def user(redmine): @@ -406,3 +423,21 @@ def times(redmine, **kwargs): for entry in entries: click.echo(Time(**entry)) + + +@cli.command() +@click.argument("issue_id") +@click.argument("hours") +@click.option(OPTIONS["on"]["long"], default=None) +@click.option(OPTIONS["activity"]["long"], OPTIONS["activity"]["short"], default=None) +@click.option(OPTIONS["comment"]["long"], OPTIONS["comment"]["short"], default=None) +@click.pass_obj +def spent(redmine, issue_id, hours, **kwargs): + """ Create new time entry """ + + try: + redmine.create_time_entry(issue_id, hours, **kwargs) + except HTTPError as e: + return click.echo(click.style(f"Fatal: {e}", fg="red")) + + click.echo(click.style("Time logged", fg="green"), err=True) diff --git a/redmine/cli/options.py b/redmine/cli/options.py index 84dcf9a..69b6e1d 100644 --- a/redmine/cli/options.py +++ b/redmine/cli/options.py @@ -31,4 +31,6 @@ "from": {"long": "--from"}, "to": {"long": "--to"}, "on": {"long": "--on"}, + "activity": {"long": "--activity", "short": "-A"}, + "comment": {"long": "--comment", "short": "-C"}, } diff --git a/redmine/issue.py b/redmine/issue.py index 9fe5ed7..ee04725 100644 --- a/redmine/issue.py +++ b/redmine/issue.py @@ -42,7 +42,7 @@ def get_header(self): created_on = datetime.strptime(self.created_on, "%Y-%m-%dT%H:%M:%SZ") header += ( - f"Reported by {self.author['name']} on" + f"Reported by {self.author['name']} on " f"{created_on.date()} {created_on.time()}\n\n" ) diff --git a/redmine/redmine.py b/redmine/redmine.py index aaed270..8603222 100644 --- a/redmine/redmine.py +++ b/redmine/redmine.py @@ -2,9 +2,10 @@ import os from urllib.parse import urljoin -import click import requests +import click + class Redmine: def __init__( @@ -82,7 +83,7 @@ def get_users(self): memberships.extend(response["memberships"]) users = {} - membership_types = ['user', 'group', 'group_anonymous'] + membership_types = ["user", "group", "group_anonymous"] for m in memberships: for t in membership_types: @@ -221,3 +222,29 @@ def create_issue(self, **kwargs): resp.raise_for_status() return resp.json()["issue"] + + def create_time_entry(self, issue_id, hours, **kwargs): + fields = { + "time_entry": { + "issue_id": issue_id, + "hours": hours, + "comments": kwargs.get("comment"), + } + } + + if kwargs.get("activity"): + fields["time_entry"].update({"activity_id": kwargs.get("activity")}) + + if kwargs.get("on"): + fields["time_entry"].update({"spent_on": kwargs.get("on")}) + + resp = requests.post( + f"{self.url}/time_entries.json", + json=fields, + headers=self.auth_header, + verify=self.ssl_verify, + ) + + resp.raise_for_status() + + return resp.json() diff --git a/redmine/time.py b/redmine/time.py index f553f5e..afe7fc3 100644 --- a/redmine/time.py +++ b/redmine/time.py @@ -9,4 +9,11 @@ def __init__(self, *args, **kwargs): self.spent_on = kwargs.get("spent_on") def __str__(self): - 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" + time = f"{self.project['name']:<21.20} " + time += f"{self.issue['id']:>6} " + time += f"{self.user['name']:<21.20} " + time += f"{self.activity['name']:<15.14} " + time += f"{self.spent_on:<11} " + time += f"{self.hours:>6} hours" + + return time diff --git a/setup.py b/setup.py index 1c76ab1..33d5871 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- -from setuptools import setup, find_packages - +from setuptools import find_packages, setup with open("README.md") as f: readme = f.read()