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 +4 -4
- data/CHANGELOG +5 -0
- data/Gemfile +9 -0
- data/HACKING.markdown +4 -0
- data/README.markdown +49 -30
- data/lib/hcl/app.rb +43 -8
- data/lib/hcl/commands.rb +14 -19
- data/lib/hcl/utility.rb +5 -0
- data/lib/hcl/version.rb +1 -1
- data/test/app_test.rb +23 -3
- data/test/command_test.rb +6 -1
- data/test/day_entry_test.rb +1 -1
- data/test/ext/capture_output.rb +23 -0
- data/test/task_test.rb +1 -1
- data/test/test_helper.rb +25 -10
- data/test/timesheet_resource_test.rb +1 -1
- data/test/utility_test.rb +1 -1
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ea82cda49c0d4f4aa43038029ae70b5e22b9e18
|
4
|
+
data.tar.gz: 3bf6719883563294afd3545ce02213abe468e7a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0994f4ee68ce6b5adabb2de5cec31a8db29091fc02eba53929461015e639b152805ba5b42707c693a1bcf1efb200e0918f07c3b6e4522e33beb46187cda9aa8
|
7
|
+
data.tar.gz: 1749a65a4eaaaa8c580573e5dab944ae026fb057bdaa33a3ae225569f1033d9cccada2c5efd77a7c0d1e5785d38fb154ef23d8943e70db48728c3ef0ad54b41f
|
data/CHANGELOG
CHANGED
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
|
-
|
15
|
+
gem install hcl
|
13
16
|
|
14
17
|
or you can install from source:
|
15
18
|
|
16
|
-
|
19
|
+
rake install
|
17
20
|
|
18
21
|
## Usage
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
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
|
-
|
48
|
-
|
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
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
85
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
135
|
+
commands show the time sheet for the specified day:
|
117
136
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
62
|
+
$stderr.puts "Error: #{e}"
|
60
63
|
exit 1
|
61
64
|
rescue SocketError => e
|
62
|
-
|
65
|
+
$stderr.puts "Connection failed. (#{e.message})"
|
63
66
|
exit 1
|
64
67
|
rescue TimesheetResource::ThrottleFailure => e
|
65
|
-
|
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
|
-
|
72
|
+
$stderr.puts "Unable to authenticate: #{e}"
|
70
73
|
request_config
|
71
74
|
run
|
72
75
|
rescue TimesheetResource::Failure => e
|
73
|
-
|
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
|
139
|
+
def read_config
|
137
140
|
if File.exists? CONFIG_FILE
|
138
|
-
config = YAML::load
|
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
|
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
|
-
|
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
|
-
|
41
|
-
exit 1
|
41
|
+
fail "Failed to delete #{entry}!"
|
42
42
|
end
|
43
43
|
else
|
44
|
-
|
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
|
-
|
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 ' '}"
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
151
|
-
exit 1
|
146
|
+
fail "No matching timer found."
|
152
147
|
end
|
153
148
|
end
|
154
149
|
|
data/lib/hcl/utility.rb
CHANGED
data/lib/hcl/version.rb
CHANGED
data/test/app_test.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'test_helper'
|
2
|
-
class AppTest <
|
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
|
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
|
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 <
|
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,
|
data/test/day_entry_test.rb
CHANGED
@@ -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
data/test/test_helper.rb
CHANGED
@@ -1,20 +1,35 @@
|
|
1
1
|
require 'bundler'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
|
data/test/utility_test.rb
CHANGED
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.
|
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
|
+
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
|