achoo 0.4.2 → 0.5
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.
- 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
|