tempo-cli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+