diff --git a/tests/test_cli.py b/tests/test_cli.py index 5c283171..0e913b5b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -222,6 +222,42 @@ def test_start_existing_frame_stopped(runner, watson, mocker): assert watson.current["project"] == "b-project" +# watson interrupt existing task with new task, restart existing + +def test_interrupt_new_frame_added(runner, watson, mocker): + # Simulate a start date so that 'at_dt' is older than now(). + watson.config.set('options', 'stop_on_start', "true") + mocker.patch('arrow.arrow.dt_datetime', wraps=datetime) + start_dt = datetime(2019, 4, 10, 15, 0, 0, tzinfo=local_tz_info()) + arrow.arrow.dt_datetime.now.return_value = start_dt + result = runner.invoke( + cli.start, + ['a-project', '--at', "14:10"], + obj=watson, + ) + + result = runner.invoke( + cli.interrupt, + ['b-project', '--at', "14:15"], + obj=watson, + ) + assert result.exit_code == 0, result.stdout + + assert watson._frames._rows[0].project == "a-project" + assert watson._frames._rows[0].stop == arrow.get( + "2019-04-10T14:15:00+01:00") + + assert watson._frames._rows[1].project == "b-project" + assert watson._frames._rows[1].start == arrow.get( + "2019-04-10T14:15:00+01:00") + assert watson._frames._rows[1].stop == arrow.get( + "2019-04-10T15:00:00+01:00") + + assert watson.current["project"] == "a-project" + assert watson.current["start"] == arrow.get( + "2019-04-10T15:00:00+01:00") + + # watson restart @pytest.mark.parametrize('at_dt', VALID_TIMES_DATA) diff --git a/watson/cli.py b/watson/cli.py index 377b76b5..4b5704e7 100644 --- a/watson/cli.py +++ b/watson/cli.py @@ -279,6 +279,80 @@ def start(ctx, watson, confirm_new_project, confirm_new_tag, args, at_, _start(watson, project, tags, start_at=at_, gap=gap_) +@cli.command() +@click.option('--at', 'at_', required=True, type=DateTime, + help=('Start frame at this time. Must be in ' + '(YYYY-MM-DDT)?HH:MM(:SS)? format.')) +@click.argument('args', nargs=-1, + shell_complete=get_project_or_task_completion) +@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, + help="Confirm creation of new tag.") +@click.pass_obj +@click.pass_context +@catch_watson_error +def interrupt(ctx, watson, confirm_new_project, confirm_new_tag, args, at_): + """ + Insert a project starting at `--at` time and ending `now`. You can add + tags indicating more specifically what you are working on with `+tag`. The + currently running task will be started again. + + If there is already a running project and the configuration option + `options.stop_on_start` is not set to a true value (`1`, `on`, `true`, or + `yes`), this command will abort. + + Example: + + \b + $ watson start apollo11 --at 13:37 + Starting project apollo11 at 13:37 + $ watson interrupt apollo13 --at 13:39 + Starting project apollo13 at 13:39 + Stopping project apollo11, started an hour ago and stopped just now. (id: e9ccd52) # noqa: E501 + Starting project apollo11 just now. + """ + if not watson.is_started: + raise click.ClickException( + 'No project running, please use watson start' + ) + + project = ' '.join( + itertools.takewhile(lambda s: not s.startswith('+'), args) + ) + if not project: + raise click.ClickException("No project given.") + + # Confirm creation of new project if that option is set + if (watson.config.getboolean('options', 'confirm_new_project') or + confirm_new_project): + confirm_project(project, watson.projects) + + # Parse all the tags + tags = parse_tags(args) + + # Confirm creation of new tag(s) if that option is set + if (watson.config.getboolean('options', 'confirm_new_tag') or + confirm_new_tag): + confirm_tags(tags, watson.tags) + + if not watson.config.getboolean('options', 'stop_on_start'): + raise click.ClickException( + style('error', 'config.stop_on_start is set to false,' + ' can not interrupt running project.'), + ) + + current = watson.current + ctx.invoke(stop, at_=at_) + watson.frames.add(project, at_, arrow.utcnow(), tags) + _start( + watson, + current["project"], + current["tags"], + start_at=arrow.utcnow(), + ) + + @cli.command(context_settings={'ignore_unknown_options': True}) @click.option('--at', 'at_', type=DateTime, default=None, help=('Stop frame at this time. Must be in '