diff --git a/docs/user-guide/commands.md b/docs/user-guide/commands.md index 7561519c..b1151cdc 100644 --- a/docs/user-guide/commands.md +++ b/docs/user-guide/commands.md @@ -17,15 +17,16 @@ Add time for project with tag(s) that was not tracked live. Example: - $ watson add --from "2018-03-20 12:00:00" --to "2018-03-20 13:00:00" \ - programming +addfeature + $ watson add --from "2018-03-20 12:00:00" --to "2018-03-20 13:00:00" + + $ watson add --from "07:00" --to "09:00" + + $ watson add --from "2018-03-20 07:00" --to "09:00" + ### Options Flag | Help -----|----- -`-f, --from DATE` | Date and time of start of tracked activity [required] -`-t, --to DATE` | Date and time of end of tracked activity [required] +`-f, --from TEXT` | Date and time of start of tracked activity. If date is omitted todays date is used. [required] +`-t, --to TEXT` | Date and time of end of tracked activity. If date is omitted todays date is used. [required] `-c, --confirm-new-project` | Confirm addition of new project. `-b, --confirm-new-tag` | Confirm creation of new tag. `--help` | Show this message and exit. diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 00000000..8595c36b --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,100 @@ +from watson import cli +from click.testing import CliRunner +import json +import os +import arrow +import pytest + +@pytest.fixture +def setup(tmpdir): + os.environ["WATSON_DIR"] = tmpdir.strpath + +# test for watson add --from "hh:mm" --to "hh:mm" +def test_time_only(setup): + + runner = CliRunner() + + test_data = [("13:00", "15:00"), + ("3:00", "17:00"), + ("1:00", "3:41")] + + project = "test_time_only" + data_index = 0 + + for data in test_data: + from_time = data[0] + to_time = data[1] + + result = runner.invoke(cli.cli, ["add", project, '--from' , from_time, '--to', to_time]) + + result = runner.invoke(cli.cli, ["log", "-j"]) + output = json.loads(result.output)[data_index] + + assert output["project"] == project + today = arrow.now().floor("day").format("YYYY-MM-DD") + assert today in output["start"] + assert from_time in output["start"] + assert today in output["stop"] + assert to_time in output["stop"] + + data_index += 1 + +# test for watson add --from "yyyy-mm-dd hh:mm" --to "hh:mm" +def test_from_date_time(setup): + runner = CliRunner() + + test_data = [("2016-03-24", "07:32", "08:54"), + ("2017-04-28", "14:00", "17:31")] + + project = "test_date_time" + + for data in test_data: + date = data[0] + from_time = data[1] + to_time = data[2] + + result = runner.invoke(cli.cli, ["add", project, '--from' , "{} {}".format(date, from_time), '--to', to_time]) + + # as watson log -a crashes, I use -f + result = runner.invoke(cli.cli, ["log", "-f", date, "-j"]) + runner.invoke(cli.cli, ["log"]) + output = json.loads(result.output)[0] + + assert output["project"] == project + assert date in output["start"] + assert from_time in output["start"] + assert date in output["stop"] + assert to_time in output["stop"] + +# test for watson add --from "yyyy-mm-dd hh:mm" --to ""yyyy-mm-dd hh:mm" +def test_date_time(setup): + runner = CliRunner() + + test_data = [("2016-03-24", "07:32", "08:54"), + ("2017-04-28", "14:00", "17:31")] + + project = "test_date_time" + + for data in test_data: + date = data[0] + from_time = data[1] + to_time = data[2] + + result = runner.invoke(cli.cli, ["add", project, '--from' , "{} {}".format(date, from_time), '--to', "{} {}".format(date, to_time)]) + + # as watson log -a crashes, I use -f + result = runner.invoke(cli.cli, ["log", "-f", date, "-j"]) + runner.invoke(cli.cli, ["log"]) + output = json.loads(result.output)[0] + + assert output["project"] == project + assert date in output["start"] + assert from_time in output["start"] + assert date in output["stop"] + assert to_time in output["stop"] + +def test_format_not_supported(setup): + runner = CliRunner() + + result = runner.invoke(cli.cli, ["add", "test", "--from", "crash 13:30", "--to", "13:37"]) + assert "Format not supported" in result.output diff --git a/tests/test_utils.py b/tests/test_utils.py index 162c5e29..bfc53663 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -27,6 +27,10 @@ safe_save, parse_tags, PY2, + isTime, + isDateTime, + getDateTimeToday, + getMergedDateTime ) from . import mock_datetime @@ -228,3 +232,49 @@ def test_confirm_tags_reject_raises_abort(confirm): watson_tags = ['a', 'b'] with pytest.raises(Abort): confirm_project(tags, watson_tags) + + +@pytest.mark.parametrize("date_time_string, result", [ + ("2018-05-28 7:00", False), + ("2018-05.28 7:00", False), + ("7:00", True), + ("17:00", True), + ("117:00", False), + ("117", False), +]) +def test_isTime(date_time_string, result): + assert isTime(date_time_string) == result + + +@pytest.mark.parametrize("date_time_string, result", [ + ("2018-05-28 7:00", True), + ("2018-05-28 07:00", True), + ("2018-05-28 127:00", False), + ("2018-05-f 7:00", False), + ("2018-05-28 7.00", False), + ("7:00", False), +]) +def test_isDateTime(date_time_string, result): + assert isDateTime(date_time_string) == result + + +@pytest.mark.parametrize("date_time, time_string", [ + ("2014-04-01", "07:00"), + ("2014-04-01", "17:00"), +]) +def test_getMergedDateTime(date_time, time_string): + result = arrow.get("{} {}".format(date_time, time_string), 'YYYY-MM-DD HH:mm') + date = arrow.get(date_time, 'YYYY-MM-DD') + assert getMergedDateTime(date, time_string) == result + + +@pytest.mark.parametrize("time_string", [ + ("07:00"), + ("17:00"), + ("09:05"), + ("13:37"), +]) +def test_getDateTimeToday(time_string): + today = datetime.date.today().strftime("%Y-%m-%d") + result = arrow.get("{} {}".format(today, time_string), 'YYYY-MM-DD HH:mm').replace(tzinfo='local') + assert getDateTimeToday(time_string) == result diff --git a/watson/cli.py b/watson/cli.py index 81b64688..3d9f3f37 100644 --- a/watson/cli.py +++ b/watson/cli.py @@ -26,6 +26,10 @@ sorted_groupby, style, parse_tags, + isTime, + isDateTime, + getDateTimeToday, + getMergedDateTime ) @@ -1013,13 +1017,14 @@ def frames(watson): for frame in watson.frames: click.echo(style('short_id', frame.id)) - @cli.command(context_settings={'ignore_unknown_options': True}) @click.argument('args', nargs=-1) -@click.option('-f', '--from', 'from_', required=True, type=Date, - help="Date and time of start of tracked activity") -@click.option('-t', '--to', required=True, type=Date, - help="Date and time of end of tracked activity") +@click.option('-f', '--from', 'from_', required=True, + help="Date and time of start of tracked activity. " + "If date is omitted todays date is used.") +@click.option('-t', '--to', required=True, + help="Date and time of end of tracked activity. " + "If date is omitted todays date is used.") @click.option('-c', '--confirm-new-project', is_flag=True, default=False, help="Confirm addition of new project.") @click.option('-b', '--confirm-new-tag', is_flag=True, default=False, @@ -1032,8 +1037,9 @@ def add(watson, args, from_, to, confirm_new_project, confirm_new_tag): Example: \b - $ watson add --from "2018-03-20 12:00:00" --to "2018-03-20 13:00:00" \\ - programming +addfeature + $ watson add --from "2018-03-20 12:00:00" --to "2018-03-20 13:00:00" + + $ watson add --from "07:00" --to "09:00" + + $ watson add --from "2018-03-20 07:00" --to "09:00" + """ # parse project name from args project = ' '.join( @@ -1053,6 +1059,25 @@ def add(watson, args, from_, to, confirm_new_project, confirm_new_tag): confirm_new_tag): confirm_tags(tags, watson.tags) + # check if and are time without a date, if yes + # convert to todays datetime + if isDateTime(from_) and isDateTime(to): + from_ = arrow.get(from_).replace(tzinfo='local') + to = arrow.get(to).replace(tzinfo='local') + elif isDateTime(from_) and isTime(to): + from_ = arrow.get(from_).replace(tzinfo='local') + to = getMergedDateTime(from_.floor("day"), to) + elif isTime(from_) and isTime(to): + from_ = getDateTimeToday(from_) + to = getDateTimeToday(to) + else: + raise click.ClickException( + style('error', "Format not supported\n" + "Usage:\n" + "watson add --from \"hh:mm\" --to \"hh:mm\"\n" + "watson add --from \"yyyy-mm-dd hh:mm\" --to \"hh:mm\"\n" + "watson add --from \"yyyy-mm-dd hh:mm\" --to \"yyyy-mm-dd hh:mm\"\n")) + # add a new frame, call watson save to update state files frame = watson.add(project=project, tags=tags, from_date=from_, to_date=to) click.echo( diff --git a/watson/utils.py b/watson/utils.py index 97f30ce2..7fa3253a 100644 --- a/watson/utils.py +++ b/watson/utils.py @@ -9,6 +9,7 @@ import click import arrow +import re from .fullmoon import get_last_full_moon @@ -282,3 +283,23 @@ def parse_tags(values_list): )) for i, w in enumerate(values_list) if w.startswith('+') )))) # pile of pancakes ! + + +def isTime(date_time_string): + match = re.search("^\d{1,2}:\d{1,2}$", date_time_string) + return match != None + + +def isDateTime(date_time_string): + match = re.search("^\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}$", date_time_string) + return match != None + + +def getDateTimeToday(time_string): + date_today = arrow.now().floor("day") + return getMergedDateTime(date_today, time_string) + + +def getMergedDateTime(date_time, time_string): + hours, minutes = time_string.split(":") + return date_time.shift(hours=int(hours), minutes=int(minutes))