repokeeper 0.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.
- checksums.yaml +7 -0
- data/GPLv3 +674 -0
- data/LICENSE +14 -0
- data/README.md +184 -0
- data/bin/repokeeper +7 -0
- data/config/default.yml +13 -0
- data/lib/repokeeper/analyzers/analyzer.rb +26 -0
- data/lib/repokeeper/analyzers/analyzers_set.rb +11 -0
- data/lib/repokeeper/analyzers/branches/local_branches_count.rb +20 -0
- data/lib/repokeeper/analyzers/branches/remote_branches_count.rb +20 -0
- data/lib/repokeeper/analyzers/commits/merge_commits.rb +11 -0
- data/lib/repokeeper/analyzers/commits/short_commit_message.rb +26 -0
- data/lib/repokeeper/analyzers/commits/similar_commits.rb +44 -0
- data/lib/repokeeper/analyzers/mixins/branches_analyzer.rb +13 -0
- data/lib/repokeeper/analyzers/mixins/branches_count.rb +22 -0
- data/lib/repokeeper/analyzers/mixins/commits_analyzer.rb +19 -0
- data/lib/repokeeper/analyzers.rb +10 -0
- data/lib/repokeeper/cli.rb +62 -0
- data/lib/repokeeper/config.rb +43 -0
- data/lib/repokeeper/offenses/branches_offense.rb +8 -0
- data/lib/repokeeper/offenses/commit_offense.rb +8 -0
- data/lib/repokeeper/repo_analyzer.rb +68 -0
- data/lib/repokeeper/repo_proxy.rb +58 -0
- data/lib/repokeeper/rev_parser.rb +22 -0
- data/lib/repokeeper/simple_text_formatter.rb +64 -0
- data/lib/repokeeper/utils.rb +10 -0
- data/lib/repokeeper/version.rb +3 -0
- data/lib/repokeeper.rb +11 -0
- metadata +130 -0
data/LICENSE
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright (c) 2014 Anatoliy Plastinin
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/README.md
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
# Repokeeper
|
2
|
+
|
3
|
+
## What's all this about?
|
4
|
+
|
5
|
+
Repokeeper is a tool for git repositories analysis that highlights common
|
6
|
+
flaws/bad practices in a workflow.
|
7
|
+
|
8
|
+
## Flaws in workflow? What does it mean?
|
9
|
+
|
10
|
+
Flaws commonly seen in repository management.
|
11
|
+
|
12
|
+
## Why do I need a tool for this?
|
13
|
+
|
14
|
+
There are many tools for static code analysis like rubocop, flay, flog,
|
15
|
+
codeclimate and etc.
|
16
|
+
Why not analyze repositories?
|
17
|
+
Unlike code, which can be refactored to fix issues, it's not possible to
|
18
|
+
refactor repo history (of course, you can rewrite git history, but rewriting
|
19
|
+
commits merged into master branch is a bad idea).
|
20
|
+
By using Repokeeper, you can explore what was wrong in project's history, and
|
21
|
+
then adjust your process accordingly.
|
22
|
+
|
23
|
+
|
24
|
+
Problems with project management usually leave traces in repository history and
|
25
|
+
structure.
|
26
|
+
For instance, a rush in delivery of features to production can lead to debugging
|
27
|
+
and fixing in production, which in turn, leads to many `fix`-like commits.
|
28
|
+
|
29
|
+
## Story behind this project
|
30
|
+
|
31
|
+
Once upon a time... while reviewing a pull request, the author found two commits
|
32
|
+
saying:
|
33
|
+
|
34
|
+
Implementing uploader
|
35
|
+
Implementing uploader
|
36
|
+
|
37
|
+
His immediate thoughts were: "WTF??? What is it? Did the first attempt fail to
|
38
|
+
work?"
|
39
|
+
But then, he decided to write a tool to analyze other repos to see if this was a
|
40
|
+
unique case, or if he had stumbled upon a more common problem.
|
41
|
+
|
42
|
+
## What can this tool tell me about my repo?
|
43
|
+
|
44
|
+
Tool detects following problems:
|
45
|
+
|
46
|
+
* **Short commit message.**
|
47
|
+
The most important thing one can do using any VCS is to write meaningful commit
|
48
|
+
message, because it will help others to better understand your changes.
|
49
|
+
If you find commit messages like: `fix` or `!!!`, that means someone doesn't do
|
50
|
+
a good job in revealing the intention behind these commits.
|
51
|
+
|
52
|
+
* **Duplicate commit message.**
|
53
|
+
A sequence of two or more sequential commits with the same message might
|
54
|
+
indicate that someone didn't find time to squash those commits or that someone
|
55
|
+
pushed a fix to master (or even deployed it to production) and it didn't work.
|
56
|
+
|
57
|
+
* **Merge commit.**
|
58
|
+
This is a commit with 2 parents. It's hard to follow project history if it
|
59
|
+
includes tons of merges.
|
60
|
+
This analysis might be useful in case you follow rebase and fast-forward only
|
61
|
+
merges workflow. Read more about rebase
|
62
|
+
[here](http://randyfay.com/content/rebase-workflow-git)
|
63
|
+
or [here](http://robots.thoughtbot.com/rebase-like-a-boss).
|
64
|
+
|
65
|
+
* **Issues with branches**.
|
66
|
+
Branches analyzers are experimental, and there are will be changes in future.
|
67
|
+
At this moment, the tool reports a warning if you have too many local or remote
|
68
|
+
branches.
|
69
|
+
Too many branches can indicate that you aren’t maintaining your repository well
|
70
|
+
(i.e., you aren’t deleting local and remote feature branches after merging it).
|
71
|
+
|
72
|
+
## OK, I want to try it
|
73
|
+
|
74
|
+
Install it from ruby gems
|
75
|
+
|
76
|
+
$ gem install repokeeper
|
77
|
+
|
78
|
+
After that
|
79
|
+
|
80
|
+
* Goto some repo's directory
|
81
|
+
* Run `repokeeper`
|
82
|
+
* Have fun
|
83
|
+
|
84
|
+
Also you can pass a path to repository, instead switching to the directory with
|
85
|
+
the repository: `repokeeper super_cool_project`
|
86
|
+
|
87
|
+
You can override default analyzers settings providing a config file with `-c`
|
88
|
+
option, e.g. `repokeeper -c .repokeeper.yml`
|
89
|
+
|
90
|
+
See `config/default.yml` for configuration file example.
|
91
|
+
|
92
|
+
**NOTE:** `repokeeper` without `-c` argument doesn't load `.repokeeper.yml`
|
93
|
+
from current directory even if it exists.
|
94
|
+
|
95
|
+
## I have a big project, and use non-fastforward merges all the time
|
96
|
+
|
97
|
+
If you are annoyed by tons of merge commits warnings, you can disable it,
|
98
|
+
by `enabled: false` option in config file.
|
99
|
+
|
100
|
+
## More fun with custom formatters
|
101
|
+
|
102
|
+
You can provide custom formatter class to change output the way you want,
|
103
|
+
or calculate statistics.
|
104
|
+
|
105
|
+
To do this you should require ruby file with formatter class using `--require`
|
106
|
+
option and provide formatter class name using `--formatter` option.
|
107
|
+
|
108
|
+
### Complex example on how to use custom formatters
|
109
|
+
|
110
|
+
Let's create a list of most common short commit messages in a repository.
|
111
|
+
|
112
|
+
```{ruby}
|
113
|
+
# messages_score_formatter.rb
|
114
|
+
class MessagesScoreFormatter
|
115
|
+
def initialize(out_stream = $stdout)
|
116
|
+
@out_stream = out_stream
|
117
|
+
end
|
118
|
+
|
119
|
+
def started
|
120
|
+
@counts = Hash.new(0)
|
121
|
+
end
|
122
|
+
|
123
|
+
def commits_analyzer_results(analyzer_name, offenses)
|
124
|
+
Array(offenses).each do |offense|
|
125
|
+
messsage = offense.commit.message.strip.downcase
|
126
|
+
@counts[messsage] += 1
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def branches_analyzer_results(analyzer_name, offenses)
|
131
|
+
end
|
132
|
+
|
133
|
+
def finished
|
134
|
+
@counts.sort_by{ |_, v| -v }.each do |k, v|
|
135
|
+
@out_stream.puts "#{k}: #{v}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
We are interested to use only short commit messages analyzer, so other analyzers
|
142
|
+
can be disabled in configuration file:
|
143
|
+
|
144
|
+
```{yaml}
|
145
|
+
# .repokeeper.yml
|
146
|
+
local_branches_count:
|
147
|
+
enabled: false
|
148
|
+
|
149
|
+
remote_branches_count:
|
150
|
+
enabled: false
|
151
|
+
|
152
|
+
merge_commits:
|
153
|
+
enabled: false
|
154
|
+
|
155
|
+
short_commit_message:
|
156
|
+
message_min_length: 10
|
157
|
+
|
158
|
+
similar_commits:
|
159
|
+
enabled: false
|
160
|
+
```
|
161
|
+
|
162
|
+
And everything is ready to run:
|
163
|
+
|
164
|
+
repokeeper --require ./messages_score_formatter.rb \
|
165
|
+
--formatter MessagesScoreFormatter \
|
166
|
+
-c .repokeeper.yml super_cool_project
|
167
|
+
|
168
|
+
## Contributing
|
169
|
+
|
170
|
+
You know what to do.
|
171
|
+
But don't forget to run `repokeeper` against your new commits ;)
|
172
|
+
|
173
|
+
|
174
|
+
## Contact
|
175
|
+
|
176
|
+
Anatoliy Plastinin
|
177
|
+
|
178
|
+
- http://github.com/antlypls
|
179
|
+
- http://twitter.com/antlypls
|
180
|
+
- hello@antlypls.com
|
181
|
+
|
182
|
+
## License
|
183
|
+
|
184
|
+
See `LICENSE`
|
data/bin/repokeeper
ADDED
data/config/default.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
# Base class for sequential commits analyzers
|
3
|
+
class Analyzer
|
4
|
+
@all = AnalyzersSet.new
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
@all.clone
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.inherited(subclass)
|
11
|
+
@all << subclass
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(config)
|
15
|
+
@config = config || {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def name
|
19
|
+
self.class.name.split('::').last
|
20
|
+
end
|
21
|
+
|
22
|
+
def enabled?
|
23
|
+
@config.fetch('enabled') { true }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
class LocalBranchesCount < Analyzer
|
3
|
+
include BranchesAnalyzer
|
4
|
+
include BranchesCount
|
5
|
+
|
6
|
+
def max_branches
|
7
|
+
@config['max_local_branches']
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def get_branches(repo)
|
13
|
+
repo.local_branches
|
14
|
+
end
|
15
|
+
|
16
|
+
def message
|
17
|
+
'too many local branches'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
class RemoteBranchesCount < Analyzer
|
3
|
+
include BranchesAnalyzer
|
4
|
+
include BranchesCount
|
5
|
+
|
6
|
+
def max_branches
|
7
|
+
@config['max_remote_branches']
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def get_branches(repo)
|
13
|
+
repo.remote_branches
|
14
|
+
end
|
15
|
+
|
16
|
+
def message
|
17
|
+
'too many remote branches'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
# Analyzes merge commits
|
3
|
+
# commits level analyzer
|
4
|
+
class MergeCommits < Analyzer
|
5
|
+
include CommitsAnalyzer
|
6
|
+
|
7
|
+
def process_commit(commit)
|
8
|
+
create_offense(commit, 'merge commit') if commit.parents.count > 1
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
# Analyzes short commit messages
|
3
|
+
# sign of undescriptive message
|
4
|
+
# commits level analyzer
|
5
|
+
class ShortCommitMessage < Analyzer
|
6
|
+
include CommitsAnalyzer
|
7
|
+
|
8
|
+
def message_min_length
|
9
|
+
@config['message_min_length']
|
10
|
+
end
|
11
|
+
|
12
|
+
def process_commit(commit)
|
13
|
+
create_offense_message(commit) if error?(commit)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def error?(commit)
|
19
|
+
commit.message.length < message_min_length
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_offense_message(commit)
|
23
|
+
create_offense(commit, "Short commit message: #{commit.message}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
# Checks for similar commits messages in commit ant its parents
|
3
|
+
# commits level analyzer
|
4
|
+
class SimilarCommits < Analyzer
|
5
|
+
include CommitsAnalyzer
|
6
|
+
|
7
|
+
def min_edit_distance
|
8
|
+
@config['min_edit_distance']
|
9
|
+
end
|
10
|
+
|
11
|
+
def process_commit(commit)
|
12
|
+
commit.parents.map do |parent|
|
13
|
+
compare_commits(commit, parent)
|
14
|
+
end.compact
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def compare_commits(newer, older)
|
20
|
+
new_message = clean_commit_message(newer)
|
21
|
+
old_message = clean_commit_message(older)
|
22
|
+
|
23
|
+
distance = Repokeeper::Utils.edit_distance(new_message, old_message)
|
24
|
+
error = error_message_by_distance(distance, new_message, old_message)
|
25
|
+
create_offense_for_error(error, newer, older)
|
26
|
+
end
|
27
|
+
|
28
|
+
def error_message_by_distance(distance, new_message, old_message)
|
29
|
+
if distance == 0
|
30
|
+
"Same commit message: '#{new_message}'"
|
31
|
+
elsif distance < min_edit_distance
|
32
|
+
"Similar commit messages: '#{new_message}' and '#{old_message}'"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_offense_for_error(error, newer, older)
|
37
|
+
create_offense(newer, "#{error}. See #{older.oid}") if error
|
38
|
+
end
|
39
|
+
|
40
|
+
def clean_commit_message(commit)
|
41
|
+
commit.message.gsub(/[\t\n]/, ' ').strip
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
module BranchesCount
|
3
|
+
def analyze(repo)
|
4
|
+
branches = get_branches(repo)
|
5
|
+
report(branches) if error?(branches)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def error?(branches)
|
11
|
+
branches.count > max_branches
|
12
|
+
end
|
13
|
+
|
14
|
+
def report(branches)
|
15
|
+
create_offense(branches)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_offense(branches)
|
19
|
+
Repokeeper::Offenses::BranchesOffense.new(branches, message, name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Repokeeper::Analyzers
|
2
|
+
module CommitsAnalyzer
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def type
|
9
|
+
:commit
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def create_offense(commit, message)
|
16
|
+
Repokeeper::Offenses::CommitOffense.new(commit, message, name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require_relative 'analyzers/mixins/branches_analyzer'
|
2
|
+
require_relative 'analyzers/mixins/branches_count'
|
3
|
+
require_relative 'analyzers/mixins/commits_analyzer'
|
4
|
+
require_relative 'analyzers/analyzers_set'
|
5
|
+
require_relative 'analyzers/analyzer'
|
6
|
+
require_relative 'analyzers/commits/merge_commits'
|
7
|
+
require_relative 'analyzers/commits/short_commit_message'
|
8
|
+
require_relative 'analyzers/commits/similar_commits'
|
9
|
+
require_relative 'analyzers/branches/local_branches_count'
|
10
|
+
require_relative 'analyzers/branches/remote_branches_count'
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'methadone'
|
2
|
+
|
3
|
+
module Repokeeper
|
4
|
+
class CLI
|
5
|
+
include Methadone::Main
|
6
|
+
include Methadone::CLILogging
|
7
|
+
|
8
|
+
version VERSION, compact: true
|
9
|
+
description 'Repokeeper checks your repo for flaws'
|
10
|
+
|
11
|
+
arg :path, :optional,
|
12
|
+
'path to repo to analyze, current dir if not specified'
|
13
|
+
|
14
|
+
on '-r REV_RANGE', '--rev-range',
|
15
|
+
'Revisions to analyze by commits analyzers'
|
16
|
+
|
17
|
+
on '-c CONFIG_FILE', '--config',
|
18
|
+
'Configuration file'
|
19
|
+
|
20
|
+
on '--require REQUIRE_FILE',
|
21
|
+
'File to require'
|
22
|
+
|
23
|
+
on '--formatter FORMATTER_CLASS',
|
24
|
+
'Formatter class'
|
25
|
+
|
26
|
+
main do |path|
|
27
|
+
file_to_require = options['require']
|
28
|
+
require file_to_require if file_to_require
|
29
|
+
|
30
|
+
formatter_class = formatter_class_by_name(options['formatter'])
|
31
|
+
|
32
|
+
config_file = options['config']
|
33
|
+
repo_analyzer = create_analyzer(path, config_file, formatter_class)
|
34
|
+
range = rev_range(options['rev-range'])
|
35
|
+
repo_analyzer.analyze(range)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.formatter_class_by_name(name)
|
39
|
+
if name && !name.empty?
|
40
|
+
const_get(name)
|
41
|
+
else
|
42
|
+
SimpleTextFormatter
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.create_analyzer(path, config_file, formatter_class)
|
47
|
+
formatter = formatter_class.new
|
48
|
+
|
49
|
+
analyzers = Analyzers::Analyzer.all
|
50
|
+
|
51
|
+
proxy = RepoProxy.new(path)
|
52
|
+
config = Config.read(config_file)
|
53
|
+
RepoAnalyzer.new(proxy, formatter, analyzers, config)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.rev_range(rev_spec)
|
57
|
+
parser = RevParser.new(rev_spec)
|
58
|
+
parser.parse
|
59
|
+
parser.range
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Repokeeper
|
2
|
+
class Config
|
3
|
+
HOME_DIR = File.expand_path('../../../', __FILE__)
|
4
|
+
CONFIG_DIR = File.join(HOME_DIR, 'config')
|
5
|
+
DEFAULT_CONFIG = File.join(CONFIG_DIR, 'default.yml')
|
6
|
+
|
7
|
+
def initialize(hash)
|
8
|
+
@config = hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def for(klass)
|
12
|
+
key = klass.name.split('::').last
|
13
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
14
|
+
@config[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.read(file_path = nil)
|
18
|
+
config_file = read_configuration_file(file_path)
|
19
|
+
config = merge_hashes(default_configuration, config_file)
|
20
|
+
new(config)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.default_configuration
|
24
|
+
read_configuration_file(DEFAULT_CONFIG)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.read_configuration_file(file_path)
|
28
|
+
return {} unless file_path
|
29
|
+
YAML.load_file(file_path)
|
30
|
+
end
|
31
|
+
private_class_method :read_configuration_file
|
32
|
+
|
33
|
+
def self.merge_hashes(hash1, hash2)
|
34
|
+
hash1.merge(hash2) do |_, oldval, newval|
|
35
|
+
old_hash = Hash(oldval)
|
36
|
+
new_hash = Hash(newval)
|
37
|
+
|
38
|
+
old_hash.merge(new_hash)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
private_class_method :read_configuration_file
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Repokeeper
|
2
|
+
# provides infrastructure for running commits analyzers
|
3
|
+
class RepoAnalyzer
|
4
|
+
def initialize(repo_proxy, formatter, analyzers, config)
|
5
|
+
@analyzers = analyzers
|
6
|
+
@formatter = formatter
|
7
|
+
@repo = repo_proxy
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def analyze(rev_range = nil)
|
12
|
+
@rev_range = rev_range
|
13
|
+
|
14
|
+
@formatter.started
|
15
|
+
run_commits_analyzers
|
16
|
+
run_branches_analyzers
|
17
|
+
@formatter.finished
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def commits_analyzers
|
23
|
+
@analyzers.commits_analyzers
|
24
|
+
end
|
25
|
+
|
26
|
+
def branch_analyzers
|
27
|
+
@analyzers.branch_analyzers
|
28
|
+
end
|
29
|
+
|
30
|
+
def enabled_analyzers(collection)
|
31
|
+
collection
|
32
|
+
.map { |analyzer_class| instantiate_analyzer(analyzer_class) }
|
33
|
+
.select { |analyzer| analyzer.enabled? }
|
34
|
+
end
|
35
|
+
|
36
|
+
def enabled_commits_analyzers
|
37
|
+
@enabled_commits_analyzers ||= enabled_analyzers(commits_analyzers)
|
38
|
+
end
|
39
|
+
|
40
|
+
def enabled_branches_analyzers
|
41
|
+
@enabled_branches_analyzers ||= enabled_analyzers(branch_analyzers)
|
42
|
+
end
|
43
|
+
|
44
|
+
def run_commits_analyzers
|
45
|
+
commits.each do |commit|
|
46
|
+
enabled_commits_analyzers.each do |analyzer|
|
47
|
+
result = analyzer.process_commit(commit)
|
48
|
+
@formatter.commits_analyzer_results(analyzer.name, result)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def run_branches_analyzers
|
54
|
+
enabled_branches_analyzers.each do |analyzer|
|
55
|
+
result = analyzer.analyze(@repo)
|
56
|
+
@formatter.branches_analyzer_results(analyzer.name, result)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def instantiate_analyzer(analyzer_class)
|
61
|
+
analyzer_class.new(@config.for(analyzer_class))
|
62
|
+
end
|
63
|
+
|
64
|
+
def commits
|
65
|
+
@commits ||= @repo.commits(@rev_range)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|