hcl 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ffeab4df3c125edae4368f304a145fa7d76bb0f
4
- data.tar.gz: 8f362f3aa3e7010d9a871212818fa247165cea49
3
+ metadata.gz: 1ea82cda49c0d4f4aa43038029ae70b5e22b9e18
4
+ data.tar.gz: 3bf6719883563294afd3545ce02213abe468e7a5
5
5
  SHA512:
6
- metadata.gz: 75031b9762f7ecc905d2b11fbe8c16b8708b459677a58de1750bca4cb9185699f25dd006626ea85841624e0b0130324ae43eef03922ffe8459b2411cf5b95817
7
- data.tar.gz: 3a3b1bfce1f9f88da3a8bebb206c5bab6c6d6b71c81d6a8914a50ee4f74ecf216e904f03386bd95ed60b97cfb5b6eb37f706327bf22dd482d5db183f810fbf9c
6
+ metadata.gz: f0994f4ee68ce6b5adabb2de5cec31a8db29091fc02eba53929461015e639b152805ba5b42707c693a1bcf1efb200e0918f07c3b6e4522e33beb46187cda9aa8
7
+ data.tar.gz: 1749a65a4eaaaa8c580573e5dab944ae026fb057bdaa33a3ae225569f1033d9cccada2c5efd77a7c0d1e5785d38fb154ef23d8943e70db48728c3ef0ad54b41f
data/CHANGELOG CHANGED
@@ -1,5 +1,10 @@
1
1
  = Recent Changes in HCl
2
2
 
3
+ == v0.4.9 2013-12-21
4
+
5
+ * MacOS X: store password in default keychain
6
+ * abort log command when a timer is running
7
+
3
8
  == v0.4.8 2013-11-30
4
9
 
5
10
  * more fixes for 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+ # XXX this is dumb but it's crazy hard to get platform specfic deps into a gemspec
4
+ gem 'rubysl-abbrev', platform:'rbx'
5
+ gem 'rubysl-singleton', platform:'rbx'
6
+ gem 'rubysl-rexml', platform:'rbx'
7
+ gem 'rubysl-coverage', platform:'rbx', group:'test'
8
+ gem 'rubinius-coverage', platform:'rbx', group:'test'
9
+ gem 'yajl-ruby', platform:'rbx', group:'test'
data/HACKING.markdown CHANGED
@@ -8,6 +8,10 @@ Use Bundler to install dependencies before you run the tests:
8
8
  bundle
9
9
  rake test
10
10
 
11
+ Coverage is tested automatically. To view the test coverage report:
12
+
13
+ open coverage/index.html
14
+
11
15
  ## Running HCl during development
12
16
 
13
17
  To run HCl in place (e.g. for testing out local changes) you can use bundle exec:
data/README.markdown CHANGED
@@ -5,28 +5,31 @@ HCl is a command-line tool for interacting with Harvest time sheets using the
5
5
 
6
6
  [htt]: http://www.getharvest.com/api/time_tracking
7
7
 
