repokeeper 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|