diff --git a/requirements-dev.txt b/requirements-dev.txt index d9db059d..1caae5b9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,6 +11,7 @@ twine # Tests flake8 py +freezegun pytest pytest-datafiles pytest-mock diff --git a/tests/test_cli.py b/tests/test_cli.py index 5c283171..16b706de 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,6 +3,7 @@ from itertools import combinations from datetime import datetime, timedelta +import freezegun import pytest from watson import cli @@ -100,6 +101,46 @@ def test_add_valid_date(runner, watson, test_dt, expected): assert OutputParser.get_start_date(watson, result.output) == expected +@pytest.mark.parametrize('test_dt,expected', VALID_DATES_DATA) +def test_add_now(runner, watson, test_dt, expected): + result = runner.invoke( + cli.add, + ['-f', test_dt, '-t', 'now', 'project-name'], + obj=watson) + assert result.exit_code == 0 + assert "and stopped just now." in result.output + + +@freezegun.freeze_time() +@pytest.mark.parametrize('from_, expected', [ + ( + "30 min ago", + arrow.now().shift(minutes=-30).format('YYYY-MM-DD HH:mm:00'), + ), + ( + "30min ago", + arrow.now().shift(minutes=-30).format('YYYY-MM-DD HH:mm:00'), + ), + ( + "01:30 ago", + arrow.now().shift(hours=-1, minutes=-30).format('YYYY-MM-DD HH:mm:00'), + ), + ( + "01:30:22 ago", + arrow.now() + .shift(hours=-1, minutes=-30, seconds=-22) + .format('YYYY-MM-DD HH:mm:ss'), + ), +]) +def test_add_from_offset(runner, watson, from_, expected): + result = runner.invoke( + cli.add, + ['-f', from_, '-t', 'now', 'project-name'], + obj=watson) + assert result.exit_code == 0 + assert OutputParser.get_start_date(watson, result.output) == expected + + @pytest.mark.parametrize('test_dt', INVALID_DATES_DATA) def test_add_invalid_date(runner, watson, test_dt): result = runner.invoke(cli.add, diff --git a/watson/cli.py b/watson/cli.py index 377b76b5..87b51600 100644 --- a/watson/cli.py +++ b/watson/cli.py @@ -109,10 +109,24 @@ def convert(self, value, param, ctx) -> arrow: def _parse_multiformat(self, value) -> arrow: date = None - for fmt in (None, 'HH:mm:ss', 'HH:mm'): + if value == "now": + return arrow.now() + + for fmt in (None, 'HH:mm:ss', 'HH:mm', 'mm'): try: if fmt is None: date = arrow.get(value) + elif "ago" in value: + v = value[:len(fmt)] + offset = arrow.get(v, fmt) + date = arrow.now().shift( + hours=offset.hour * -1, + minutes=offset.minute * -1, + seconds=offset.second * -1, + ) + if fmt != 'HH:mm:ss': + date = date.replace(second=0) + break else: date = arrow.get(value, fmt) date = arrow.now().replace( @@ -1222,11 +1236,28 @@ def add(watson, args, from_, to, confirm_new_project, confirm_new_tag): """ Add time to a project with tag(s) that was not tracked live. + The `--from` and `--to` options support providing an offset, supported + formats [`HH:mm:ss ago`, `HH:mm ago`, `mm min ago`]. + + The `--to` option also supports providing `now` as the offset. + Example: \b $ watson add --from "2018-03-20 12:00:00" --to "2018-03-20 13:00:00" \\ programming +addfeature + + \b + $ watson add --from "30 min ago" --to "now" \\ + programming +addfeature + + \b + $ watson add --from "09:30" --to "now" \\ + programming +addfeature + + \b + $ watson add --from "09:30" --to "30 min ago" \\ + programming +addfeature """ # parse project name from args project = ' '.join(