8
+ [![Build Status](https://travis-ci.org/zenhob/hcl.png?branch=master)](https://travis-ci.org/zenhob/hcl)
9
+ [![Gem Version](https://badge.fury.io/rb/hcl.png)](http://badge.fury.io/rb/hcl)
10
+
8
11
  ## Quick Start
9
12
 
10
13
  You can install hcl directly from rubygems.org:
11
14
 
12
- $ gem install hcl
15
+ gem install hcl
13
16
 
14
17
  or you can install from source:
15
18
 
16
- $ rake install
19
+ rake install
17
20
 
18
21
  ## Usage
19
22
 
20
- $ hcl [start] @<task_alias> [+<time>] [<message>]
21
- $ hcl note <message>
22
- $ hcl stop [<message>]
23
- $ hcl resume [@<task_alias>]
24
- $ hcl log @<task_alias> [+<time>] [<message>]
25
- $ hcl show [<date>]
26
- $ hcl tasks [<project_code>]
27
- $ hcl alias <task_alias> <project_id> <task_id>
28
- $ hcl aliases
29
- $ hcl (cancel | nvm | oops)
23
+ hcl [start] @<task_alias> [+<time>] [<message>]
24
+ hcl note <message>
25
+ hcl stop [<message>]
26
+ hcl resume [@<task_alias>]
27
+ hcl log @<task_alias> [+<time>] [<message>]
28
+ hcl show [<date>]
29
+ hcl tasks [<project_code>]
30
+ hcl alias <task_alias> <project_id> <task_id>
31
+ hcl aliases
32
+ hcl (cancel | nvm | oops)
30
33
 
31
34
  ### Available Projects and Tasks
32
35
 
@@ -34,7 +37,7 @@ To start a new timer you need to identify the project and task.
34
37
  The tasks command displays a list of available tasks with their
35
38
  project and task IDs.
36
39
 
37
- $ hcl tasks
40
+ hcl tasks
38
41
 
39
42
  You can also pass a project code (this is the short optional code associated
40
43
  with each project) to list only the tasks for that project.
@@ -44,8 +47,8 @@ with each project) to list only the tasks for that project.
44
47
  Since it's not practical to enter two long numbers every time you want to
45
48
  identify a task, HCl supports task aliases:
46
49
 
47
- $ hcl alias tacodev 1234 5678
48
- $ hcl @tacodev Adding a new feature
50
+ hcl alias tacodev 1234 5678
51
+ hcl @tacodev Adding a new feature
49
52
 
50
53
  ### Starting a Timer with Initial Time
51
54
 
@@ -53,20 +56,20 @@ You can also provide an initial time when starting a new timer.
53
56
  This can be expressed in floating-point or HH:MM. The following two
54
57
  commands are equivalent:
55
58
 
56
- $ hcl @tacodev +0:15 Doing some stuff
57
- $ hcl +.25 @tacodev Doing some stuff
59
+ hcl @tacodev +0:15 Doing some stuff
60
+ hcl +.25 @tacodev Doing some stuff
58
61
 
59
62
  ### Adding Notes to a Running Task
60
63
 
61
64
  While a task is running you can append lines to the task notes:
62
65
 
63
- $ hcl note Then I did something else
66
+ hcl note Then I did something else
64
67
 
65
68
  **Note** that `show` only displays the last line of the timer notes.
66
69
  You can list all the notes for a running timer by issuing the note
67
70
  command without any arguments:
68
71
 
69
- $ hcl note
72
+ hcl note
70
73
 
71
74
  ### Stopping a Timer
72
75
 
@@ -74,22 +77,22 @@ The following command will stop a running timer (currently only one timer at
74
77
  a time is supported). You can provide a message when stopping a timer as
75
78
  well:
76
79
 
77
- $ hcl stop All done doing things
80
+ hcl stop All done doing things
78
81
 
79
82
  ### Resuming a Timer
80
83
 
81
84
  You can resume a stopped timer. Specify a task to resume the last timer
82
85
  for that task:
83
86
 
84
- $ hcl resume
85
- $ hcl resume @xdev
87
+ hcl resume
88
+ hcl resume @xdev
86
89
 
87
90
  ### Canceling a Timer
88
91
 
89
92
  If you accidentally started a timer that you didn't mean to, you can cancel
90
93
  it:
91
94
 
92
- $ hcl cancel
95
+ hcl cancel
93
96
 
94
97
  This will delete the running timer, or the last-updated timer if one isn't
95
98
  running. You can also use `nvm` or `oops` instead of `cancel`.
@@ -99,26 +102,42 @@ running. You can also use `nvm` or `oops` instead of `cancel`.
99
102
  You can log time and notes without leaving a timer running. It takes
100
103
  the same arguments as start:
101
104
 
102
- $ hcl log @xdev +1 Worked for an hour.
105
+ hcl log @xdev +1 Worked for an hour.
103
106
 
104
107
  The above starts and immediately stops a one-hour timer with the given note.
105
108
 
109
+ ## Advanced Usage
110
+
106
111
  ### Bash Auto-completion of Task Aliases
107
112
 
108
- You can enable auto-completion of task aliases by adding this to your bashrc:
113
+ You can enable auto-completion of task aliases by adding this to your shell
114
+ configuration:
109
115
 
110
116
  eval `hcl completion`
111
117
 
118
+ ### Configuration Profiles
119
+
120
+ You can specify an alternate configuration directory in the environment as
121
+ `HCL_DIR`. This can be used to easily interact with multiple harvest accounts.
122
+ Here is a shell alias `myhcl` with a separate configuration from the
123
+ main `hcl` command, including alias completion:
124
+
125
+ alias myhcl="env HCL_DIR=~/.myhcl hcl"
126
+ eval `myhcl completion myhcl`
127
+
128
+ When using `myhcl` you can use different credentials and aliases, while
129
+ `hcl` will continue to function with your original configuration.
130
+
112
131
  ### Date Formats
113
132
 
114
133
  Dates can be expressed in a variety of ways. See the [Chronic documentation][cd]
115
134
  for more information about available date input formats. The following
116
- commands show the timesheet for the specified day:
135
+ commands show the time sheet for the specified day:
117
136
 
118
- $ hcl show yesterday
119
- $ hcl show last friday
120
- $ hcl show 2 days ago
121
- $ hcl show 1 week ago
137
+ hcl show yesterday
138
+ hcl show last friday
139
+ hcl show 2 days ago
140
+ hcl show 1 week ago
122
141
 
123
142
  [cd]: http://chronic.rubyforge.org/
124
143
 
data/lib/hcl/app.rb CHANGED
@@ -55,22 +55,25 @@ module HCl
55
55
  else
56
56
  puts show
57
57
  end
58
+ rescue CommandError => e
59
+ $stderr.puts e
60
+ exit 1
58
61
  rescue RuntimeError => e
59
- STDERR.puts "Error: #{e}"
62
+ $stderr.puts "Error: #{e}"
60
63
  exit 1
61
64
  rescue SocketError => e
62
- STDERR.puts "Connection failed. (#{e.message})"
65
+ $stderr.puts "Connection failed. (#{e.message})"
63
66
  exit 1
64
67
  rescue TimesheetResource::ThrottleFailure => e
65
- STDERR.puts "Too many requests, retrying in #{e.retry_after+5} seconds..."
68
+ $stderr.puts "Too many requests, retrying in #{e.retry_after+5} seconds..."
66
69
  sleep e.retry_after+5
67
70
  run
68
71
  rescue TimesheetResource::AuthFailure => e
69
- STDERR.puts "Unable to authenticate: #{e}"
72
+ $stderr.puts "Unable to authenticate: #{e}"
70
73
  request_config
71
74
  run
72
75
  rescue TimesheetResource::Failure => e
73
- STDERR.puts "API failure: #{e}"
76
+ $stderr.puts "API failure: #{e}"
74
77
  exit 1
75
78
  end
76
79
  end
@@ -133,9 +136,12 @@ EOM
133
136
 
134
137
  private
135
138
 
136
- def read_config force=false
139
+ def read_config
137
140
  if File.exists? CONFIG_FILE
138
- config = YAML::load File.read(CONFIG_FILE)
141
+ config = YAML::load(File.read(CONFIG_FILE)) || {}
142
+ if has_security_command?
143
+ load_password config
144
+ end
139
145
  TimesheetResource.configure config
140
146
  elsif File.exists? OLD_CONFIG_FILE
141
147
  config = YAML::load File.read(OLD_CONFIG_FILE)
@@ -159,10 +165,13 @@ EOM
159
165
 
160
166
  def write_config config
161
167
  puts "Writing configuration to #{CONFIG_FILE}."
168
+ if has_security_command?
169
+ save_password config
170
+ end
162
171
  File.open(CONFIG_FILE, 'w') do |f|
163
172
  f.write config.to_yaml
164
173
  end
165
- FileUtils.chmod 0400, CONFIG_FILE
174
+ FileUtils.chmod 0600, CONFIG_FILE
166
175
  end
167
176
 
168
177
  def read_settings
@@ -182,6 +191,32 @@ EOM
182
191
  end
183
192
  nil
184
193
  end
194
+
195
+ def has_security_command?
196
+ if @has_security.nil?
197
+ @has_security = File.exists?('/usr/bin/security') &&
198
+ (`/usr/bin/security error 1` =~ /CSSM_ERRCODE_INTERNAL_ERROR/)
199
+ else
200
+ @has_security
201
+ end
202
+ end
203
+
204
+ def load_password config
205
+ cmd = "security find-internet-password -l hcl -a '%s' -s '%s.harvestapp.com' -w" % [
206
+ config['login'],
207
+ config['subdomain'],
208
+ ]
209
+ password = `#{cmd}`
210
+ config.update('password'=>password.chomp) if $?.success?
211
+ end
212
+
213
+ def save_password config
214
+ if system("security add-internet-password -U -l hcl -a '%s' -s '%s.harvestapp.com' -w '%s'" % [
215
+ config['login'],
216
+ config['subdomain'],
217
+ config['password'],
218
+ ]) then config.delete('password') end
219
+ end
185
220
  end
186
221
  end
187
222
 
data/lib/hcl/commands.rb CHANGED
@@ -3,6 +3,8 @@ require 'highline'
3
3
 
4
4
  module HCl
5
5
  module Commands
6
+ class Error < StandardError; end
7
+
6
8
  def tasks project_code=nil
7
9
  tasks = Task.all
8
10
  if tasks.empty? # cache tasks
@@ -11,8 +13,7 @@ module HCl
11
13
  end
12
14
  tasks.select! {|t| t.project.code == project_code } if project_code
13
15
  if tasks.empty?
14
- puts "No matching tasks."
15
- exit 1
16
+ fail "No matching tasks."
16
17
  end
17
18
  tasks.map { |task| "#{task.project.id} #{task.id}\t#{task}" }.join("\n")
18
19
  end
@@ -37,12 +38,10 @@ module HCl
37
38
  if entry.cancel
38
39
  "Deleted entry #{entry}."
39
40
  else
40
- puts "Failed to delete #{entry}!"
41
- exit 1
41
+ fail "Failed to delete #{entry}!"
42
42
  end
43
43
  else
44
- puts 'Nothing to cancel.'
45
- exit 1
44
+ fail 'Nothing to cancel.'
46
45
  end
47
46
  end
48
47
  alias_method :oops, :cancel
@@ -64,13 +63,12 @@ module HCl
64
63
  set "task.#{task_name}", *value
65
64
  "Added alias @#{task_name} for #{task}."
66
65
  else
67
- puts "Unrecognized project and task ID: #{value.inspect}"
68
- exit 1
66
+ fail "Unrecognized project and task ID: #{value.inspect}"
69
67
  end
70
68
  end
71
69
 
72
- def completion
73
- %[complete -W "#{aliases.join ' '}" hcl]
70
+ def completion command=$PROGRAM_NAME
71
+ %[complete -W "#{aliases.join ' '}" #{command}]
74
72
  end
75
73
 
76
74
  def aliases
@@ -81,8 +79,7 @@ module HCl
81
79
  starting_time = get_starting_time args
82
80
  task = get_task args
83
81
  if task.nil?
84
- puts "Unknown task alias, try one of the following: ", aliases.join(', ')
85
- exit 1
82
+ fail "Unknown task alias, try one of the following: ", aliases.join(', ')
86
83
  end
87
84
  timer = task.start \
88
85
  :starting_time => starting_time,
@@ -91,6 +88,7 @@ module HCl
91
88
  end
92
89
 
93
90
  def log *args
91
+ fail "There is already a timer running." if DayEntry.with_timer
94
92
  start *args
95
93
  stop
96
94
  end
@@ -102,8 +100,7 @@ module HCl
102
100
  entry.toggle
103
101
  "Stopped #{entry} (at #{current_time})"
104
102
  else
105
- puts "No running timers found."
106
- exit 1
103
+ fail "No running timers found."
107
104
  end
108
105
  end
109
106
 
@@ -117,8 +114,7 @@ module HCl
117
114
  "Added note to #{entry}."
118
115
  end
119
116
  else
120
- puts "No running timers found."
121
- exit 1
117
+ fail "No running timers found."
122
118
  end
123
119
  end
124
120
 
@@ -128,7 +124,7 @@ module HCl
128
124
  result = ''
129
125
  DayEntry.all(date).each do |day|
130
126
  running = day.running? ? '(running) ' : ''
131
- columns = HighLine::SystemExtensions.terminal_size[0]
127
+ columns = HighLine::SystemExtensions.terminal_size[0] rescue 80
132
128
  result << "\t#{day.formatted_hours}\t#{running}#{day.project}: #{day.notes.lines.to_a.last}\n"[0..columns-1]
133
129
  total_hours = total_hours + day.hours.to_f
134
130
  end
@@ -147,8 +143,7 @@ module HCl
147
143
  if entry
148
144
  entry.toggle
149
145
  else
150
- puts "No matching timer found."
151
- exit 1
146
+ fail "No matching timer found."
152
147
  end
153
148
  end
154
149
 
data/lib/hcl/utility.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  module HCl
2
+ class CommandError < StandardError; end
2
3
  module Utility
4
+ def fail *message
5
+ raise CommandError, message.join(' ')
6
+ end
7
+
3
8
  def get_task_ids ident, args
4
9
  if @settings.key? "task.#{ident}"
5
10
  @settings["task.#{ident}"].split(/\s+/)
data/lib/hcl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module HCl
2
- VERSION = '0.4.8'
2
+ VERSION = '0.4.9'
3
3
  end
data/test/app_test.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'test_helper'
2
- class AppTest < Test::Unit::TestCase
2
+ class AppTest < HCl::TestCase
3
3
 
4
4
  def setup
5
5
  # touch config to avoid triggering manual config
@@ -30,18 +30,38 @@ class AppTest < Test::Unit::TestCase
30
30
  app.process_args('show').run
31
31
  end
32
32
 
33
- def test_report_generic_failure
33
+ def test_generic_failure
34
34
  app = HCl::App.new
35
35
  app.expects(:show).raises(RuntimeError)
36
36
  app.expects(:exit).with(1)
37
37
  app.process_args('show').run
38
38
  end
39
39
 
40
- def test_report_socket_error
40
+ def test_socket_error
41
41
  app = HCl::App.new
42
42
  app.expects(:show).raises(SocketError)
43
43
  app.expects(:exit).with(1)
44
44
  app.process_args('show').run
45
+ assert_match /connection failed/i, error_output
46
+ end
47
+
48
+ def test_configure_on_auth_failure
49
+ app = HCl::App.new
50
+ configured = states('configured').starts_as(false)
51
+ app.expects(:show).raises(HCl::TimesheetResource::AuthFailure).when(configured.is(false))
52
+ app.expects(:ask).returns('xxx').times(4).when(configured.is(false))
53
+ app.expects(:write_config).then(configured.is(true))
54
+ app.expects(:show).when(configured.is(true))
55
+ app.process_args('show').run
56
+ assert_match /unable to authenticate/i, error_output
57
+ end
58
+
59
+ def test_api_failure
60
+ app = HCl::App.new
61
+ app.expects(:show).raises(HCl::TimesheetResource::Failure)
62
+ app.expects(:exit).with(1)
63
+ app.process_args('show').run
64
+ assert_match /API failure/i, error_output
45
65
  end
46
66
 
47
67
  end
data/test/command_test.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'test_helper'
2
- class CommandTest < Test::Unit::TestCase
2
+ class CommandTest < HCl::TestCase
3
3
  include HCl::Commands
4
4
  include HCl::Utility
5
5
 
@@ -18,6 +18,11 @@ class CommandTest < Test::Unit::TestCase
18
18
  @settings
19
19
  end
20
20
 
21
+ def test_log_failure
22
+ HCl::DayEntry.expects(:with_timer).returns(stub)
23
+ assert_raises(HCl::CommandError) { log "stuff" }
24
+ end
25
+
21
26
  def test_tasks
22
27
  HCl::Task.expects(:all).returns([HCl::Task.new(
23
28
  id:123,
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class DayEntryTest < Test::Unit::TestCase
3
+ class DayEntryTest < HCl::TestCase
4
4
  def test_from_xml
5
5
  entries = HCl::DayEntry.from_xml(<<-EOD)
6
6
  <daily>
@@ -0,0 +1,23 @@
1
+ module CaptureOutput
2
+ def before_setup
3
+ super
4
+ $stderr = @stderr = StringIO.new
5
+ $stdout = @stdout = StringIO.new
6
+ end
7
+ def after_teardown
8
+ super
9
+ $stderr = STDERR
10
+ $stdout = STDOUT
11
+ end
12
+ def error_output
13
+ @stderr.string
14
+ end
15
+ def standard_output
16
+ @stdout.string
17
+ end
18
+ end
19
+ class MiniTest::Unit::TestCase
20
+ include CaptureOutput
21
+ end
22
+
23
+
data/test/task_test.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- class Task < Test::Unit::TestCase
2
+ class Task < HCl::TestCase
3
3
  def test_cache_file
4
4
  assert_equal "#{HCl::App::HCL_DIR}/cache/tasks.yml", HCl::Task.cache_file
5
5
  end
data/test/test_helper.rb CHANGED
@@ -1,20 +1,35 @@
1
1
  require 'bundler'
2
- require 'simplecov'
3
- SimpleCov.start do
4
- add_filter '/test/'
5
- add_filter do |source_file|
6
- source_file.lines.count < 15
2
+
3
+ begin
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_filter '/test/'
7
+ add_filter '/vendor/' # for travis-ci
8
+ add_filter do |source_file|
9
+ source_file.lines.count < 15
10
+ end
11
+ # source: https://travis-ci.org/zenhob/hcl
12
+ minimum_coverage case RUBY_ENGINE
13
+ when "rbx" then 84
14
+ when "jruby" then 73
15
+ else 78
16
+ end
7
17
  end
18
+ rescue LoadError => e
19
+ $stderr.puts 'No test coverage tools found, skipping coverage check.'
8
20
  end
9
21
 
10
- require 'test/unit'
11
- require 'mocha/setup'
12
- require 'fileutils'
13
- require 'fakeweb'
14
-
15
22
  # override the default hcl dir
16
23
  ENV['HCL_DIR'] = File.dirname(__FILE__)+"/dot_hcl"
17
24
 
18
25
  require 'hcl'
26
+ require 'minitest/autorun'
27
+ require 'mocha/setup'
28
+ require 'fileutils'
29
+ require 'fakeweb'
30
+
31
+ # require test extensions/helpers
32
+ Dir[File.dirname(__FILE__) + '/ext/*.rb'].each { |ext| require ext }
19
33
 
34
+ class HCl::TestCase < MiniTest::Unit::TestCase; end
20
35
 
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class TimesheetResourceTest < Test::Unit::TestCase
3
+ class TimesheetResourceTest < HCl::TestCase
4
4
 
5
5
  def setup
6
6
  FakeWeb.allow_net_connect = false
data/test/utility_test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class UtilityTest < Test::Unit::TestCase
3
+ class UtilityTest < HCl::TestCase
4
4
  include HCl::Utility
5
5
 
6
6
  def test_time2float_decimal
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hcl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zack Hobson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-30 00:00:00.000000000 Z
11
+ date: 2013-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trollop
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rubygems-tasks
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +136,20 @@ dependencies:
122
136
  - - '>='
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: minitest
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
125
153
  description: HCl is a command-line client for manipulating Harvest time sheets.
126
154
  email: zack@zackhobson.com
127
155
  executables:
@@ -132,6 +160,7 @@ files:
132
160
  - CHANGELOG
133
161
  - LICENSE
134
162
  - Rakefile
163
+ - Gemfile
135
164
  - HACKING.markdown
136
165
  - README.markdown
137
166
  - bin/hcl
@@ -147,6 +176,7 @@ files:
147
176
  - test/app_test.rb
148
177
  - test/command_test.rb
149
178
  - test/day_entry_test.rb
179
+ - test/ext/capture_output.rb
150
180
  - test/task_test.rb
151
181
  - test/test_helper.rb
152
182
  - test/timesheet_resource_test.rb