Skip to content

Commit

Permalink
Add 'notes' field to frames.
Browse files Browse the repository at this point in the history
This is a large commit that adds the following:

1. Syntax: `watson stop --notes "some additional information"`.
2. Print only non-empty notes in log.
3. Always pass id to `new_frame` so that the length of array with/without
   notes doesn't cause ambiguity.
4. Print a warning message and the existing note if overwriting a note.
5. Print notes in report.

Primary work here was done by the following people:

Co-authored-by: Tristan Pratt <[email protected]>
Co-authored-by: Joel Ostblom <[email protected]>
  • Loading branch information
3 people committed Feb 11, 2021
1 parent 560e962 commit 6d9c1e4
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 58 deletions.
8 changes: 7 additions & 1 deletion docs/user-guide/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -705,17 +705,23 @@ If `--at` option is given, the provided stopping time is used. The
specified time must be after the beginning of the to-be-ended frame and must
not be in the future.

Example:
You can optionally pass a log message to be saved with the frame via
the ``-n/--note`` option.

Example:

$ watson stop --at 13:37
Stopping project apollo11, started an hour ago and stopped 30 minutes ago. (id: e9ccd52) # noqa: E501
$ watson stop -n "Done some thinking"
Stopping project apollo11, started a minute ago. (id: e7ccd52)
Log message: Done some thinking

### Options

Flag | Help
-----|-----
`--at DATETIME` | Stop frame at this time. Must be in (YYYY-MM-DDT)?HH:MM(:SS)? format.
`-n, --note TEXT` | Save given log message with the project frame.
`--help` | Show this message and exit.

## `sync`
Expand Down
4 changes: 2 additions & 2 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def test_frames_to_csv(watson):
result = frames_to_csv(watson.frames)

read_csv = list(csv.reader(StringIO(result)))
header = ['id', 'start', 'stop', 'project', 'tags']
header = ['id', 'start', 'stop', 'project', 'tags', 'note']
assert len(read_csv) == 2
assert read_csv[0] == header
assert read_csv[1][3] == 'foo'
Expand All @@ -319,7 +319,7 @@ def test_frames_to_json(watson):

result = json.loads(frames_to_json(watson.frames))

keys = {'id', 'start', 'stop', 'project', 'tags'}
keys = {'id', 'start', 'stop', 'project', 'tags', 'note'}
assert len(result) == 1
assert set(result[0].keys()) == keys
assert result[0]['project'] == 'foo'
Expand Down
111 changes: 108 additions & 3 deletions tests/test_watson.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,54 @@ def test_frames_without_tags(mocker, watson):
assert watson.frames[0].tags == []


def test_frames_with_note(mocker, watson):
"""Test loading frames with notes."""
content = json.dumps([
[3601, 3610, 'foo', 'abcdefg', ['A', 'B', 'C'], 3650,
"My hovercraft is full of eels"]
])

mocker.patch('%s.open' % builtins, mocker.mock_open(read_data=content))
assert len(watson.frames) == 1
frame = watson.frames['abcdefg']
assert frame.id == 'abcdefg'
assert frame.project == 'foo'
assert frame.start == arrow.get(3601)
assert frame.stop == arrow.get(3610)
assert frame.tags == ['A', 'B', 'C']
assert frame.note == "My hovercraft is full of eels"


def test_frames_without_note(mocker, watson):
"""Test loading frames without notes."""
content = json.dumps([
[3601, 3610, 'foo', 'abcdefg'],
[3611, 3620, 'foo', 'hijklmn', ['A', 'B', 'C']],
[3621, 3630, 'foo', 'opqrstu', ['A', 'B', 'C'], 3630]
])

mocker.patch('%s.open' % builtins, mocker.mock_open(read_data=content))
assert len(watson.frames) == 3
frame = watson.frames['abcdefg']
assert frame.id == 'abcdefg'
assert frame.project == 'foo'
assert frame.start == arrow.get(3601)
assert frame.stop == arrow.get(3610)
assert frame.tags == []
assert frame.note is None

frame = watson.frames['hijklmn']
assert frame.id == 'hijklmn'
assert frame.tags == ['A', 'B', 'C']
assert frame.note is None

frame = watson.frames['opqrstu']
assert frame.id == 'opqrstu'
assert frame.tags == ['A', 'B', 'C']
assert frame.updated_at == arrow.get(3630)
assert frame.note is None


