bugwatch 0.1
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/bugwatch.gemspec +74 -0
- data/lib/bugwatch.rb +50 -0
- data/lib/bugwatch/adapters.rb +50 -0
- data/lib/bugwatch/analysis.rb +58 -0
- data/lib/bugwatch/attrs.rb +64 -0
- data/lib/bugwatch/churn.rb +60 -0
- data/lib/bugwatch/commit.rb +82 -0
- data/lib/bugwatch/complexity_score.rb +59 -0
- data/lib/bugwatch/diff.rb +73 -0
- data/lib/bugwatch/diff_parser.rb +68 -0
- data/lib/bugwatch/exception_data.rb +57 -0
- data/lib/bugwatch/exception_tracker.rb +72 -0
- data/lib/bugwatch/file_adapters/ruby_file_adapter.rb +51 -0
- data/lib/bugwatch/flog_score.rb +88 -0
- data/lib/bugwatch/import.rb +57 -0
- data/lib/bugwatch/method_parser.rb +105 -0
- data/lib/bugwatch/repo.rb +134 -0
- data/lib/bugwatch/ruby_complexity.rb +85 -0
- data/lib/bugwatch/tag.rb +59 -0
- data/lib/bugwatch/tree.rb +65 -0
- data/vendor/flog/lib/flog.rb +803 -0
- metadata +113 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright (c) 2013, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
module Bugwatch
|
32
|
+
|
33
|
+
class Import
|
34
|
+
|
35
|
+
def initialize(repo, caching_strategy)
|
36
|
+
@repo = repo
|
37
|
+
@caching_strategy = caching_strategy
|
38
|
+
end
|
39
|
+
|
40
|
+
def import(begin_sha=nil)
|
41
|
+
unimported_commits(begin_sha).each do |commit_sha|
|
42
|
+
commit = @repo.commit(commit_sha)
|
43
|
+
@caching_strategy.store(commit) if commit
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def unimported_commits(begin_sha)
|
50
|
+
repo_shas = @repo.commit_shas(begin_sha)
|
51
|
+
imported_shas = @caching_strategy.imported
|
52
|
+
repo_shas - imported_shas
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# Copyright (c) 2013, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
require 'ruby_parser'
|
32
|
+
require 'sexp_processor'
|
33
|
+
|
34
|
+
module Bugwatch
|
35
|
+
|
36
|
+
class MethodParser < SexpProcessor
|
37
|
+
|
38
|
+
attr_reader :parser, :klasses
|
39
|
+
|
40
|
+
def initialize(line_range)
|
41
|
+
super()
|
42
|
+
@line_range = line_range
|
43
|
+
@klasses = Hash.new {|h, k| h[k] = []}
|
44
|
+
@current_class = []
|
45
|
+
self.auto_shift_type = true
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.find(code, line_range)
|
49
|
+
method_parser = new(line_range)
|
50
|
+
ast = RubyParser.new.process(code)
|
51
|
+
method_parser.process ast
|
52
|
+
method_parser.klasses
|
53
|
+
end
|
54
|
+
|
55
|
+
def process_class(exp)
|
56
|
+
begin_line = exp.line
|
57
|
+
line_range = begin_line..exp.last.line # TODO figure out last line
|
58
|
+
class_name = get_class_name(exp.shift)
|
59
|
+
within_class(class_name, line_range) do
|
60
|
+
process(exp.shift) until exp.empty?
|
61
|
+
end
|
62
|
+
s()
|
63
|
+
end
|
64
|
+
|
65
|
+
alias_method :process_module, :process_class
|
66
|
+
|
67
|
+
def process_defn(exp)
|
68
|
+
first_line_of_method = exp.line
|
69
|
+
name = exp.shift
|
70
|
+
@klasses[current_class].push name.to_s if within_target?(first_line_of_method..exp.last.line)
|
71
|
+
process(exp.shift) until exp.empty?
|
72
|
+
s()
|
73
|
+
end
|
74
|
+
|
75
|
+
def within_class(class_name, line_range, &block)
|
76
|
+
@current_class.push class_name
|
77
|
+
methods_before_process = @klasses[current_class].count
|
78
|
+
block.call
|
79
|
+
if (methods_before_process == @klasses[current_class].count) && within_target?(line_range)
|
80
|
+
@klasses[current_class].push nil
|
81
|
+
end
|
82
|
+
@current_class.shift
|
83
|
+
end
|
84
|
+
|
85
|
+
def within_target?(range)
|
86
|
+
@line_range.any? {|num| range.cover? num}
|
87
|
+
end
|
88
|
+
|
89
|
+
def current_class
|
90
|
+
@current_class.join('::')
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_class_name(exp, namespace=[])
|
94
|
+
if exp.is_a?(Sexp) && exp.first.is_a?(Sexp)
|
95
|
+
get_class_name(exp.first, namespace + [exp.last])
|
96
|
+
elsif exp.is_a?(Sexp) && exp[1].is_a?(Sexp)
|
97
|
+
get_class_name(exp[1], namespace + [exp.last])
|
98
|
+
else
|
99
|
+
([Array(exp).last] + namespace.reverse).join('::')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# Copyright (c) 2013, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
module Bugwatch
|
32
|
+
|
33
|
+
class Repo
|
34
|
+
|
35
|
+
REPO_PATH = 'repos'
|
36
|
+
|
37
|
+
attr_reader :name, :url
|
38
|
+
|
39
|
+
def self.discover(name, url)
|
40
|
+
new(name, url).tap {|repo| repo.discover! }
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(name, url)
|
44
|
+
@name = name
|
45
|
+
@url = url
|
46
|
+
end
|
47
|
+
|
48
|
+
def discover!
|
49
|
+
if exists?
|
50
|
+
update!
|
51
|
+
else
|
52
|
+
clone!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def clone!
|
57
|
+
Kernel.system("cd #{REPO_PATH}; git clone #{url} #{name}")
|
58
|
+
end
|
59
|
+
|
60
|
+
def update!
|
61
|
+
Kernel.system("cd #{path_to_repo}; git fetch origin master; git reset --hard origin/master; git fetch --tags")
|
62
|
+
end
|
63
|
+
|
64
|
+
def exists?
|
65
|
+
File.exists?(path_to_repo)
|
66
|
+
end
|
67
|
+
|
68
|
+
def analyze!(caching_strategy, analyzers, begin_sha=nil)
|
69
|
+
import(caching_strategy, begin_sha)
|
70
|
+
analyze(caching_strategy, *analyzers)
|
71
|
+
end
|
72
|
+
|
73
|
+
def import(caching_strategy, begin_sha=nil)
|
74
|
+
Import.new(self, caching_strategy).import(sha_or_head(begin_sha))
|
75
|
+
end
|
76
|
+
|
77
|
+
def analyze(caching_strategy, *analyzers)
|
78
|
+
Analysis.new(self, caching_strategy).analyze(*analyzers)
|
79
|
+
end
|
80
|
+
|
81
|
+
def head
|
82
|
+
rugged_repo.head.target
|
83
|
+
end
|
84
|
+
|
85
|
+
def commits(begin_sha=nil)
|
86
|
+
rugged_repo.walk(sha_or_head(begin_sha)).map do |rugged_commit|
|
87
|
+
self.commit(rugged_commit.oid)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def commit(sha)
|
92
|
+
grit_commit = grit.commit(sha)
|
93
|
+
Commit.from_grit(grit_commit) if grit_commit
|
94
|
+
end
|
95
|
+
|
96
|
+
def commit_shas(begin_sha=nil)
|
97
|
+
rugged_repo.walk(sha_or_head(begin_sha)).map(&:oid)
|
98
|
+
end
|
99
|
+
|
100
|
+
def tree
|
101
|
+
Tree.new(grit.tree)
|
102
|
+
end
|
103
|
+
|
104
|
+
def grit
|
105
|
+
@grit ||= Grit::Repo.new(path_to_repo)
|
106
|
+
end
|
107
|
+
|
108
|
+
def tags
|
109
|
+
grit_tags.map do |tag|
|
110
|
+
Tag.new(tag)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def sha_or_head(sha)
|
117
|
+
sha || head
|
118
|
+
end
|
119
|
+
|
120
|
+
def grit_tags
|
121
|
+
@grit_tags ||= grit.tags
|
122
|
+
end
|
123
|
+
|
124
|
+
def path_to_repo
|
125
|
+
"#{REPO_PATH}/#{name}"
|
126
|
+
end
|
127
|
+
|
128
|
+
def rugged_repo
|
129
|
+
@rugged_repo ||= Rugged::Repository.new(path_to_repo)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Copyright (c) 2013, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
module Bugwatch
|
32
|
+
|
33
|
+
class RubyComplexity
|
34
|
+
|
35
|
+
include RubyFileAdapter
|
36
|
+
|
37
|
+
def initialize(diffs)
|
38
|
+
@diffs = diffs
|
39
|
+
end
|
40
|
+
|
41
|
+
def score
|
42
|
+
ruby_flog.total_score
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_score
|
46
|
+
test_flog.total_score
|
47
|
+
end
|
48
|
+
|
49
|
+
def scores
|
50
|
+
complexity_scores(ruby_flog.scores)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_scores
|
54
|
+
complexity_scores(test_flog.scores)
|
55
|
+
end
|
56
|
+
|
57
|
+
def cyclomatic
|
58
|
+
[]
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def ruby_flog
|
64
|
+
FlogScore.new(ruby_diffs)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_flog
|
68
|
+
FlogScore.new(test_diffs)
|
69
|
+
end
|
70
|
+
|
71
|
+
def ruby_diffs
|
72
|
+
@diffs.select {|diff| analyzable_file? diff.path }
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_diffs
|
76
|
+
@diffs.select {|diff| test_file? diff.path }
|
77
|
+
end
|
78
|
+
|
79
|
+
def complexity_scores(scores)
|
80
|
+
scores.map {|(file, before_score, after_score)| ComplexityScore.new(file, before_score, after_score) }
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/lib/bugwatch/tag.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright (c) 2013, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
module Bugwatch
|
32
|
+
|
33
|
+
class Tag
|
34
|
+
|
35
|
+
attr_reader :grit
|
36
|
+
|
37
|
+
def initialize(grit_tag)
|
38
|
+
@grit = grit_tag
|
39
|
+
end
|
40
|
+
|
41
|
+
def name
|
42
|
+
grit.name
|
43
|
+
end
|
44
|
+
|
45
|
+
def committed_date
|
46
|
+
grit.commit.committed_date
|
47
|
+
end
|
48
|
+
|
49
|
+
def authored_date
|
50
|
+
grit.commit.authored_date
|
51
|
+
end
|
52
|
+
|
53
|
+
def tag_date
|
54
|
+
grit.tag_date
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Copyright (c) 2013, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
module Bugwatch
|
32
|
+
|
33
|
+
class Tree
|
34
|
+
|
35
|
+
Content = Struct.new(:file, :size)
|
36
|
+
|
37
|
+
def initialize(grit=nil)
|
38
|
+
@grit = grit
|
39
|
+
end
|
40
|
+
|
41
|
+
def /(filepath)
|
42
|
+
@grit / filepath if @grit
|
43
|
+
end
|
44
|
+
|
45
|
+
def ruby_files
|
46
|
+
@files ||= get_ruby_files(@grit.contents)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def get_ruby_files(tree_contents)
|
52
|
+
tree_contents.reduce([]) do |count, type|
|
53
|
+
if type.is_a?(Grit::Blob) && RubyFileAdapter.ruby_file?(type.name)
|
54
|
+
count + [Content.new(type.name, type.size)]
|
55
|
+
elsif type.is_a?(Grit::Tree)
|
56
|
+
count + get_ruby_files(type.contents)
|
57
|
+
else
|
58
|
+
count
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|