tempo-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +56 -0
  4. data/README.md +326 -0
  5. data/Rakefile +65 -0
  6. data/bin/tempo +477 -0
  7. data/features/arrange.feature +43 -0
  8. data/features/checkout.feature +63 -0
  9. data/features/end.feature +65 -0
  10. data/features/project.feature +246 -0
  11. data/features/report.feature +62 -0
  12. data/features/start.feature +87 -0
  13. data/features/step_definitions/tempo_steps.rb +138 -0
  14. data/features/support/env.rb +26 -0
  15. data/features/tempo.feature +13 -0
  16. data/features/update.feature +69 -0
  17. data/lib/file_record/directory.rb +11 -0
  18. data/lib/file_record/directory_structure/tempo/README.txt +4 -0
  19. data/lib/file_record/directory_structure/tempo/tempo_projects.yaml +6 -0
  20. data/lib/file_record/record.rb +120 -0
  21. data/lib/tempo/controllers/arrange_controller.rb +52 -0
  22. data/lib/tempo/controllers/base.rb +117 -0
  23. data/lib/tempo/controllers/checkout_controller.rb +42 -0
  24. data/lib/tempo/controllers/end_controller.rb +42 -0
  25. data/lib/tempo/controllers/projects_controller.rb +107 -0
  26. data/lib/tempo/controllers/records_controller.rb +21 -0
  27. data/lib/tempo/controllers/report_controller.rb +55 -0
  28. data/lib/tempo/controllers/start_controller.rb +42 -0
  29. data/lib/tempo/controllers/update_controller.rb +78 -0
  30. data/lib/tempo/models/base.rb +176 -0
  31. data/lib/tempo/models/composite.rb +71 -0
  32. data/lib/tempo/models/log.rb +194 -0
  33. data/lib/tempo/models/project.rb +73 -0
  34. data/lib/tempo/models/time_record.rb +235 -0
  35. data/lib/tempo/version.rb +3 -0
  36. data/lib/tempo/views/arrange_view.rb +27 -0
  37. data/lib/tempo/views/base.rb +82 -0
  38. data/lib/tempo/views/formatters/base.rb +30 -0
  39. data/lib/tempo/views/formatters/screen.rb +86 -0
  40. data/lib/tempo/views/projects_view.rb +82 -0
  41. data/lib/tempo/views/report_view.rb +26 -0
  42. data/lib/tempo/views/reporter.rb +70 -0
  43. data/lib/tempo/views/time_record_view.rb +30 -0
  44. data/lib/tempo/views/view_records/base.rb +117 -0
  45. data/lib/tempo/views/view_records/composite.rb +40 -0
  46. data/lib/tempo/views/view_records/log.rb +28 -0
  47. data/lib/tempo/views/view_records/project.rb +32 -0
  48. data/lib/tempo/views/view_records/time_record.rb +48 -0
  49. data/lib/tempo.rb +26 -0
  50. data/lib/time_utilities.rb +30 -0
  51. data/tempo-cli.gemspec +26 -0
  52. data/test/lib/file_record/directory_test.rb +30 -0
  53. data/test/lib/file_record/record_test.rb +106 -0
  54. data/test/lib/tempo/controllers/base_controller_test.rb +60 -0
  55. data/test/lib/tempo/controllers/project_controller_test.rb +24 -0
  56. data/test/lib/tempo/models/base_test.rb +173 -0
  57. data/test/lib/tempo/models/composite_test.rb +76 -0
  58. data/test/lib/tempo/models/log_test.rb +171 -0
  59. data/test/lib/tempo/models/project_test.rb +105 -0
  60. data/test/lib/tempo/models/time_record_test.rb +212 -0
  61. data/test/lib/tempo/views/base_test.rb +31 -0
  62. data/test/lib/tempo/views/formatters/base_test.rb +13 -0
  63. data/test/lib/tempo/views/formatters/screen_test.rb +94 -0
  64. data/test/lib/tempo/views/reporter_test.rb +40 -0
  65. data/test/lib/tempo/views/view_records/base_test.rb +77 -0
  66. data/test/lib/tempo/views/view_records/composite_test.rb +57 -0
  67. data/test/lib/tempo/views/view_records/log_test.rb +28 -0
  68. data/test/lib/tempo/views/view_records/project_test.rb +0 -0
  69. data/test/lib/tempo/views/view_records/time_record_test.rb +0 -0
  70. data/test/support/factories.rb +177 -0
  71. data/test/support/helpers.rb +69 -0
  72. data/test/test_helper.rb +31 -0
  73. metadata +230 -0
