achoo 0.4.2 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +13 -0
- data/README.rdoc +26 -22
- data/lib/achoo/achievo/hour_administration_form.rb +2 -3
- data/lib/achoo/achievo/hour_registration_form.rb +12 -15
- data/lib/achoo/achievo/hour_registration_form_ranged.rb +5 -2
- data/lib/achoo/achievo/lock_month_form.rb +1 -5
- data/lib/achoo/achievo/login_form.rb +3 -3
- data/lib/achoo/app.rb +27 -28
- data/lib/achoo/awake.rb +1 -1
- data/lib/achoo/extensions.rb +4 -0
- data/lib/achoo/ical.rb +6 -2
- data/lib/achoo/plugin/awake.rb +23 -0
- data/lib/achoo/plugin/ical.rb +47 -0
- data/lib/achoo/plugin/vcs.rb +26 -0
- data/lib/achoo/plugin_base.rb +6 -0
- data/lib/achoo/rc_loader.rb +9 -0
- data/lib/achoo/temporal/timespan.rb +3 -3
- data/lib/achoo/term.rb +7 -3
- data/lib/achoo/term/table.rb +5 -6
- data/lib/achoo/ui/commands.rb +12 -12
- data/lib/achoo/ui/date_chooser.rb +1 -1
- data/lib/achoo/ui/exception_handling.rb +1 -1
- data/lib/achoo/ui/register_hours.rb +50 -50
- data/lib/achoo/vcs/git.rb +5 -3
- data/test/acceptance/test_flexi_time.rb +41 -0
- data/test/acceptance/test_lock_month.rb +39 -0
- data/test/acceptance/test_register_hours.rb +161 -0
- data/test/lib/achievo_mock.rb +76 -0
- data/test/lib/achoo_runner.rb +54 -0
- data/test/lib/test_helpers.rb +43 -0
- data/test/unit/test_achievo_date_field.rb +34 -0
- data/test/unit/test_awake.rb +98 -0
- data/test/unit/test_extensions_array.rb +25 -0
- data/test/unit/test_system_cstruct.rb +28 -0
- data/test/unit/test_system_log_entry.rb +31 -0
- data/test/unit/test_term_menu.rb +71 -0
- data/test/unit/test_term_table.rb +52 -0
- data/test/unit/test_timespan.rb +48 -0
- data/test/unit/test_ui_date_chooser.rb +36 -0
- metadata +101 -74
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'achoo'
|
2
|
+
require 'achoo/vcs'
|
3
|
+
require 'achoo/ui'
|
4
|
+
require 'plugman/plugin_base'
|
5
|
+
|
6
|
+
module Achoo
|
7
|
+
class Plugin
|
8
|
+
class VCS < Plugman::PluginBase
|
9
|
+
|
10
|
+
include UI::ExceptionHandling
|
11
|
+
|
12
|
+
def state_ok?; RC.has_key?(:vcs_dirs); end
|
13
|
+
|
14
|
+
def before_register_hour_remark(date)
|
15
|
+
puts '-' * 80
|
16
|
+
puts "VCS logs for #{date}:"
|
17
|
+
begin
|
18
|
+
Achoo::VCS.print_logs_for(date, RC[:vcs_dirs])
|
19
|
+
rescue Exception => e
|
20
|
+
puts handle_exception("Failed to retrieve VCS logs.", e)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/achoo/rc_loader.rb
CHANGED
@@ -49,6 +49,15 @@ module Achoo
|
|
49
49
|
RC[key] = []
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
if RC.has_key?(:ical)
|
54
|
+
RC[:ical].each do |cal|
|
55
|
+
if cal.has_key?(:host)
|
56
|
+
puts Term.warn "You are using the old configuration format for ical. See the README for information on the new format"
|
57
|
+
return
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
52
61
|
end
|
53
62
|
|
54
63
|
end
|
@@ -18,14 +18,14 @@ module Achoo
|
|
18
18
|
def contains?(timeish_or_timespan)
|
19
19
|
if timeish_or_timespan.is_a? Timespan
|
20
20
|
time = timeish_or_timespan
|
21
|
-
|
21
|
+
cover?(time.first) && cover?(time.last)
|
22
22
|
else
|
23
|
-
|
23
|
+
cover?(to_time(timeish_or_timespan))
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
def overlaps?(timespan)
|
28
|
-
|
28
|
+
cover?(timespan.first) || cover?(timespan.last) ||
|
29
29
|
timespan.contains?(self)
|
30
30
|
end
|
31
31
|
|
data/lib/achoo/term.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'achoo'
|
4
|
+
require 'readline'
|
4
5
|
|
5
6
|
module Achoo
|
6
7
|
class Term
|
@@ -20,6 +21,11 @@ module Achoo
|
|
20
21
|
def self.warn(text); effect(YELLOW, text); end
|
21
22
|
def self.fatal(text); effect(RED, text); end
|
22
23
|
|
24
|
+
def self.clearscreen
|
25
|
+
print "\e[2J\e[H"
|
26
|
+
$stdout.flush
|
27
|
+
end
|
28
|
+
|
23
29
|
def self.password
|
24
30
|
`stty -echo`
|
25
31
|
pas = ask('Password')
|
@@ -30,9 +36,7 @@ module Achoo
|
|
30
36
|
def self.ask(question='')
|
31
37
|
answer = nil
|
32
38
|
loop do
|
33
|
-
|
34
|
-
$stdout.flush
|
35
|
-
answer = gets
|
39
|
+
answer = Readline.readline(bold("#{question}> "), true)
|
36
40
|
|
37
41
|
# Answer is nil if user hits C-d on an empty input
|
38
42
|
if answer.nil?
|
data/lib/achoo/term/table.rb
CHANGED
@@ -65,13 +65,12 @@ module Achoo
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def calculate_table_cell_widths
|
68
|
-
|
69
|
-
@
|
70
|
-
|
71
|
-
|
72
|
-
@data_rows.each do |r|
|
68
|
+
rows = [@headers] + @data_rows
|
69
|
+
rows += [@summaries] unless @summaries.nil?
|
70
|
+
lengths = Array.new(@headers.length, 0)
|
71
|
+
rows.each do |r|
|
73
72
|
r.each_with_index do |d, i|
|
74
|
-
lengths[i] = [d.length, lengths[i]].max
|
73
|
+
lengths[i] = [d.scan(/./mu).length, lengths[i]].max # FIX scan is a 1.8 hack
|
75
74
|
end
|
76
75
|
end
|
77
76
|
lengths
|
data/lib/achoo/ui/commands.rb
CHANGED
@@ -9,30 +9,30 @@ module Achoo
|
|
9
9
|
include DateChoosers
|
10
10
|
include Common
|
11
11
|
|
12
|
-
def show_registered_hours_for_day
|
12
|
+
def show_registered_hours_for_day
|
13
13
|
date = date_chooser
|
14
|
-
form = Achievo::HourAdministrationForm.new
|
14
|
+
form = Achievo::HourAdministrationForm.new
|
15
15
|
form.show_registered_hours_for_day(date)
|
16
16
|
end
|
17
17
|
|
18
|
-
def show_registered_hours_for_week
|
18
|
+
def show_registered_hours_for_week
|
19
19
|
date = date_chooser
|
20
|
-
form = Achievo::HourAdministrationForm.new
|
20
|
+
form = Achievo::HourAdministrationForm.new
|
21
21
|
form.show_registered_hours_for_week(date)
|
22
22
|
end
|
23
23
|
|
24
24
|
|
25
|
-
def show_flexi_time
|
25
|
+
def show_flexi_time
|
26
26
|
date = date_chooser
|
27
|
-
form = Achievo::HourAdministrationForm.new
|
27
|
+
form = Achievo::HourAdministrationForm.new
|
28
28
|
balance = form.flexi_time(date)
|
29
29
|
puts "Flexi time balance: #{Term::underline(balance)}"
|
30
30
|
end
|
31
31
|
|
32
32
|
|
33
|
-
def lock_month
|
33
|
+
def lock_month
|
34
34
|
month = month_chooser
|
35
|
-
form = Achievo::LockMonthForm.new
|
35
|
+
form = Achievo::LockMonthForm.new
|
36
36
|
form.lock_month(month)
|
37
37
|
form.print_values
|
38
38
|
if confirm
|
@@ -43,20 +43,20 @@ module Achoo
|
|
43
43
|
end
|
44
44
|
|
45
45
|
|
46
|
-
def show_holiday_report
|
47
|
-
page =
|
46
|
+
def show_holiday_report
|
47
|
+
page = AGENT.get(RC[:holiday_report_url])
|
48
48
|
page.body.match(/<b>(\d+,\d+)<\/b>/)
|
49
49
|
puts "Balance: #{Term::underline($1)}"
|
50
50
|
end
|
51
51
|
|
52
52
|
|
53
|
-
def view_report
|
53
|
+
def view_report
|
54
54
|
choices = RC[:reports].keys
|
55
55
|
answer = Term.choose('Report', choices)
|
56
56
|
key = choices[answer.to_i - 1]
|
57
57
|
|
58
58
|
puts "Fetching data ..."
|
59
|
-
page =
|
59
|
+
page = AGENT.get(RC[:url] + RC[:reports][key])
|
60
60
|
|
61
61
|
table = Achievo::Table.new(page.search('#rl_1 tr'))
|
62
62
|
table.select_columns do |c|
|
@@ -14,7 +14,7 @@ module Achoo
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def get_exception_reason(e)
|
17
|
-
"\nReason: \n\t" + e.message.gsub("\n", "\n\t") + "\n---\n\t" + e.backtrace.join("\n\t")
|
17
|
+
"\nType:\t" + e.class.to_s + "\nReason: \n\t" + e.message.gsub("\n", "\n\t") + "\n---\n\t" + e.backtrace.join("\n\t")
|
18
18
|
end
|
19
19
|
|
20
20
|
end
|
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'achoo/achievo'
|
2
|
-
require 'achoo/awake'
|
3
|
-
require 'achoo/ical'
|
4
2
|
require 'achoo/term'
|
5
3
|
require 'achoo/ui'
|
6
|
-
require '
|
4
|
+
require 'readline'
|
7
5
|
|
8
6
|
module Achoo
|
9
7
|
module UI
|
@@ -12,7 +10,10 @@ module Achoo
|
|
12
10
|
include DateChoosers
|
13
11
|
include ExceptionHandling
|
14
12
|
|
15
|
-
def
|
13
|
+
def initialize
|
14
|
+
end
|
15
|
+
|
16
|
+
def register_hours
|
16
17
|
date = optionally_ranged_date_chooser
|
17
18
|
|
18
19
|
puts "Fetching data ..."
|
@@ -20,14 +21,14 @@ module Achoo
|
|
20
21
|
Achievo::HourRegistrationFormRanged
|
21
22
|
else
|
22
23
|
Achievo::HourRegistrationForm
|
23
|
-
end.new
|
24
|
+
end.new
|
24
25
|
|
25
26
|
form.date = date
|
26
27
|
form.project = project_chooser(form)
|
27
28
|
form.phase = phase_chooser(form)
|
28
|
-
|
29
|
+
PLUGINS.send_before_register_hour_remark(date) unless date.class == Array
|
29
30
|
form.remark = remark_chooser
|
30
|
-
|
31
|
+
PLUGINS.send_before_register_hour_hours(date) unless date.class == Array
|
31
32
|
form.hours = hours_chooser
|
32
33
|
|
33
34
|
answer = Term.ask("Do you want to change the defaults for worktime period and/or billing percentage? [N/y]").downcase
|
@@ -43,6 +44,8 @@ module Achoo
|
|
43
44
|
else
|
44
45
|
puts "Cancelled"
|
45
46
|
end
|
47
|
+
|
48
|
+
date
|
46
49
|
end
|
47
50
|
|
48
51
|
|
@@ -53,17 +56,6 @@ module Achoo
|
|
53
56
|
end
|
54
57
|
|
55
58
|
|
56
|
-
def print_hours_help(date)
|
57
|
-
puts "Awake log:"
|
58
|
-
begin
|
59
|
-
awake = Awake.new
|
60
|
-
awake.at(date)
|
61
|
-
puts
|
62
|
-
rescue Exception => e
|
63
|
-
print handle_exception("Failed to retrieve awake log.", e)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
59
|
def hours_chooser
|
68
60
|
answer = Term::ask 'Hours [7:30]'
|
69
61
|
return answer == '' ? '7.5' : answer
|
@@ -83,25 +75,6 @@ module Achoo
|
|
83
75
|
true)
|
84
76
|
end
|
85
77
|
|
86
|
-
def print_remark_help(date)
|
87
|
-
puts "VCS logs for #{date}:"
|
88
|
-
begin
|
89
|
-
VCS.print_logs_for(date, RC[:vcs_dirs])
|
90
|
-
rescue Exception => e
|
91
|
-
puts handle_exception("Failed to retrieve VCS logs.", e)
|
92
|
-
end
|
93
|
-
puts '-' * 80
|
94
|
-
puts "Calendar events for #{date}:"
|
95
|
-
puts '---'
|
96
|
-
begin
|
97
|
-
RC[:ical].each do |config|
|
98
|
-
ICal.from_http_request(config).print_events(date)
|
99
|
-
end
|
100
|
-
rescue Exception => e
|
101
|
-
puts handle_exception("Failed to retrieve calendar events.", e)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
78
|
def remark_chooser
|
106
79
|
Term::ask 'Remark'
|
107
80
|
end
|
@@ -112,29 +85,56 @@ module Achoo
|
|
112
85
|
projects = form.recent_projects
|
113
86
|
answer = Term.choose('Project [1]', projects.collect { |p| p[1] },
|
114
87
|
'Other', [''])
|
115
|
-
case answer
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
88
|
+
return case answer
|
89
|
+
when '0'
|
90
|
+
all_projects_chooser(form)
|
91
|
+
when ''
|
92
|
+
projects[0][0]
|
93
|
+
else
|
94
|
+
projects[answer.to_i-1][0]
|
95
|
+
end
|
123
96
|
end
|
124
97
|
|
125
98
|
|
126
99
|
|
127
100
|
def all_projects_chooser(form)
|
128
|
-
|
129
|
-
|
130
|
-
|
101
|
+
projects = form.all_projects
|
102
|
+
|
103
|
+
p projects
|
104
|
+
|
105
|
+
# FIX move readline stuff to the term modules
|
106
|
+
original_readline_comp_proc = Readline.completion_proc
|
107
|
+
original_readline_comp_append_char = Readline.completion_append_character
|
108
|
+
Readline.completion_append_character = ''
|
109
|
+
Readline.completion_proc = proc do |s|
|
110
|
+
projects.collect {|p| p[1] }.grep(/^#{Regexp.escape(s)}/)
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
answer = chooser_helper(projects,
|
115
|
+
'All projects',
|
116
|
+
'Project')
|
117
|
+
|
118
|
+
Readline.completion_proc = original_readline_comp_proc
|
119
|
+
Readline.completion_append_character = original_readline_comp_append_char
|
120
|
+
|
121
|
+
answer
|
131
122
|
end
|
132
123
|
|
133
124
|
def chooser_helper(options, heading, prompt, empty_allowed=false)
|
134
|
-
puts heading
|
135
125
|
extra = empty_allowed ? [''] : []
|
136
|
-
|
126
|
+
project_names = options.collect {|p| p[1] }
|
127
|
+
if heading == 'All projects'
|
128
|
+
# FIX ugly conditional
|
129
|
+
extra += project_names
|
130
|
+
end
|
131
|
+
answer = Achoo::Term.choose(prompt, options.collect {|p| p[1] }, nil, extra)
|
137
132
|
answer = '1' if answer.empty?
|
133
|
+
if heading == 'All projects'
|
134
|
+
# FIX ugly conditional
|
135
|
+
index = project_names.find_index(answer) + 1
|
136
|
+
answer = index unless index.nil?
|
137
|
+
end
|
138
138
|
options[answer.to_i-1][0]
|
139
139
|
end
|
140
140
|
|
data/lib/achoo/vcs/git.rb
CHANGED
@@ -13,10 +13,12 @@ module Achoo
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def log_for(date)
|
16
|
-
|
17
|
-
|
16
|
+
format = '%Y-%m-%dT00:00:00'
|
17
|
+
from = date.strftime(format)
|
18
|
+
to = (date+1).strftime(format)
|
18
19
|
|
19
|
-
|
20
|
+
cmd = "cd #@dir; git log --author=#{ENV['USER']} --oneline --after=#{from} --before=#{to} | cut -d ' ' -f 2-"
|
21
|
+
`#{cmd}`
|
20
22
|
end
|
21
23
|
|
22
24
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test_helpers'
|
2
|
+
|
3
|
+
class TestFlexiTime < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include AcceptanceBase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
|
10
|
+
hour_administration_html = %q{
|
11
|
+
<html>
|
12
|
+
<head></head>
|
13
|
+
<body>
|
14
|
+
<form name="dayview">
|
15
|
+
<input type="text" name="viewdate[day]" value="20">
|
16
|
+
<input type="text" name="viewdate[month]" value="03">
|
17
|
+
<input type="text" name="viewdate[year]" value="2010">
|
18
|
+
</form>
|
19
|
+
|
20
|
+
<p>Flexi time balance: -44:30</p>
|
21
|
+
|
22
|
+
</body>
|
23
|
+
</html>
|
24
|
+
}
|
25
|
+
|
26
|
+
@server.register(:get, '/time_registration', [ 200, nil, hour_administration_html ])
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_flexi_time
|
30
|
+
achoo(:verbose => $DEBUG) do
|
31
|
+
expect '2. Show flexitime balance'
|
32
|
+
expect_main_prompt
|
33
|
+
puts '2'
|
34
|
+
puts '2010-03-20'
|
35
|
+
expect /Flexi time balance:.*-44:30/
|
36
|
+
expect_main_prompt
|
37
|
+
puts 'q'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'test_helpers'
|
2
|
+
|
3
|
+
class TestLockMonth < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include AcceptanceBase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
|
10
|
+
lock_month_html = %q{
|
11
|
+
<html>
|
12
|
+
<head></head>
|
13
|
+
<body>
|
14
|
+
<form name="entryform">
|
15
|
+
<input type="text" name="period" value="">
|
16
|
+
</form>
|
17
|
+
</body>
|
18
|
+
</html>
|
19
|
+
}
|
20
|
+
|
21
|
+
@server.register(:get, '/lock_months', [ 200, nil, lock_month_html ])
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_lock_month
|
25
|
+
achoo(:verbose => $DEBUG) do
|
26
|
+
expect '6. Lock month'
|
27
|
+
expect_main_prompt
|
28
|
+
puts '6'
|
29
|
+
expect /Period \(\[\d{6}\] | YYYYMM\)>/
|
30
|
+
puts '201003'
|
31
|
+
expect 'Month: 201003'
|
32
|
+
expect 'Submit? [Y/n]>'
|
33
|
+
puts 'n'
|
34
|
+
expect 'Cancelled'
|
35
|
+
expect_main_prompt
|
36
|
+
puts 'q'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|