def test_frames_with_empty_file(mocker, watson):
mocker.patch('builtins.open', mocker.mock_open(read_data=""))
mocker.patch('os.path.getsize', return_value=0)
Expand Down Expand Up @@ -315,6 +363,32 @@ def test_stop_started_project_without_tags(watson):
assert watson.frames[0].tags == []


def test_stop_started_project_without_note(watson):
"""Test stopping watson without adding a note."""
watson.start('foo')
watson.stop()

assert watson.current == {}
assert watson.is_started is False
assert len(watson.frames) == 1
frame = watson.frames[0]
assert frame.project == 'foo'
assert frame.note is None


def test_stop_started_project_with_note(watson):
"""Test stopping watson when adding a note."""
watson.start('foo')
watson.stop(None, "My hovercraft is full of eels")

assert watson.current == {}
assert watson.is_started is False
assert len(watson.frames) == 1
frame = watson.frames[0]
assert frame.project == 'foo'
assert frame.note == "My hovercraft is full of eels"


def test_stop_no_project(watson):
with pytest.raises(WatsonError):
watson.stop()
Expand Down Expand Up @@ -403,7 +477,8 @@ def test_save_empty_current(config_dir, mocker, json_mock):

assert json_mock.call_count == 1
result = json_mock.call_args[0][0]
assert result == {'project': 'foo', 'start': 4000, 'tags': []}
assert result == {'project': 'foo', 'start': 4000,
'tags': [], 'note': None}

watson.current = {}
watson.save()
Expand Down Expand Up @@ -763,9 +838,12 @@ def test_report(watson):
assert 'time' in report['projects'][0]['tags'][0]
assert report['projects'][0]['tags'][1]['name'] == 'B'
assert 'time' in report['projects'][0]['tags'][1]
assert len(report['projects'][0]['notes']) == 0
assert len(report['projects'][0]['tags'][0]['notes']) == 0
assert len(report['projects'][0]['tags'][1]['notes']) == 0

watson.start('bar', tags=['C'])
watson.stop()
watson.stop(note='bar note')

report = watson.report(arrow.now(), arrow.now())
assert len(report['projects']) == 2
Expand All @@ -774,6 +852,13 @@ def test_report(watson):
assert len(report['projects'][0]['tags']) == 1
assert report['projects'][0]['tags'][0]['name'] == 'C'

assert len(report['projects'][1]['notes']) == 0
assert len(report['projects'][1]['tags'][0]['notes']) == 0
assert len(report['projects'][1]['tags'][1]['notes']) == 0
assert len(report['projects'][0]['notes']) == 0
assert len(report['projects'][0]['tags'][0]['notes']) == 1
assert report['projects'][0]['tags'][0]['notes'][0] == 'bar note'

report = watson.report(
arrow.now(), arrow.now(), projects=['foo'], tags=['B']
)
Expand All @@ -783,16 +868,36 @@ def test_report(watson):
assert report['projects'][0]['tags'][0]['name'] == 'B'

watson.start('baz', tags=['D'])
watson.stop()
watson.stop(note='baz note')

watson.start('foo')
watson.stop(note='foo no tags')

watson.start('foo', tags=['A'])
watson.stop(note='foo one tag A')

report = watson.report(arrow.now(), arrow.now(), projects=["foo"])

assert len(report['projects']) == 1
assert len(report['projects'][0]['notes']) == 1
# A project-level note because this frame has no tags
assert report['projects'][0]['notes'][0] == 'foo no tags'
assert len(report['projects'][0]['tags']) == 2
assert report['projects'][0]['tags'][0]['name'] == 'A'
assert report['projects'][0]['tags'][1]['name'] == 'B'
assert len(report['projects'][0]['tags'][0]['notes']) == 1
assert len(report['projects'][0]['tags'][1]['notes']) == 0
# A tag-level note because this frame has tags
assert report['projects'][0]['tags'][0]['notes'][0] == 'foo one tag A'

report = watson.report(arrow.now(), arrow.now(), ignore_projects=["bar"])
assert len(report['projects']) == 2

report = watson.report(arrow.now(), arrow.now(), tags=["A"])
assert len(report['projects']) == 1
assert len(report['projects'][0]['notes']) == 0
assert len(report['projects'][0]['tags'][0]['notes']) == 1
assert report['projects'][0]['tags'][0]['notes'][0] == 'foo one tag A'

report = watson.report(arrow.now(), arrow.now(), ignore_tags=["D"])
assert len(report['projects']) == 2
Expand Down
Loading

0 comments on commit 6d9c1e4

Please sign in to comment.