data/bin/tempo ADDED
@@ -0,0 +1,477 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # In development, you need to use `bundle exec bin/tempo` to run this app
4
+ require 'gli'
5
+ require 'tempo'
6
+ require 'pry'
7
+ include GLI::App
8
+ # to preserve all the args in ARGV:
9
+ # preserve_argv
10
+
11
+ program_desc 'Command line time tracking by project'
12
+
13
+ version Tempo::VERSION
14
+
15
+ # == GLOBAL OPTIONS ==
16
+
17
+ desc 'verbose output'
18
+ long_desc 'include verbose reporting in the command output'
19
+ switch [:v, :verbose]
20
+
21
+ desc 'output id'
22
+ long_desc 'include id reporting in the command output'
23
+ switch [:i, :id]
24
+
25
+ # desc 'Describe some flag here'
26
+ # default_value 'the default'
27
+ # arg_name 'The name of the argument'
28
+ # flag [:f,:flagname]
29
+
30
+ # COMMAND: PROJECT
31
+
32
+ desc 'Manage the Projects that timed tasks are assigned to'
33
+ long_desc "Manage the Projects that timed tasks are assigned to.
34
+
35
+ Manage the Projects that timed tasks are assigned to.
36
+ By default, lists the current project, or with --list tag, lists all projects.
37
+ The active project will be marked by an asterisk.
38
+
39
+ If supplied with arguments and no command options,
40
+ a new project will be added.
41
+
42
+ Arguments supplied to --list, --delete, and --[un]tag
43
+ will use fuzzy matching unless you:
44
+
45
+ - Use the --exact flag to match the arguments exactly
46
+
47
+ - Use the --id tag to match by id
48
+
49
+ examples:
50
+
51
+ # list current project
52
+
53
+ $ tempo project
54
+
55
+ # list all projects
56
+
57
+ $ tempo project --list
58
+
59
+ # adding a new project titled 'star gazing'
60
+
61
+ $ tempo project star gazing
62
+
63
+ # adding a new project with a tag
64
+
65
+ $ tempo project --add star gazing --tag cellar
66
+
67
+ # untagging and tagging an existing project
68
+
69
+ $ tempo project star gazing --untag cellar --tag stellar"
70
+
71
+ arg_name '"name of the project"'
72
+ command [:project, :p] do |c|
73
+
74
+ c.desc 'Add a Project'
75
+ c.long_desc "Add a Project (default command behavior). When used with --tag adds a new project with the given tag"
76
+ c.switch [:a, :add], negatable: false
77
+
78
+ c.desc 'List Projects'
79
+ c.long_desc "Lists all projects that match the supplied argument"
80
+ c.switch [:l, :list], negatable: false
81
+
82
+ c.desc 'Exact Match'
83
+ c.long_desc "Match project with an exact title"
84
+ c.switch [:e, :exact]
85
+
86
+ c.desc 'List by or perform command by project id'
87
+ c.long_desc 'show IDs in output or perform command by matching to id'
88
+ c.switch [:i, :id], negatable: false
89
+
90
+ c.desc 'Delete a Project'
91
+ c.default_value nil
92
+ c.arg_name 'title'
93
+ c.flag [:d, :delete]
94
+
95
+ c.desc 'Tag a Project'
96
+ c.long_desc "Tag a project with one-word tags. Pass multiple tags in quotes to add multiple tags"
97
+ c.default_value nil
98
+ c.arg_name 'tagword'
99
+ c.flag [:t, :tag]
100
+
101
+ c.desc 'Untag a Project'
102
+ c.default_value nil
103
+ c.arg_name 'tagword'
104
+ c.flag [:u, :untag]
105
+
106
+ c.action do |global_options, options, args|
107
+
108
+ controller = Tempo::Controllers::Projects
109
+
110
+ # tag a project
111
+ #
112
+ if options[:tag]
113
+ controller.tag options, args
114
+
115
+ # untag a project
116
+ #
117
+ elsif options[:untag]
118
+ controller.tag options, args
119
+
120
+ # delete a project
121
+ #
122
+ elsif options[:delete]
123
+ controller.delete options, args
124
+
125
+ # add a project
126
+ #
127
+ elsif !options[:list] && !args.empty?
128
+ controller.add options, args
129
+
130
+ elsif !options[:list] && args.empty?
131
+ controller.show_active
132
+
133
+ # list projects, fiter by args
134
+ #
135
+ else
136
+ controller.index options, args
137
+ end
138
+ end
139
+ end
140
+
141
+ # COMMAND: CHECKOUT
142
+
143
+ desc 'Checkout a project to track time against'
144
+ long_desc "Checkout the Projects that timed tasks are assigned to.
145
+
146
+ Arguments supplied will use fuzzy matching unless you:
147
+
148
+ - Use the --exact flag to match the arguments exactly
149
+
150
+ - Use the --id tag to match by id
151
+
152
+ examples:
153
+
154
+ # checking out an existing project titled 'star gazing'
155
+
156
+ $ tempo checkout star gazing
157
+
158
+ # adding and checking out a new project titled 'star gazing'
159
+
160
+ $ tempo checkout -a star gazing"
161
+
162
+ arg_name '"name of the project"'
163
+ command [:checkout, :c] do |c|
164
+
165
+ c.desc 'Add and Checkout a new project'
166
+ c.arg_name 'title'
167
+ c.flag [:a, :add]
168
+
169
+ c.desc 'use an exact match for project title'
170
+ c.switch [:e, :exact]
171
+
172
+ c.desc 'checkout by project id'
173
+ c.switch [:i, :id], negatable: false
174
+
175
+ c.action do |global_options,options,args|
176
+
177
+ controller = Tempo::Controllers::Checkout
178
+
179
+ # add and checkout a project
180
+ #
181
+ if options[:add]
182
+ controller.add_project options, args
183
+
184
+ # checkout existing project
185
+ else
186
+ if args.empty?
187
+ controller.assistance
188
+ else
189
+ controller.existing_project options, args
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+
196
+ # COMMAND: ARRANGE
197
+
198
+ desc 'Arrange project hierarchy'
199
+ long_desc "Arrange projects into a parent/child hierarchy
200
+
201
+ New projects are added as root projects by default.
202
+
203
+ Use the --child flag with the project command to add a new project as the child of the current project
204
+
205
+ Use arrange to arrange existing projects as child or root projects.
206
+
207
+ Arguments supplied will use fuzzy matching unless you:
208
+
209
+ - Use the --exact flag to match the arguments exactly
210
+
211
+ - Use the --id tag to match by id
212
+
213
+ examples:
214
+
215
+ # Arrange an existing project as a root project
216
+
217
+ $ tempo arrange : aquascaping
218
+
219
+ # Arrange an existing project as a child project
220
+
221
+ $ tempo arrange aquascaping : coral pruning"
222
+
223
+ arg_name '[parent project] : child project'
224
+ command [:arrange, :a] do |c|
225
+
226
+ c.desc 'use an exact match for project title'
227
+ c.switch [:e, :exact]
228
+
229
+ c.desc 'checkout by project id'
230
+ c.switch [:i, :id]
231
+
232
+ c.action do |global_options, options, args|
233
+ controller = Tempo::Controllers::Arrange
234
+ controller.parse options, args
235
+ end
236
+ end
237
+
238
+ # COMMAND: EDIT
239
+
240
+ # COMMAND: START
241
+
242
+ desc 'Start a time entry'
243
+ long_desc "Starts a new time entry, and closes out any running time entries.
244
+
245
+ You can also add a description of the time entry.
246
+
247
+ To start a time entry at a time other than the current, pass it in as an argument
248
+ to the --at flag. This will accept a number of human readable formats, multiple
249
+ word time formats should be enclosed in quotes.
250
+
251
+ examples:
252
+
253
+ # start a new time record at the current time with no description
254
+
255
+ $ tempo start
256
+
257
+ # start and end a previous time record with a description
258
+
259
+ $ tempo start learning how to do the Hustle --at 'yesterday at 8:00 in the evening' --end 'yesterday at 11:59pm'
260
+ "
261
+
262
+ arg_name 'description'
263
+ command [:start, :s] do |c|
264
+
265
+ c.desc 'end the entry at a given time'
266
+ c.arg_name 'time'
267
+ c.flag [:e, :end]
268
+
269
+ c.desc 'start the entry at a given time'
270
+ c.arg_name 'time'
271
+ c.flag [:a, :at]
272
+
273
+ c.action do |global_options, options, args|
274
+ controller = Tempo::Controllers::Start
275
+
276
+ controller.start_timer options, args
277
+ end
278
+ end
279
+
280
+ # COMMAND: END
281
+
282
+ desc 'End a time entry'
283
+ long_desc "Closes out any running time entries.
284
+
285
+ You can optionally add a description of the time entry, which will overwrite the current description.
286
+
287
+ To end a time entry at a time other than the current, pass it in as an argument
288
+ to the --at flag. This will accept a number of human readable formats, multiple
289
+ word time formats should be enclosed in quotes.
290
+
291
+ examples:
292
+
293
+ # creating an entry at 4:55pm, then ending it 5 minutes later and changing the description
294
+
295
+ $ tempo start --at 16:55 practicing the human torch trick
296
+
297
+ $ tempo end --at 'today at 5:00pm' learning how to stop, drop, and roll
298
+ "
299
+
300
+
301
+ arg_name 'time out, defaults to now'
302
+ command [:end, :e] do |c|
303
+
304
+ c.desc 'time'
305
+ c.arg_name 'end the current time entry at the given time'
306
+ c.flag [:a, :at]
307
+
308
+ c.action do |global_options, options, args|
309
+ controller = Tempo::Controllers::End
310
+
311
+ controller.end_timer options, args
312
+ end
313
+ end
314
+
315
+ # COMMAND: REPORT
316
+
317
+ desc 'Report time entries'
318
+ long_desc "Reports time entries for a day or a period of days.
319
+
320
+ By default, lists the last recorded day's entries.
321
+
322
+ To list a different day, supply a day as the args
323
+
324
+ To list a series of records, include a --from and --to value
325
+
326
+ examples:
327
+
328
+ # report current day's entries
329
+
330
+ $ tempo report
331
+
332
+ # report a different day
333
+
334
+ $ tempo report 11/24/14
335
+
336
+ # report the past week
337
+
338
+ $ tempo report -f 'a week ago'
339
+
340
+ # report a period of days
341
+
342
+ $ tempo report -f 'last monday' -t 'last friday'"
343
+
344
+ arg_name '[day]'
345
+ command [:report, :r] do |c|
346
+
347
+ c.desc 'begin time records on this date'
348
+ c.arg_name 'time'
349
+ c.default_value 'last record'
350
+ c.flag [:f, :from]
351
+
352
+ c.desc 'end time records on this date'
353
+ c.arg_name 'time'
354
+ c.default_value 'today'
355
+ c.flag [:t, :to]
356
+
357
+ c.action do |global_options, options, args|
358
+ controller = Tempo::Controllers::Report
359
+
360
+ controller.report options, args
361
+ end
362
+ end
363
+
364
+ # COMMAND: UPDATE
365
+
366
+ desc 'update a time entry'
367
+ long_desc "update the project, start time, or end time for a time
368
+ entry.
369
+
370
+ Defaults to the current time entry, or most recently completed time entry
371
+ if none are running. Optionally, you can supply an id for a time entry on the current
372
+ day, or a day and id to update previous time entries.
373
+
374
+ The description, if passed in, will be used to replace the existing description. You can
375
+ also change the start or end time, or delete the entire time entry.
376
+
377
+ examples:
378
+
379
+ # update description for the last time entry
380
+
381
+ $ tempo update practicing banjo
382
+
383
+ # update the description for yesterday's entry with id of 2
384
+
385
+ $ tempo update --id 2 --on 'yesterday' practicing banjo
386
+
387
+ # update the start time for the last time entry
388
+
389
+ $ tempo update --start 7:00
390
+
391
+ # update the end time and description
392
+
393
+ $ tempo update --end '8:00pm' practicing banjo
394
+
395
+ # delete the last time entry
396
+
397
+ $ tempo update --delete
398
+
399
+ # update the description, start, and end time for a previous day's entry
400
+
401
+ $ tempo update --on 1/17/14 --start \"1/17/14 8am\" --end \"1/17/14 10am\" practicing banjo
402
+ "
403
+
404
+ arg_name '[description]'
405
+ command [:update, :u] do |c|
406
+
407
+ c.desc 'Select by Id'
408
+ c.arg_name 'number'
409
+ c.flag [:i, :id]
410
+
411
+ c.desc 'Select On Date'
412
+ c.arg_name 'date'
413
+ c.flag [:o, :on]
414
+
415
+ c.desc 'Update to the active project'
416
+ c.switch [:p, :project], negatable: false
417
+
418
+ c.desc 'Update the Start Time'
419
+ c.arg_name 'time'
420
+ c.flag [:s, :start]
421
+
422
+ c.desc 'Update the End Time'
423
+ c.arg_name 'time'
424
+ c.flag [:e, :end]
425
+
426
+ c.desc 'Delete a Time Entry'
427
+ c.switch [:d, :delete], negatable: false
428
+
429
+ c.action do |global_options, options, args|
430
+ controller = Tempo::Controllers::Update
431
+
432
+ controller.parse options, args
433
+ end
434
+ end
435
+
436
+ pre do |global,command,options,args|
437
+ # Return true to proceed; false to abort and not call the
438
+ # chosen command
439
+ # Use skips_pre before a command to skip this block
440
+ # on that command only
441
+
442
+ # add reporting of all arguments
443
+ if global[:v]
444
+ Tempo::Views::options_report command.name, global, options, args
445
+ end
446
+
447
+ Tempo::Views::initialize_view_options command.name, global, options
448
+
449
+ # Load the stored records
450
+ Tempo::Controllers::Records.initialize_from_records options, args
451
+
452
+ # TODO: send formats in through global options, and then:
453
+ # Tempo::Views::Reporter.add_formats
454
+
455
+ true
456
+ end
457
+
458
+ post do |global,command,options,args|
459
+ # Post logic here
460
+ # Use skips_post before a command to skip this
461
+ # block on that command only
462
+
463
+ Tempo::Views::Reporter.report
464
+
465
+ end
466
+
467
+ on_error do |exception|
468
+ # Error logic here
469
+ # return false to skip default error handling
470
+
471
+ # remove before distribution:
472
+ #puts exception.backtrace
473
+
474
+ true
475
+ end
476
+
477
+ exit run(ARGV)
@@ -0,0 +1,43 @@
1
+ Feature: Arrange Command manages the hierarchy of a list of projects
2
+ Projects can be ordered as root projects or children of other projects
3
+ The arrange command manages the relationship between parentg and child projects
4
+
5
+ Scenario: Arranging a project as a root projects
6
+ Given an existing project file
7
+ When I successfully run `tempo arrange : basement mushrooms`
8
+ Then the stdout should contain "root project:\nbasement mushrooms"
9
+ And the project file should contain ":parent: :root" at line 20
10
+
11
+ Scenario: Arranging a project as a child of another project
12
+ Given an existing project file
13
+ When I successfully run `tempo arrange horticulture : nano aquarium`
14
+ Then the stdout should contain "parent project:\nhorticulture"
15
+ And the stdout should contain "child project:\nnano aquarium"
16
+ And the project file should contain ":parent: 1" at line 39
17
+ And the project file should contain "- 5" at line 7
18
+
19
+ Scenario: Attempting to arrange projects without using a colon in the args
20
+ Given an existing project file
21
+ When I run `tempo arrange horticulture aquaculture`
22
+ Then the stderr should contain "arrange requires a colon (:) in the arguments"
23
+
24
+ Scenario: Attempting to arrange a root project as a root project
25
+ Given an existing project file
26
+ When I run `tempo arrange : horticulture`
27
+ Then the stdout should contain "already a root project:\nhorticulture"
28
+
29
+ Scenario: Arranging projects by id
30
+ Given an existing project file
31
+ When I successfully run `tempo arrange -i 4 : 1`
32
+ Then the stdout should contain "parent project:\naquaculture"
33
+ And the stdout should contain "child project:\nhorticulture"
34
+ And the project file should contain ":parent: 4" at line 3
35
+ And the project file should contain "- 1" at line 31
36
+
37
+ Scenario: Arranging projects by exact match
38
+ Given an existing project file
39
+ When I successfully run `tempo arrange -e reading aquaculture digest : aquaculture`
40
+ Then the stdout should contain "parent project:\nreading aquaculture digest"
41
+ And the stdout should contain "child project:\naquaculture"
42
+ And the project file should contain ":parent: 6" at line 29
43
+ And the project file should contain "- 4" at line 47
@@ -0,0 +1,63 @@
1
+ Feature: Checkout Command manages the active project
2
+ A New project can be added and checked out
3
+ An Exiting project can be checked out
4
+
5
+ Scenario: Checkout an existing project with checkout
6
+ Given an existing project file
7
+ When I successfully run `tempo checkout "backyard bonsai"`
8
+ Then the stdout should contain "switched to project:\nbackyard bonsai"
9
+ And the project file should contain ":current: true" at line 18
10
+
11
+ Scenario: Checkout an exising project with c
12
+ Given an existing project file
13
+ When I successfully run `tempo c "backyard bonsai"`
14
+ Then the stdout should contain "switched to project:\nbackyard bonsai"
15
+ And the project file should contain ":current: true" at line 18
16
+
17
+ Scenario: Checkout an existing project by partial match
18
+ Given an existing project file
19
+ When I successfully run `tempo checkout "bonsai"`
20
+ Then the stdout should contain "switched to project:\nbackyard bonsai"
21
+ And the project file should contain ":current: true" at line 18
22
+
23
+ Scenario: Checkout a project by id
24
+ Given an existing project file
25
+ When I successfully run `tempo checkout -i 3`
26
+ Then the stdout should contain "switched to project:\nbasement mushrooms"
27
+
28
+ Scenario: Checkout a project by exact match
29
+ Given an existing project file
30
+ And I successfully run `tempo checkout -e aquaculture`
31
+ Then the stdout should contain "switched to project:\naquaculture"
32
+ And the stdout should not contain "switched to project:\nreading aquaculture digest"
33
+
34
+ Scenario: Attempting to Checkout an existing project by partial match with multiple possibilities
35
+ Given an existing project file
36
+ And I run `tempo checkout aquaculture`
37
+ Then the stdout should contain "The following projects matched your search:"
38
+ And the stdout should contain "aquaculture"
39
+ And the stdout should contain "reading aquaculture digest"
40
+ And the stderr should contain "error: cannot checkout multiple projects"
41
+
42
+ Scenario: Attempting to Checkout the current project
43
+ Given an existing project file
44
+ When I successfully run `tempo checkout "horticulture"`
45
+ Then the stdout should contain "already on project:\nhorticulture"
46
+
47
+ Scenario: Attempting to checkout a non-existant project
48
+ Given an existing project file
49
+ When I run `tempo checkout "new project"`
50
+ And the stdout should not contain "switched"
51
+ Then the stderr should contain "no projects match the request: new project"
52
+
53
+ Scenario: Adding and checking out a new project
54
+ Given an existing project file
55
+ When I successfully run `tempo checkout --add "bathtup scuba diving"`
56
+ Then the stdout should contain "switched to project:\nbathtup scuba diving"
57
+ And the project file should contain ":title: bathtup scuba diving"
58
+ And the project file should contain ":current: true"
59
+
60
+ Scenario: Attempting to add an exising project
61
+ Given an existing project file
62
+ When I run `tempo checkout --add "basement mushrooms"`
63
+ Then the stderr should contain "error: project 'basement mushrooms' already exists"
@@ -0,0 +1,65 @@
1
+ Feature: End Command ends the current time record
2
+ The end command ends the currenly running time record. It can be passed a value
3
+ that will end the record at a given time
4
+
5
+ Scenario: Attempting to add time before any projects exist
6
+ Given a clean installation
7
+ When I run `tempo end`
8
+ Then the stderr should contain "no projects exist"
9
+ And the project file should contain "#" at line 1
10
+
11
+ Scenario: Attempting to end a time record when none are running
12
+ Given an existing project file
13
+ When I run `tempo end`
14
+ Then the stderr should contain "no running time records exist"
15
+
16
+ Scenario: Ending the current time record
17
+ Given an existing project file
18
+ When I run `tempo start`
19
+ And I run `tempo end`
20
+ Then the stdout should contain "time record ended"
21
+ And the output should match /\d{2}:\d{2} - \d{2}:\d{2}[^\*]/
22
+
23
+ Scenario: Ending the current time record and changing the description
24
+ Given an existing project file
25
+ When I run `tempo start old description`
26
+ And I run `tempo end new description`
27
+ Then the stdout should contain "time record ended"
28
+ And the output should contain "new description"
29
+ And the output should match /\d{2}:\d{2} - \d{2}:\d{2}[^\*]/
30
+
31
+ Scenario: Attempting to add an invalid end time
32
+ Given an existing project file
33
+ When I run `tempo start`
34
+ When I run `tempo end --at "invalid time"`
35
+ Then the stderr should contain "no valid timeframe matches the request: invalid time"
36
+
37
+ Scenario: Ending a time record for a specific time
38
+ Given an existing project file
39
+ When I run `tempo start --at "1-5-2014 7:00"`
40
+ And I run `tempo end --at "1-5-2014 15:00"`
41
+ Then the stdout should contain "time record ended"
42
+ And the output should match /7:00 - 15:00/
43
+ @pending
44
+ Scenario: Attempting to end after the beginning time
45
+ Given an existing project file
46
+ When I run `tempo start --at "1-5-2014 17:00"`
47
+ And I run `tempo end --at "1-5-2014 6:00"`
48
+ Then the stderr should contain "you cannot end a time record before the starting time"
49
+
50
+ @pending
51
+ Scenario: Ending a time record with tags
52
+ Given an existing project file
53
+ @pending
54
+ Scenario: Ending a time record on a previous day
55
+ Given an existing project file
56
+ When I run `tempo start --at "1-1-2014 7:00"`
57
+ And I run `tempo end --at "1-3-2014 10:00"`
58
+ Then the stdout should contain "time record ended"
59
+ And the time record 20140101 should contain ":end_time: 2014-01-01 23:59" at line 5
60
+ And the time record 20140102 should contain ":end_time: 2014-01-01 23:59" at line 5
61
+ And the time record 20140103 should contain ":end_time: 2014-01-01 10:00" at line 5
62
+
63
+
64
+
65
+