pendaxes 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README.md +148 -0
- data/Rakefile +5 -0
- data/bin/pendaxes +11 -0
- data/fixtures/repo.tar.gz +0 -0
- data/lib/pendaxes/command_line.rb +56 -0
- data/lib/pendaxes/config.rb +10 -0
- data/lib/pendaxes/defaults.rb +12 -0
- data/lib/pendaxes/detector.rb +23 -0
- data/lib/pendaxes/detectors/rspec.rb +78 -0
- data/lib/pendaxes/finder.rb +34 -0
- data/lib/pendaxes/notificator.rb +32 -0
- data/lib/pendaxes/notificators/mail.rb +72 -0
- data/lib/pendaxes/notificators/terminal.rb +19 -0
- data/lib/pendaxes/pending_manager.rb +30 -0
- data/lib/pendaxes/reporter.rb +27 -0
- data/lib/pendaxes/reporters/haml.rb +49 -0
- data/lib/pendaxes/reporters/template.haml +45 -0
- data/lib/pendaxes/reporters/text.rb +13 -0
- data/lib/pendaxes/version.rb +3 -0
- data/lib/pendaxes/workspace.rb +39 -0
- data/lib/pendaxes.rb +10 -0
- data/pendaxes.gemspec +32 -0
- data/spec/defaults_spec.rb +41 -0
- data/spec/detector_spec.rb +12 -0
- data/spec/detectors/rspec_spec.rb +75 -0
- data/spec/finder_spec.rb +62 -0
- data/spec/notificator_spec.rb +41 -0
- data/spec/notificators/mail_spec.rb +184 -0
- data/spec/notificators/terminal_spec.rb +67 -0
- data/spec/pendaxes_spec.rb +7 -0
- data/spec/pending_manager_spec.rb +97 -0
- data/spec/reporter_spec.rb +23 -0
- data/spec/reporters/text_spec.rb +34 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/workspace_spec.rb +115 -0
- metadata +203 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
# Pendaxes
|
2
|
+
|
3
|
+
Throw axes to pending makers!
|
4
|
+
|
5
|
+
Leaving a pending long time is really bad, shouldn't be happened. They'll make a trouble.
|
6
|
+
So, this gem sends notification to committer that added pending after a while from the commit.
|
7
|
+
|
8
|
+
Avoid the trouble due to pending examples :D
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
(1.9 required)
|
13
|
+
|
14
|
+
$ gem install pendaxes
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
$ pendaxes <config_file>
|
19
|
+
|
20
|
+
(writing in cron is recommended)
|
21
|
+
|
22
|
+
### Configuration
|
23
|
+
|
24
|
+
#### Minimal
|
25
|
+
|
26
|
+
Clone `https://github.com/foo/bar.git` to `/path/to/be/cloned/repository`, then detect pendings using rspec detector (default).
|
27
|
+
|
28
|
+
Finally send notification to committers via email (from `no-reply@example.com`).
|
29
|
+
|
30
|
+
workspace:
|
31
|
+
path: /path/to/be/cloned/repository # where to clone?
|
32
|
+
repository: https://github.com/foo/bar.git # where clone from?
|
33
|
+
report:
|
34
|
+
use: haml
|
35
|
+
to: "report.html"
|
36
|
+
notifications:
|
37
|
+
- use: mail
|
38
|
+
from: no-reply@example.com
|
39
|
+
reporter:
|
40
|
+
use: haml
|
41
|
+
|
42
|
+
|
43
|
+
#### Full
|
44
|
+
|
45
|
+
detection:
|
46
|
+
use: rspec # use rspec detector for pending detection. (default)
|
47
|
+
# pattern: '*_spec.rb' # this will be passed after `git grep ... --`. Default is "*_spec.rb".
|
48
|
+
# allowed_for: 604800 # (second) = 1 week. Pendings will be marked "not allowed" if it elapsed more than this value
|
49
|
+
|
50
|
+
workspace:
|
51
|
+
path: /path/to/be/cloned/repository # where to clone?
|
52
|
+
repository: "https://github.com/user/repo.git" # where clone from?
|
53
|
+
|
54
|
+
report: # report configuration to save
|
55
|
+
use: haml # what reporter to use (haml and text is bundled in the gem)
|
56
|
+
to: "report.html" # where to save?
|
57
|
+
include_allowed: true # include "allowed" pendings in report. (default: true)
|
58
|
+
# VVV haml reporter specific configuration VVV
|
59
|
+
commit_url: "https://github.com/user/repo/commit/%commit%" # Used for link to commit. %commit% will be replaced to sha1. If not specified, will not be a link.
|
60
|
+
file_url: "https://github.com/user/repo/blob/HEAD/%file%#L%line%" # Used for link to file. %file% and %line% will be replaced to filepath and line no. If not specified, will not be a link.
|
61
|
+
|
62
|
+
notifications: # notifications. multiple values are accepted.
|
63
|
+
- use: terminal # use terminal notificator.
|
64
|
+
- use: mail # use mail notificator.
|
65
|
+
reporter: # reporter setting for this (mail) notification
|
66
|
+
use: haml
|
67
|
+
commit_url: "https://github.com/user/repo/commit/%commit%"
|
68
|
+
file_url: "https://github.com/user/repo/blob/HEAD/%file%#L%line%"
|
69
|
+
|
70
|
+
# VVV mail notificator specific configuration VVV
|
71
|
+
from: no-reply@example.com
|
72
|
+
to: foo@example.com # (optional) mail will be sent once to this mail address.
|
73
|
+
# without this, mail will be sent separated for each committer.
|
74
|
+
# (mails will include pendings added by its recipient only.)
|
75
|
+
|
76
|
+
delivery_method: sendmail # specify delivery_method. https://github.com/mikel/mail for more detail.
|
77
|
+
delivery_options: # (optional) used as option for delivery_method.
|
78
|
+
:location: /usr/sbin/sendmail
|
79
|
+
|
80
|
+
whitelist: # (optional) if whitelist set, mail won't be sent if not matched.
|
81
|
+
- foo@bar # complete match.
|
82
|
+
- /example\.com$/ # used as regexp.
|
83
|
+
blacklist: # (optional) mail won't be sent if matched. preferred than whitelist.
|
84
|
+
- black@example.com
|
85
|
+
- /^black/
|
86
|
+
|
87
|
+
alias: # (optional) Aliasing emails. if mail will be sent to <value> if git commit author is <key>.
|
88
|
+
"foo@gmail.com": "foo@company.com"
|
89
|
+
|
90
|
+
|
91
|
+
* Reporter: generates text or html by given pendings
|
92
|
+
* Notificator: get text or html by reporter, and notify it (via mail, to terminal, etc...)
|
93
|
+
|
94
|
+
## Axes?
|
95
|
+
|
96
|
+
斧... Axe in Japanese. Recently, Japanese engineer says a review comment as axe (斧).
|
97
|
+
|
98
|
+
Throwing axe means "comment my opnion."
|
99
|
+
|
100
|
+
This script throws axe to committer, about his/her uncontrolled pending tests.
|
101
|
+
|
102
|
+
## Requirements
|
103
|
+
|
104
|
+
* Ruby 1.9+ (1.9.3 supported)
|
105
|
+
* git
|
106
|
+
|
107
|
+
we're using `git grep` and `git blame` to detect pendings, and supported test suite is currently `rspec` only.
|
108
|
+
this gem supports git managed repository, and using rspec.
|
109
|
+
|
110
|
+
Patches for other environment are welcomed. :-)
|
111
|
+
|
112
|
+
## Writing notificator and reporter
|
113
|
+
|
114
|
+
TBD
|
115
|
+
|
116
|
+
## License
|
117
|
+
|
118
|
+
MIT License:
|
119
|
+
|
120
|
+
(c) 2012 Shota Fukumori (sora_h)
|
121
|
+
|
122
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
123
|
+
of this software and associated documentation files (the "Software"), to deal
|
124
|
+
in the Software without restriction, including without limitation the rights
|
125
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
126
|
+
copies of the Software, and to permit persons to whom the Software is
|
127
|
+
furnished to do so, subject to the following conditions:
|
128
|
+
|
129
|
+
The above copyright notice and this permission notice shall be included in
|
130
|
+
all copies or substantial portions of the Software.
|
131
|
+
|
132
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
133
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
134
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
135
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
136
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
137
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
138
|
+
THE SOFTWARE.
|
139
|
+
|
140
|
+
## Contributing
|
141
|
+
|
142
|
+
1. Fork it
|
143
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
144
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
145
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
146
|
+
5. Create new Pull Request
|
147
|
+
|
148
|
+
|
data/Rakefile
ADDED
data/bin/pendaxes
ADDED
Binary file
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative "./config"
|
2
|
+
require_relative "./workspace"
|
3
|
+
require_relative "./detector"
|
4
|
+
require_relative "./reporter"
|
5
|
+
require_relative "./notificator"
|
6
|
+
|
7
|
+
module Pendaxes
|
8
|
+
class CommandLine
|
9
|
+
def initialize(*args)
|
10
|
+
@args = args
|
11
|
+
@config = Config.new(YAML.load_file(args.first))
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
puts "=> Update repository"
|
16
|
+
update
|
17
|
+
|
18
|
+
puts "=> Detect pendings"
|
19
|
+
detect
|
20
|
+
|
21
|
+
puts "=> Writing report"
|
22
|
+
report
|
23
|
+
|
24
|
+
puts "=> Send notifications"
|
25
|
+
notify
|
26
|
+
|
27
|
+
0
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
@workspace = Workspace.new(@config.workspace)
|
32
|
+
@workspace.update
|
33
|
+
end
|
34
|
+
|
35
|
+
def detect
|
36
|
+
@detector = Detector.find(@config.detection.use.to_sym).new(@workspace, {out: $stdout}.merge(@config.detection))
|
37
|
+
@pendings = @detector.detect
|
38
|
+
end
|
39
|
+
|
40
|
+
def report
|
41
|
+
@reporter = Reporter.find(@config.report.use.to_sym).new(@config.report)
|
42
|
+
@reporter.add @pendings
|
43
|
+
report = @reporter.report
|
44
|
+
open(@config.report.to, 'w') {|io| io.puts report }
|
45
|
+
end
|
46
|
+
|
47
|
+
def notify
|
48
|
+
@config.notifications.map{|x| Hashr.new(x) }.each do |notification|
|
49
|
+
puts " * #{notification.use}"
|
50
|
+
notificator = Notificator.find(notification.use.to_sym).new({out: $stdout}.merge(notification))
|
51
|
+
notificator.add @pendings
|
52
|
+
notificator.notify
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pendaxes
|
2
|
+
module Defaults
|
3
|
+
def defaults(h=nil)
|
4
|
+
default_defaults = self.superclass.respond_to?(:defaults) ? self.superclass.defaults : Hashr.new
|
5
|
+
@defaults ||= default_defaults
|
6
|
+
if h
|
7
|
+
@defaults = default_defaults.merge(h)
|
8
|
+
end
|
9
|
+
@defaults
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'pending_manager'
|
2
|
+
require_relative 'defaults'
|
3
|
+
require_relative 'finder'
|
4
|
+
require 'hashr'
|
5
|
+
|
6
|
+
module Pendaxes
|
7
|
+
class Detector
|
8
|
+
extend Defaults
|
9
|
+
extend Finder
|
10
|
+
find_in 'pendaxes/detectors'
|
11
|
+
|
12
|
+
defaults allowed_for: 604800
|
13
|
+
|
14
|
+
def initialize(workspace, config={})
|
15
|
+
@config = Hashr.new(self.class.defaults.merge(config))
|
16
|
+
@workspace = workspace
|
17
|
+
@pendings = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def detect
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative '../detector'
|
3
|
+
require 'time'
|
4
|
+
require 'ripper'
|
5
|
+
require 'ripper/lexer'
|
6
|
+
|
7
|
+
module Pendaxes
|
8
|
+
class Detector
|
9
|
+
class RSpec < Detector
|
10
|
+
PENDERS = %w(xit xexample xspecify pending).freeze
|
11
|
+
GREP_CMD = ( %w(grep --name-only -e) \
|
12
|
+
+ PENDERS.join(' --or -e ').split(/ /) \
|
13
|
+
+ ['--']
|
14
|
+
).freeze
|
15
|
+
PARENTS = %w(context describe it example specify xexample xspecify xit).freeze
|
16
|
+
|
17
|
+
defaults pattern: '*_spec.rb'
|
18
|
+
|
19
|
+
def detect
|
20
|
+
@workspace.dive do
|
21
|
+
pattern = @config.pattern.is_a?(Array) ? @config.pattern : [@config.pattern]
|
22
|
+
grep = @workspace.git(*GREP_CMD, *pattern).force_encoding("UTF-8")
|
23
|
+
return [] unless grep
|
24
|
+
files = grep.split(/\r?\n/).map(&:chomp)
|
25
|
+
|
26
|
+
files.inject([]) do |pendings, file|
|
27
|
+
@config.out.puts "* #{file}" if @config.out
|
28
|
+
file_content = File.read(file).force_encoding(@config.encoding || "UTF-8")
|
29
|
+
lines = file_content.split(/\r?\n/)
|
30
|
+
tokens = Ripper.lex(file_content, file)
|
31
|
+
_prev = nil
|
32
|
+
|
33
|
+
tokens.each_with_index do |token, i|
|
34
|
+
prev = _prev
|
35
|
+
_prev = token[1]
|
36
|
+
next if prev == :on_symbeg
|
37
|
+
next unless token[1] == :on_ident && PENDERS.include?(token[2])
|
38
|
+
pending = {}
|
39
|
+
|
40
|
+
line = token[0][0]
|
41
|
+
|
42
|
+
parent = (i-1).downto(0).inject {|_, j|
|
43
|
+
break lines[tokens[j][0][0]-1] if tokens[j][1] == :on_ident && (j.zero? || tokens[j-1][1] != :on_symbeg) && PARENTS.include?(tokens[j][2])
|
44
|
+
nil
|
45
|
+
}
|
46
|
+
parent.gsub!(/^[ \t]+/, '') if parent
|
47
|
+
|
48
|
+
pending[:example] = {
|
49
|
+
file: file, line: line,
|
50
|
+
message: lines[line-1].gsub(/^[ \t]+/, ''), parent: parent
|
51
|
+
}
|
52
|
+
|
53
|
+
pending[:commit] = blame(file, line)
|
54
|
+
pending[:allowed] = (Time.now - pending[:commit][:at]) <= @config.allowed_for
|
55
|
+
|
56
|
+
pendings << pending
|
57
|
+
end
|
58
|
+
|
59
|
+
pendings
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def blame(file, line)
|
67
|
+
@config.out.puts " * blaming #{file}:#{line}" if @config.out
|
68
|
+
blame = @workspace.git('blame', '-L', "#{line},#{line}", '-l', '-w', '-p', file).force_encoding("UTF-8").split(/\r?\n/).map{|l| l.split(/ /) }
|
69
|
+
commit = {
|
70
|
+
sha: blame[0].first, name: blame[1][1..-1].join(' '),
|
71
|
+
email: blame[2][1..-1].join(' ').gsub(/^</,'').gsub(/>$/,'')
|
72
|
+
}
|
73
|
+
commit[:at] = Time.parse(@workspace.git(*%w(log --pretty=%aD -n1), commit[:sha]).chomp)
|
74
|
+
commit
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Pendaxes
|
2
|
+
module Finder
|
3
|
+
def find(name)
|
4
|
+
@finder_cache ||= {}
|
5
|
+
path = case name
|
6
|
+
when String
|
7
|
+
name
|
8
|
+
when Symbol
|
9
|
+
"#{@finder_prefix || ""}#{name}"
|
10
|
+
else
|
11
|
+
raise ArgumentError, "name should be a kind of String or Symbol"
|
12
|
+
end
|
13
|
+
return @finder_cache[name] if @finder_cache[name]
|
14
|
+
require path
|
15
|
+
announce name, @finder_latest_inherited
|
16
|
+
end
|
17
|
+
|
18
|
+
def inherited(klass)
|
19
|
+
if klass.name
|
20
|
+
announce klass.name.gsub(/^.*::/,'').gsub(/.[A-Z]/){|s| s[0]+"_"+s[1] }.downcase.to_sym, klass
|
21
|
+
end
|
22
|
+
@finder_latest_inherited = klass
|
23
|
+
end
|
24
|
+
|
25
|
+
def announce(name, klass)
|
26
|
+
(@finder_cache ||= {})[name] = klass
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_in(prefix)
|
30
|
+
@finder_prefix = prefix + "/"
|
31
|
+
end
|
32
|
+
private :find_in
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'pending_manager'
|
2
|
+
require_relative 'defaults'
|
3
|
+
require_relative 'finder'
|
4
|
+
require 'hashr'
|
5
|
+
|
6
|
+
module Pendaxes
|
7
|
+
class Notificator
|
8
|
+
include PendingManager
|
9
|
+
extend Defaults
|
10
|
+
extend Finder
|
11
|
+
find_in 'pendaxes/notificators'
|
12
|
+
defaults reporter: {use: :text}
|
13
|
+
|
14
|
+
def initialize(config={})
|
15
|
+
@config = Hashr.new(self.class.defaults.merge(config))
|
16
|
+
@pendings = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def notify
|
20
|
+
end
|
21
|
+
|
22
|
+
def reporter
|
23
|
+
Reporter.find(@config.reporter.use.to_sym)
|
24
|
+
end
|
25
|
+
|
26
|
+
def report_for(pendings)
|
27
|
+
r = reporter.new({include_allowed: true}.merge(@config.reporter))
|
28
|
+
r.add pendings
|
29
|
+
r.report
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative '../notificator'
|
2
|
+
require 'mail'
|
3
|
+
|
4
|
+
module Pendaxes
|
5
|
+
class Notificator
|
6
|
+
class Mail < Notificator
|
7
|
+
defaults reporter: {use: :text}, blacklist: []
|
8
|
+
|
9
|
+
def notify
|
10
|
+
if @config.to
|
11
|
+
deliver(pendings, @config.to)
|
12
|
+
else
|
13
|
+
pendings.group_by {|pending| pending[:commit][:email] }.each do |email, pends|
|
14
|
+
deliver(pends, email)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def whitelist
|
20
|
+
if @config.whitelist
|
21
|
+
@whitelist ||= process_email_filter(@config.whitelist)
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def blacklist
|
28
|
+
@blacklist ||= process_email_filter(@config.blacklist)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def deliver(pends,email)
|
34
|
+
real_email = (@config.alias || {})[email] || email
|
35
|
+
return nil if blacklist.match?(real_email) || (whitelist && !whitelist.match?(real_email))
|
36
|
+
|
37
|
+
mail = ::Mail.new
|
38
|
+
mail.from = @config.from
|
39
|
+
mail.to = real_email
|
40
|
+
mail.subject = "[Pendaxes] Your #{pends.size} pending tests are waiting to be fixed"
|
41
|
+
mail.body = report_for(pends)
|
42
|
+
mail.content_type = 'text/html; charset=utf-8' if reporter.html?
|
43
|
+
|
44
|
+
if @config.delivery_method
|
45
|
+
mail.delivery_method @config.delivery_method.to_sym, @config.delivery_options || {}
|
46
|
+
end
|
47
|
+
|
48
|
+
@config.out.puts mail.inspect if @config.out
|
49
|
+
|
50
|
+
mail.deliver
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_email_filter(list)
|
54
|
+
filter = list.map do |email|
|
55
|
+
if %r{^/(.*)/$} === email
|
56
|
+
Regexp.new($1)
|
57
|
+
else
|
58
|
+
email
|
59
|
+
end
|
60
|
+
end
|
61
|
+
class << filter
|
62
|
+
def match?(email)
|
63
|
+
self.any? do |condition|
|
64
|
+
condition.is_a?(Regexp) ? condition === email : condition == email
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
filter
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative '../notificator'
|
2
|
+
|
3
|
+
module Pendaxes
|
4
|
+
class Notificator
|
5
|
+
class Terminal < Notificator
|
6
|
+
defaults to: $stdout, reporter: {use: :text}
|
7
|
+
|
8
|
+
def notify
|
9
|
+
io = @config.to
|
10
|
+
pendings.group_by{|x| "#{x[:commit][:name]} <#{x[:commit][:email]}>" }.each do |name, pends|
|
11
|
+
io.puts "#{name}:"
|
12
|
+
io.puts
|
13
|
+
io.puts report_for(pends)
|
14
|
+
io.puts
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'hashr'
|
2
|
+
|
3
|
+
module Pendaxes
|
4
|
+
module PendingManager
|
5
|
+
def add(pending={})
|
6
|
+
case pending
|
7
|
+
when Array
|
8
|
+
@pendings.push *pending.map{|x| Hashr.new(x) }
|
9
|
+
when Hash
|
10
|
+
@pendings << Hashr.new(pending)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def pendings
|
15
|
+
if @config.include_allowed
|
16
|
+
all_pendings
|
17
|
+
else
|
18
|
+
@pendings.reject(&:allowed)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def all_pendings
|
23
|
+
@pendings
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset
|
27
|
+
@pendings = []
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'pending_manager'
|
2
|
+
require_relative 'defaults'
|
3
|
+
require_relative 'finder'
|
4
|
+
require 'hashr'
|
5
|
+
|
6
|
+
module Pendaxes
|
7
|
+
class Reporter
|
8
|
+
include PendingManager
|
9
|
+
extend Defaults
|
10
|
+
extend Finder
|
11
|
+
find_in 'pendaxes/reporters'
|
12
|
+
|
13
|
+
defaults include_allowed: true
|
14
|
+
|
15
|
+
def initialize(config={})
|
16
|
+
@config = Hashr.new(self.class.defaults.merge(config))
|
17
|
+
@pendings = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def report
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.html?
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative '../reporter'
|
2
|
+
require 'haml'
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'cgi'
|
5
|
+
|
6
|
+
module Pendaxes
|
7
|
+
class Reporter
|
8
|
+
class Haml < Reporter
|
9
|
+
defaults commit_url: nil,
|
10
|
+
file_url: nil,
|
11
|
+
report_url: nil,
|
12
|
+
gravatar: true,
|
13
|
+
older_first: true,
|
14
|
+
template: "#{File.dirname(__FILE__)}/template.haml"
|
15
|
+
|
16
|
+
def report
|
17
|
+
haml = ::Haml::Engine.new(File.read(@config.template))
|
18
|
+
haml.render(binding, config: @config)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.html?; true; end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def relative_time(time, from = Time.now)
|
26
|
+
diff = from - time
|
27
|
+
return "in the future" if diff < 0
|
28
|
+
case diff
|
29
|
+
when 0..10
|
30
|
+
"Just now"
|
31
|
+
when 11..60
|
32
|
+
"in a minute"
|
33
|
+
when 61...3600
|
34
|
+
"%.1f minutes ago" % (diff/60)
|
35
|
+
when 3600...86400
|
36
|
+
"%.1f hours ago" % (diff/3600.0)
|
37
|
+
when 86400...604800
|
38
|
+
"%.1f days ago" % (diff/86400.0)
|
39
|
+
when 604800...2419200
|
40
|
+
"%.1f weeks ago" % (diff/604800.0)
|
41
|
+
when 2419200...31556926
|
42
|
+
"%.1f months ago" % (diff/2419200.0)
|
43
|
+
else
|
44
|
+
"%.1f years ago" % (diff/31556926.0)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|