rubycritic-simplecov 4.1.0
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/CHANGELOG.md +290 -0
- data/CONTRIBUTING.md +93 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +259 -0
- data/ROADMAP.md +56 -0
- data/Rakefile +28 -0
- data/bin/rubycritic +10 -0
- data/lib/rubycritic/analysers/attributes.rb +29 -0
- data/lib/rubycritic/analysers/churn.rb +30 -0
- data/lib/rubycritic/analysers/complexity.rb +30 -0
- data/lib/rubycritic/analysers/coverage.rb +118 -0
- data/lib/rubycritic/analysers/helpers/ast_node.rb +76 -0
- data/lib/rubycritic/analysers/helpers/flay.rb +13 -0
- data/lib/rubycritic/analysers/helpers/flog.rb +17 -0
- data/lib/rubycritic/analysers/helpers/methods_counter.rb +25 -0
- data/lib/rubycritic/analysers/helpers/modules_locator.rb +42 -0
- data/lib/rubycritic/analysers/helpers/parser.rb +14 -0
- data/lib/rubycritic/analysers/helpers/reek.rb +11 -0
- data/lib/rubycritic/analysers/smells/flay.rb +79 -0
- data/lib/rubycritic/analysers/smells/flog.rb +69 -0
- data/lib/rubycritic/analysers/smells/reek.rb +53 -0
- data/lib/rubycritic/analysers_runner.rb +41 -0
- data/lib/rubycritic/analysis_summary.rb +40 -0
- data/lib/rubycritic/browser.rb +19 -0
- data/lib/rubycritic/cli/application.rb +34 -0
- data/lib/rubycritic/cli/options/argv.rb +137 -0
- data/lib/rubycritic/cli/options/file.rb +100 -0
- data/lib/rubycritic/cli/options.rb +33 -0
- data/lib/rubycritic/colorize.rb +17 -0
- data/lib/rubycritic/command_factory.rb +25 -0
- data/lib/rubycritic/commands/base.rb +18 -0
- data/lib/rubycritic/commands/ci.rb +14 -0
- data/lib/rubycritic/commands/compare.rb +106 -0
- data/lib/rubycritic/commands/default.rb +38 -0
- data/lib/rubycritic/commands/help.rb +18 -0
- data/lib/rubycritic/commands/status_reporter.rb +45 -0
- data/lib/rubycritic/commands/utils/build_number_file.rb +37 -0
- data/lib/rubycritic/commands/version.rb +16 -0
- data/lib/rubycritic/configuration.rb +69 -0
- data/lib/rubycritic/core/analysed_module.rb +93 -0
- data/lib/rubycritic/core/analysed_modules_collection.rb +95 -0
- data/lib/rubycritic/core/location.rb +47 -0
- data/lib/rubycritic/core/rating.rb +30 -0
- data/lib/rubycritic/core/smell.rb +84 -0
- data/lib/rubycritic/generators/console_report.rb +20 -0
- data/lib/rubycritic/generators/html/assets/fonts/FontAwesome.otf +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/Roboto-Medium.ttf +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/Roboto-Regular.ttf +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/fontawesome-webfont.eot +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/fontawesome-webfont.svg +2671 -0
- data/lib/rubycritic/generators/html/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/fontawesome-webfont.woff +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/fontawesome-webfont.woff2 +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/glyphicons-halflings-regular.svg +288 -0
- data/lib/rubycritic/generators/html/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/rubycritic/generators/html/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/lib/rubycritic/generators/html/assets/images/logo.png +0 -0
- data/lib/rubycritic/generators/html/assets/javascripts/application.js +281 -0
- data/lib/rubycritic/generators/html/assets/javascripts/bootstrap.min.js +7 -0
- data/lib/rubycritic/generators/html/assets/javascripts/highcharts.src-4.0.1.js +17672 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.filtertable.min.js +13 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.min.js +4 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.scrollTo.min.js +7 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.tablesorter.js +1031 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.tablesorter.min.js +4 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.timeago.js +231 -0
- data/lib/rubycritic/generators/html/assets/javascripts/prettify.js +46 -0
- data/lib/rubycritic/generators/html/assets/stylesheets/application.css +570 -0
- data/lib/rubycritic/generators/html/assets/stylesheets/bootstrap.min.css +6 -0
- data/lib/rubycritic/generators/html/assets/stylesheets/font-awesome.min.css +4 -0
- data/lib/rubycritic/generators/html/assets/stylesheets/prettify.css +1 -0
- data/lib/rubycritic/generators/html/assets/stylesheets/prettify.custom_theme.css +69 -0
- data/lib/rubycritic/generators/html/base.rb +54 -0
- data/lib/rubycritic/generators/html/code_file.rb +51 -0
- data/lib/rubycritic/generators/html/code_index.rb +33 -0
- data/lib/rubycritic/generators/html/line.rb +37 -0
- data/lib/rubycritic/generators/html/overview.rb +38 -0
- data/lib/rubycritic/generators/html/simple_cov_index.rb +44 -0
- data/lib/rubycritic/generators/html/smells_index.rb +45 -0
- data/lib/rubycritic/generators/html/templates/code_file.html.erb +61 -0
- data/lib/rubycritic/generators/html/templates/code_index.html.erb +55 -0
- data/lib/rubycritic/generators/html/templates/layouts/application.html.erb +66 -0
- data/lib/rubycritic/generators/html/templates/line.html.erb +1 -0
- data/lib/rubycritic/generators/html/templates/overview.html.erb +68 -0
- data/lib/rubycritic/generators/html/templates/simple_cov_index.html.erb +44 -0
- data/lib/rubycritic/generators/html/templates/smells_index.html.erb +47 -0
- data/lib/rubycritic/generators/html/templates/smelly_line.html.erb +23 -0
- data/lib/rubycritic/generators/html/turbulence.rb +17 -0
- data/lib/rubycritic/generators/html/view_helpers.rb +58 -0
- data/lib/rubycritic/generators/html_report.rb +77 -0
- data/lib/rubycritic/generators/json/simple.rb +43 -0
- data/lib/rubycritic/generators/json_report.rb +26 -0
- data/lib/rubycritic/generators/lint_report.rb +30 -0
- data/lib/rubycritic/generators/text/lint.rb +41 -0
- data/lib/rubycritic/generators/text/list.rb +45 -0
- data/lib/rubycritic/generators/text/templates/lint.erb +3 -0
- data/lib/rubycritic/generators/text/templates/list.erb +12 -0
- data/lib/rubycritic/rake_task.rb +71 -0
- data/lib/rubycritic/reporter.rb +39 -0
- data/lib/rubycritic/revision_comparator.rb +45 -0
- data/lib/rubycritic/serializer.rb +32 -0
- data/lib/rubycritic/smells_status_setter.rb +18 -0
- data/lib/rubycritic/source_control_systems/base.rb +41 -0
- data/lib/rubycritic/source_control_systems/double.rb +19 -0
- data/lib/rubycritic/source_control_systems/git.rb +95 -0
- data/lib/rubycritic/source_control_systems/mercurial.rb +29 -0
- data/lib/rubycritic/source_control_systems/perforce.rb +116 -0
- data/lib/rubycritic/source_locator.rb +52 -0
- data/lib/rubycritic/version.rb +5 -0
- data/lib/rubycritic.rb +6 -0
- metadata +528 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'rubycritic/configuration'
|
|
5
|
+
require 'rubycritic/generators/html/overview'
|
|
6
|
+
require 'rubycritic/generators/html/smells_index'
|
|
7
|
+
require 'rubycritic/generators/html/code_index'
|
|
8
|
+
require 'rubycritic/generators/html/simple_cov_index'
|
|
9
|
+
require 'rubycritic/generators/html/code_file'
|
|
10
|
+
|
|
11
|
+
module RubyCritic
|
|
12
|
+
module Generator
|
|
13
|
+
class HtmlReport
|
|
14
|
+
ASSETS_DIR = File.expand_path('html/assets', __dir__)
|
|
15
|
+
|
|
16
|
+
def initialize(analysed_modules)
|
|
17
|
+
@analysed_modules = analysed_modules
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def generate_report
|
|
21
|
+
create_directories_and_files
|
|
22
|
+
copy_assets_to_report_directory
|
|
23
|
+
puts "New critique at #{report_location}"
|
|
24
|
+
browser.open unless Config.no_browser
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def browser
|
|
28
|
+
@browser ||= RubyCritic::Browser.new(report_location)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def create_directories_and_files
|
|
34
|
+
Array(generators).each do |generator|
|
|
35
|
+
FileUtils.mkdir_p(generator.file_directory)
|
|
36
|
+
File.open(generator.file_pathname, 'w+') do |file|
|
|
37
|
+
file.write(generator.render)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def generators
|
|
43
|
+
[overview_generator, code_index_generator, smells_index_generator, simple_cov_index_generator] + file_generators
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def overview_generator
|
|
47
|
+
@overview_generator ||= Html::Overview.new(@analysed_modules)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def code_index_generator
|
|
51
|
+
Html::CodeIndex.new(@analysed_modules)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def smells_index_generator
|
|
55
|
+
Html::SmellsIndex.new(@analysed_modules)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def simple_cov_index_generator
|
|
59
|
+
Html::SimpleCovIndex.new(@analysed_modules)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def file_generators
|
|
63
|
+
@analysed_modules.map do |analysed_module|
|
|
64
|
+
Html::CodeFile.new(analysed_module)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def copy_assets_to_report_directory
|
|
69
|
+
FileUtils.cp_r(ASSETS_DIR, Config.root)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def report_location
|
|
73
|
+
overview_generator.file_href
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'rubycritic/version'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
|
|
7
|
+
module RubyCritic
|
|
8
|
+
module Generator
|
|
9
|
+
module Json
|
|
10
|
+
class Simple
|
|
11
|
+
def initialize(analysed_modules)
|
|
12
|
+
@analysed_modules = analysed_modules
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
FILE_NAME = 'report.json'.freeze
|
|
16
|
+
|
|
17
|
+
def render
|
|
18
|
+
JSON.dump(data)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def data
|
|
22
|
+
{
|
|
23
|
+
metadata: {
|
|
24
|
+
rubycritic: {
|
|
25
|
+
version: RubyCritic::VERSION
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
analysed_modules: @analysed_modules,
|
|
29
|
+
score: @analysed_modules.score
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def file_directory
|
|
34
|
+
@file_directory ||= Pathname.new(Config.root)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def file_pathname
|
|
38
|
+
Pathname.new(file_directory).join FILE_NAME
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rubycritic/generators/json/simple'
|
|
4
|
+
|
|
5
|
+
module RubyCritic
|
|
6
|
+
module Generator
|
|
7
|
+
class JsonReport
|
|
8
|
+
def initialize(analysed_modules)
|
|
9
|
+
@analysed_modules = analysed_modules
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def generate_report
|
|
13
|
+
FileUtils.mkdir_p(generator.file_directory)
|
|
14
|
+
File.open(generator.file_pathname, 'w+') do |file|
|
|
15
|
+
file.write(generator.render)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def generator
|
|
22
|
+
Json::Simple.new(@analysed_modules)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rubycritic/generators/text/lint'
|
|
4
|
+
|
|
5
|
+
module RubyCritic
|
|
6
|
+
module Generator
|
|
7
|
+
class LintReport
|
|
8
|
+
def initialize(analysed_modules)
|
|
9
|
+
@analysed_modules = analysed_modules
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def generate_report
|
|
13
|
+
FileUtils.mkdir_p(generator.file_directory)
|
|
14
|
+
File.open(generator.file_pathname, 'w+') do |file|
|
|
15
|
+
file.write(reports.join("\n"))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def generator
|
|
20
|
+
Text::Lint
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def reports
|
|
24
|
+
@analysed_modules.sort.map do |mod|
|
|
25
|
+
generator.new(mod).render
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'erb'
|
|
4
|
+
module RubyCritic
|
|
5
|
+
module Generator
|
|
6
|
+
module Text
|
|
7
|
+
class Lint
|
|
8
|
+
class << self
|
|
9
|
+
TEMPLATE_PATH = File.expand_path('templates/lint.erb', __dir__)
|
|
10
|
+
FILE_NAME = 'lint.txt'.freeze
|
|
11
|
+
|
|
12
|
+
def file_directory
|
|
13
|
+
@file_directory ||= Pathname.new(Config.root)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def file_pathname
|
|
17
|
+
Pathname.new(file_directory).join FILE_NAME
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def erb_template
|
|
21
|
+
@erb_template ||= ERB.new(File.read(TEMPLATE_PATH), nil, '-')
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def initialize(analysed_module)
|
|
26
|
+
@analysed_module = analysed_module
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def render
|
|
30
|
+
erb_template.result(binding)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def erb_template
|
|
36
|
+
self.class.erb_template
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rainbow'
|
|
4
|
+
|
|
5
|
+
module RubyCritic
|
|
6
|
+
module Generator
|
|
7
|
+
module Text
|
|
8
|
+
class List
|
|
9
|
+
class << self
|
|
10
|
+
TEMPLATE_PATH = File.expand_path('templates/list.erb', __dir__)
|
|
11
|
+
|
|
12
|
+
def erb_template
|
|
13
|
+
@erb_template ||= ERB.new(File.read(TEMPLATE_PATH), nil, '-')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
RATING_TO_COLOR = {
|
|
18
|
+
'A' => :green,
|
|
19
|
+
'B' => :green,
|
|
20
|
+
'C' => :yellow,
|
|
21
|
+
'D' => :orange,
|
|
22
|
+
'F' => :red
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
def initialize(analysed_module)
|
|
26
|
+
@analysed_module = analysed_module
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def render
|
|
30
|
+
erb_template.result(binding)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def erb_template
|
|
36
|
+
self.class.erb_template
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def color
|
|
40
|
+
@color ||= RATING_TO_COLOR[@analysed_module.rating.to_s]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%= Rainbow(@analysed_module.name.to_s).foreground(color) %>:
|
|
2
|
+
Rating: <%= Rainbow(@analysed_module.rating.to_s).foreground(color) %>
|
|
3
|
+
Churn: <%= @analysed_module.churn %>
|
|
4
|
+
Complexity: <%= @analysed_module.complexity %>
|
|
5
|
+
Duplication: <%= @analysed_module.duplication %>
|
|
6
|
+
Smells: <%= @analysed_module.smells.count %>
|
|
7
|
+
<%- @analysed_module.smells.each do |smell| -%>
|
|
8
|
+
* <%= smell %>
|
|
9
|
+
<%- smell.locations.each do |location| -%>
|
|
10
|
+
- <%= location %>
|
|
11
|
+
<%- end -%>
|
|
12
|
+
<%- end -%>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rake'
|
|
4
|
+
require 'rake/tasklib'
|
|
5
|
+
require 'English'
|
|
6
|
+
require 'rubycritic/cli/application'
|
|
7
|
+
|
|
8
|
+
module RubyCritic
|
|
9
|
+
#
|
|
10
|
+
# A rake task that runs RubyCritic on a set of source files.
|
|
11
|
+
#
|
|
12
|
+
# This will create a task that can be run with:
|
|
13
|
+
#
|
|
14
|
+
# rake rubycritic
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
#
|
|
18
|
+
# require 'rubycritic/rake_task'
|
|
19
|
+
#
|
|
20
|
+
# RubyCritic::RakeTask.new do |task|
|
|
21
|
+
# task.paths = FileList['lib/**/*.rb', 'spec/**/*.rb']
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
class RakeTask < ::Rake::TaskLib
|
|
25
|
+
# Name of RubyCritic task. Defaults to :rubycritic.
|
|
26
|
+
attr_writer :name
|
|
27
|
+
|
|
28
|
+
# Glob pattern to match source files. Defaults to FileList['.'].
|
|
29
|
+
attr_writer :paths
|
|
30
|
+
|
|
31
|
+
# Use verbose output. If this is set to true, the task will print
|
|
32
|
+
# the rubycritic command to stdout. Defaults to false.
|
|
33
|
+
attr_writer :verbose
|
|
34
|
+
|
|
35
|
+
# You can pass all the options here in that are shown by "rubycritic -h" except for
|
|
36
|
+
# "-p / --path" since that is set separately. Defaults to ''.
|
|
37
|
+
attr_writer :options
|
|
38
|
+
|
|
39
|
+
def initialize(name = :rubycritic)
|
|
40
|
+
@name = name
|
|
41
|
+
@paths = FileList['.']
|
|
42
|
+
@options = ''
|
|
43
|
+
@verbose = false
|
|
44
|
+
|
|
45
|
+
yield self if block_given?
|
|
46
|
+
define_task
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
attr_reader :name, :paths, :verbose, :options
|
|
52
|
+
|
|
53
|
+
def define_task
|
|
54
|
+
desc 'Run RubyCritic'
|
|
55
|
+
task(name) { run_task }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def run_task
|
|
59
|
+
if verbose
|
|
60
|
+
puts "\n\n!!! Running `#{name}` rake command\n"
|
|
61
|
+
puts "!!! Inspecting #{paths} #{options.empty? ? '' : "with options #{options}"}\n\n"
|
|
62
|
+
end
|
|
63
|
+
application = RubyCritic::Cli::Application.new(options_as_arguments + paths)
|
|
64
|
+
application.execute
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def options_as_arguments
|
|
68
|
+
options.split(/\s+/)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyCritic
|
|
4
|
+
module Reporter
|
|
5
|
+
REPORT_GENERATOR_CLASS_FORMATS = %i[json console lint].freeze
|
|
6
|
+
|
|
7
|
+
def self.generate_report(analysed_modules)
|
|
8
|
+
RubyCritic::Config.formats.uniq.each do |format|
|
|
9
|
+
report_generator_class(format).new(analysed_modules).generate_report
|
|
10
|
+
end
|
|
11
|
+
RubyCritic::Config.formatters.each do |formatter|
|
|
12
|
+
report_generator_class_from_formatter(formatter).new(analysed_modules).generate_report
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.report_generator_class(config_format)
|
|
17
|
+
if REPORT_GENERATOR_CLASS_FORMATS.include? config_format
|
|
18
|
+
require "rubycritic/generators/#{config_format}_report"
|
|
19
|
+
Generator.const_get("#{config_format.capitalize}Report")
|
|
20
|
+
else
|
|
21
|
+
require 'rubycritic/generators/html_report'
|
|
22
|
+
Generator::HtmlReport
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.report_generator_class_from_formatter(formatter)
|
|
27
|
+
require_path, class_name = formatter.sub(/([^:]):([^:])/, '\1\;\2').split('\;', 2)
|
|
28
|
+
class_name ||= require_path
|
|
29
|
+
require require_path unless require_path == class_name
|
|
30
|
+
class_from_path(class_name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.class_from_path(path)
|
|
34
|
+
path.split('::').inject(Object) { |obj, klass| obj.const_get klass }
|
|
35
|
+
rescue NameError => error
|
|
36
|
+
raise "Could not create reporter for class #{path}. Error: #{error}!"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rubycritic/serializer'
|
|
4
|
+
require 'rubycritic/analysers_runner'
|
|
5
|
+
require 'rubycritic/smells_status_setter'
|
|
6
|
+
require 'rubycritic/version'
|
|
7
|
+
require 'digest/md5'
|
|
8
|
+
|
|
9
|
+
module RubyCritic
|
|
10
|
+
class RevisionComparator
|
|
11
|
+
SNAPSHOTS_DIR_NAME = 'snapshots'.freeze
|
|
12
|
+
|
|
13
|
+
def initialize(paths)
|
|
14
|
+
@paths = paths
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def statuses=(analysed_modules_now)
|
|
18
|
+
return unless Config.source_control_system.revision?
|
|
19
|
+
|
|
20
|
+
analysed_modules_before = load_cached_analysed_modules
|
|
21
|
+
return unless analysed_modules_before
|
|
22
|
+
|
|
23
|
+
SmellsStatusSetter.set(
|
|
24
|
+
analysed_modules_before.flat_map(&:smells),
|
|
25
|
+
analysed_modules_now.flat_map(&:smells)
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def load_cached_analysed_modules
|
|
32
|
+
Serializer.new(revision_file).load if File.file?(revision_file)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def revision_file
|
|
36
|
+
@revision_file ||= File.join(
|
|
37
|
+
Config.root,
|
|
38
|
+
SNAPSHOTS_DIR_NAME,
|
|
39
|
+
VERSION,
|
|
40
|
+
Digest::MD5.hexdigest(Marshal.dump(@paths)),
|
|
41
|
+
Config.source_control_system.head_reference
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module RubyCritic
|
|
6
|
+
class Serializer
|
|
7
|
+
def initialize(file)
|
|
8
|
+
@file = file
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def load
|
|
12
|
+
Marshal.load(File.binread(@file))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def dump(content)
|
|
16
|
+
create_file_directory
|
|
17
|
+
File.open(@file, 'w+') do |file|
|
|
18
|
+
Marshal.dump(content, file)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def create_file_directory
|
|
25
|
+
FileUtils.mkdir_p(file_directory)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def file_directory
|
|
29
|
+
File.dirname(@file)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyCritic
|
|
4
|
+
module SmellsStatusSetter
|
|
5
|
+
def self.set(smells_before, smells_now)
|
|
6
|
+
old_smells = smells_now & smells_before
|
|
7
|
+
set_status(old_smells, :old)
|
|
8
|
+
new_smells = smells_now - smells_before
|
|
9
|
+
set_status(new_smells, :new)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.set_status(smells, status)
|
|
13
|
+
smells.each { |smell| smell.status = status }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private_class_method :set_status
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'English'
|
|
4
|
+
require 'shellwords'
|
|
5
|
+
|
|
6
|
+
module RubyCritic
|
|
7
|
+
module SourceControlSystem
|
|
8
|
+
class Base
|
|
9
|
+
@@systems = []
|
|
10
|
+
|
|
11
|
+
def self.register_system
|
|
12
|
+
@@systems << self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.systems
|
|
16
|
+
@@systems
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.create
|
|
20
|
+
supported_system = systems.find(&:supported?)
|
|
21
|
+
if supported_system
|
|
22
|
+
supported_system.new
|
|
23
|
+
else
|
|
24
|
+
puts 'RubyCritic can provide more feedback if you use '\
|
|
25
|
+
"a #{connected_system_names} repository. "\
|
|
26
|
+
'Churn will not be calculated.'
|
|
27
|
+
Double.new
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.connected_system_names
|
|
32
|
+
"#{systems[0...-1].join(', ')} or #{systems[-1]}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
require 'rubycritic/source_control_systems/double'
|
|
39
|
+
require 'rubycritic/source_control_systems/git'
|
|
40
|
+
require 'rubycritic/source_control_systems/mercurial'
|
|
41
|
+
require 'rubycritic/source_control_systems/perforce'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyCritic
|
|
4
|
+
module SourceControlSystem
|
|
5
|
+
class Double < Base
|
|
6
|
+
def revisions_count(_path)
|
|
7
|
+
0
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def date_of_last_commit(_path)
|
|
11
|
+
nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def revision?
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tty/which'
|
|
4
|
+
|
|
5
|
+
module RubyCritic
|
|
6
|
+
module SourceControlSystem
|
|
7
|
+
class Git < Base
|
|
8
|
+
register_system
|
|
9
|
+
GIT_EXECUTABLE = TTY::Which.which('git')
|
|
10
|
+
|
|
11
|
+
def self.git(arg)
|
|
12
|
+
if Gem.win_platform?
|
|
13
|
+
`\"#{GIT_EXECUTABLE}\" #{arg}`
|
|
14
|
+
else
|
|
15
|
+
`#{GIT_EXECUTABLE} #{arg}`
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def git(arg)
|
|
20
|
+
self.class.git(arg)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.supported?
|
|
24
|
+
git('branch 2>&1') && $CHILD_STATUS.success?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.to_s
|
|
28
|
+
'Git'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def revisions_count(path)
|
|
32
|
+
git("log --follow --format=%h #{path.shellescape}").count("\n")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def date_of_last_commit(path)
|
|
36
|
+
git("log -1 --date=iso --format=%ad #{path.shellescape}").chomp!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def revision?
|
|
40
|
+
head_reference && $CHILD_STATUS.success?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def head_reference
|
|
44
|
+
git('rev-parse --verify HEAD').chomp!
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def travel_to_head
|
|
48
|
+
stash_successful = stash_changes
|
|
49
|
+
yield
|
|
50
|
+
ensure
|
|
51
|
+
travel_to_original_state if stash_successful
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.switch_branch(branch)
|
|
55
|
+
uncommitted_changes? ? abort('Uncommitted changes are present.') : `git checkout #{branch}`
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.uncommitted_changes?
|
|
59
|
+
!`git diff-index HEAD --`.empty?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.modified_files
|
|
63
|
+
modified_files = `git diff --name-status #{Config.base_branch} #{Config.feature_branch}`
|
|
64
|
+
modified_files.split("\n").map do |line|
|
|
65
|
+
next if line.start_with?('D')
|
|
66
|
+
|
|
67
|
+
file_name = line.split("\t")[1]
|
|
68
|
+
file_name
|
|
69
|
+
end.compact
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.current_branch
|
|
73
|
+
branch_list = `git branch`
|
|
74
|
+
branch_list.match(/\*.*$/)[0].gsub('* ', '')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def stash_changes
|
|
80
|
+
stashes_count_before = stashes_count
|
|
81
|
+
git('stash')
|
|
82
|
+
stashes_count_after = stashes_count
|
|
83
|
+
stashes_count_after > stashes_count_before
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def stashes_count
|
|
87
|
+
git('stash list --format=%h').count("\n")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def travel_to_original_state
|
|
91
|
+
git('stash pop')
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyCritic
|
|
4
|
+
module SourceControlSystem
|
|
5
|
+
class Mercurial < Base
|
|
6
|
+
register_system
|
|
7
|
+
|
|
8
|
+
def self.supported?
|
|
9
|
+
`hg verify 2>&1` && $CHILD_STATUS.success?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.to_s
|
|
13
|
+
'Mercurial'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def revisions_count(path)
|
|
17
|
+
`hg log #{path.shellescape} --template '1'`.size
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def date_of_last_commit(path)
|
|
21
|
+
`hg log #{path.shellescape} --template '{date|isodate}' --limit 1`.chomp
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def revision?
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|