codeclimate 0.17.0 → 0.18.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 +4 -4
- data/lib/cc/analyzer.rb +0 -3
- data/lib/cc/analyzer/container.rb +1 -0
- data/lib/cc/analyzer/engines_config_builder.rb +29 -23
- data/lib/cc/analyzer/filesystem.rb +6 -20
- data/lib/cc/cli.rb +12 -0
- data/lib/cc/cli/config.rb +1 -7
- data/lib/cc/cli/config_generator.rb +26 -2
- data/lib/cc/cli/init.rb +25 -18
- data/lib/cc/cli/runner.rb +1 -3
- data/lib/cc/workspace.rb +34 -0
- data/lib/cc/workspace/exclusion.rb +29 -0
- data/lib/cc/workspace/path_tree.rb +110 -0
- metadata +7 -10
- data/lib/cc/analyzer/include_paths_builder.rb +0 -62
- data/lib/cc/analyzer/path_entries.rb +0 -27
- data/lib/cc/analyzer/path_filter.rb +0 -50
- data/lib/cc/analyzer/path_minimizer.rb +0 -84
- data/lib/cc/analyzer/path_patterns.rb +0 -46
- data/lib/file_utils_ext.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cc07ab27995ff71abe7fcf3d17cdb26c0e7cab0
|
4
|
+
data.tar.gz: 0bde4385fe0659131b7254d595a3b87a2a099659
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 788524a629d27d9825bfd87bb3181da46444273395fbac5c16ac10254a7ac5d13f9c0bb86494f5f4710d605115a4ae97385ce6773713802fce2bc983dcbf3caf
|
7
|
+
data.tar.gz: def528a3546470b85c9200334286a1afd1a6c6c0eb8eca43189d3fb747745dd43f22db131e8b87b587438aa2b4379637200adca22c21be62aea9049617833af1
|
data/lib/cc/analyzer.rb
CHANGED
@@ -12,13 +12,10 @@ module CC
|
|
12
12
|
autoload :EnginesRunner, "cc/analyzer/engines_runner"
|
13
13
|
autoload :Filesystem, "cc/analyzer/filesystem"
|
14
14
|
autoload :Formatters, "cc/analyzer/formatters"
|
15
|
-
autoload :IncludePathsBuilder, "cc/analyzer/include_paths_builder"
|
16
15
|
autoload :Issue, "cc/analyzer/issue"
|
17
16
|
autoload :IssueSorter, "cc/analyzer/issue_sorter"
|
18
17
|
autoload :LocationDescription, "cc/analyzer/location_description"
|
19
18
|
autoload :LoggingContainerListener, "cc/analyzer/logging_container_listener"
|
20
|
-
autoload :PathPatterns, "cc/analyzer/path_patterns"
|
21
|
-
autoload :PathMinimizer, "cc/analyzer/path_minimizer"
|
22
19
|
autoload :RaisingContainerListener, "cc/analyzer/raising_container_listener"
|
23
20
|
autoload :SourceBuffer, "cc/analyzer/source_buffer"
|
24
21
|
autoload :StatsdContainerListener, "cc/analyzer/statsd_container_listener"
|
@@ -172,6 +172,7 @@ module CC
|
|
172
172
|
def reap_running_container(message)
|
173
173
|
Analyzer.logger.warn("killing container name=#{@name} message=#{message.inspect}")
|
174
174
|
POSIX::Spawn::Child.new("docker", "kill", @name)
|
175
|
+
POSIX::Spawn::Child.new("docker", "wait", @name, timeout: 5.minutes)
|
175
176
|
end
|
176
177
|
|
177
178
|
def timeout
|
@@ -29,23 +29,27 @@ module CC
|
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
-
attr_reader :include_paths
|
33
|
-
|
34
32
|
def engine_config(raw_engine_config)
|
33
|
+
engine_workspace = engine_workspace(raw_engine_config)
|
35
34
|
config = raw_engine_config.merge(
|
36
|
-
|
37
|
-
include_paths: include_paths,
|
35
|
+
include_paths: engine_workspace.paths,
|
38
36
|
)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
# TODO: update the engines to expect the hash and then remove this.
|
43
|
-
if config.fetch("config", {}).keys.size == 1 && config["config"].key?("file")
|
44
|
-
config["config"] = config["config"]["file"]
|
45
|
-
end
|
37
|
+
|
38
|
+
normalize_config_file(config)
|
39
|
+
|
46
40
|
config
|
47
41
|
end
|
48
42
|
|
43
|
+
def engine_workspace(raw_engine_config)
|
44
|
+
if raw_engine_config.key?("exclude_paths") && !@requested_paths.present?
|
45
|
+
base_workspace.clone.tap do |workspace|
|
46
|
+
workspace.remove(raw_engine_config["exclude_paths"])
|
47
|
+
end
|
48
|
+
else
|
49
|
+
base_workspace
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
49
53
|
def names_and_raw_engine_configs
|
50
54
|
{}.tap do |ret|
|
51
55
|
(@config.engines || {}).each do |name, raw_engine_config|
|
@@ -56,20 +60,22 @@ module CC
|
|
56
60
|
end
|
57
61
|
end
|
58
62
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
def base_workspace
|
64
|
+
@base_workspace ||= Workspace.new.tap do |workspace|
|
65
|
+
workspace.add(@requested_paths)
|
66
|
+
unless @requested_paths.present?
|
67
|
+
workspace.remove([".git"])
|
68
|
+
workspace.remove(@config.exclude_paths)
|
69
|
+
end
|
70
|
+
end
|
66
71
|
end
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
+
# The yaml gem turns a config file string into a hash, but engines expect
|
74
|
+
# the string. So we (for now) need to turn it into a string in that one
|
75
|
+
# scenario.
|
76
|
+
def normalize_config_file(config)
|
77
|
+
if config.fetch("config", {}).keys.size == 1 && config["config"].key?("file")
|
78
|
+
config["config"] = config["config"]["file"]
|
73
79
|
end
|
74
80
|
end
|
75
81
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module CC
|
2
2
|
module Analyzer
|
3
3
|
class Filesystem
|
4
|
+
attr_reader :root
|
5
|
+
|
4
6
|
def initialize(root)
|
5
7
|
@root = root
|
6
8
|
end
|
@@ -22,30 +24,14 @@ module CC
|
|
22
24
|
File.chown(root_uid, root_gid, path_for(path))
|
23
25
|
end
|
24
26
|
|
25
|
-
def
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def files_matching(globs)
|
30
|
-
Dir.chdir(@root) do
|
31
|
-
globs.map do |glob|
|
32
|
-
Dir.glob(glob)
|
33
|
-
end.flatten.sort.uniq
|
34
|
-
end
|
27
|
+
def ls
|
28
|
+
Dir.entries(root).reject { |entry| [".", ".."].include?(entry) }
|
35
29
|
end
|
36
30
|
|
37
31
|
private
|
38
32
|
|
39
|
-
def file_paths
|
40
|
-
@file_paths ||= Dir.chdir(@root) do
|
41
|
-
`find . -type f -print0`.strip.split("\0").map do |path|
|
42
|
-
path.sub(%r{^\.\/}, "")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
33
|
def path_for(path)
|
48
|
-
File.join(
|
34
|
+
File.join(root, path)
|
49
35
|
end
|
50
36
|
|
51
37
|
def root_uid
|
@@ -57,7 +43,7 @@ module CC
|
|
57
43
|
end
|
58
44
|
|
59
45
|
def root_stat
|
60
|
-
@root_stat ||= File.stat(
|
46
|
+
@root_stat ||= File.stat(root)
|
61
47
|
end
|
62
48
|
end
|
63
49
|
end
|
data/lib/cc/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "active_support"
|
2
2
|
require "active_support/core_ext"
|
3
3
|
require "cc/analyzer"
|
4
|
+
require "cc/workspace"
|
4
5
|
require "cc/yaml"
|
5
6
|
|
6
7
|
module CC
|
@@ -15,5 +16,16 @@ module CC
|
|
15
16
|
autoload :Test, "cc/cli/test"
|
16
17
|
autoload :ValidateConfig, "cc/cli/validate_config"
|
17
18
|
autoload :Version, "cc/cli/version"
|
19
|
+
|
20
|
+
def self.debug(message, values = {})
|
21
|
+
if ENV["CODECLIMATE_DEBUG"]
|
22
|
+
if values.any?
|
23
|
+
message << " "
|
24
|
+
message << values.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")
|
25
|
+
end
|
26
|
+
|
27
|
+
$stderr.puts("[DEBUG] #{message}")
|
28
|
+
end
|
29
|
+
end
|
18
30
|
end
|
19
31
|
end
|
data/lib/cc/cli/config.rb
CHANGED
@@ -21,13 +21,7 @@ module CC
|
|
21
21
|
|
22
22
|
def add_exclude_paths(paths)
|
23
23
|
config["exclude_paths"] ||= []
|
24
|
-
config["exclude_paths"]
|
25
|
-
if path.ends_with?("/")
|
26
|
-
"#{path}**/*"
|
27
|
-
else
|
28
|
-
path
|
29
|
-
end
|
30
|
-
end
|
24
|
+
config["exclude_paths"] |= paths
|
31
25
|
end
|
32
26
|
|
33
27
|
private
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
1
3
|
module CC
|
2
4
|
module CLI
|
3
5
|
class ConfigGenerator
|
@@ -37,7 +39,7 @@ module CC
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def exclude_paths
|
40
|
-
AUTO_EXCLUDE_PATHS.select { |path| filesystem.exist?(path) }
|
42
|
+
@exclude_paths ||= AUTO_EXCLUDE_PATHS.select { |path| filesystem.exist?(path) }
|
41
43
|
end
|
42
44
|
|
43
45
|
def post_generation_verb
|
@@ -59,10 +61,32 @@ module CC
|
|
59
61
|
end
|
60
62
|
|
61
63
|
def files_exist?(engine)
|
62
|
-
|
64
|
+
workspace_files.any? do |path|
|
63
65
|
engine["enable_regexps"].any? { |re| Regexp.new(re).match(path) }
|
64
66
|
end
|
65
67
|
end
|
68
|
+
|
69
|
+
def non_excluded_paths
|
70
|
+
@non_excluded_paths ||= begin
|
71
|
+
excludes = exclude_paths.map { |path| path.chomp("/") }
|
72
|
+
filesystem.ls.reject do |path|
|
73
|
+
path.starts_with?(".") || excludes.include?(path)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def workspace_files
|
79
|
+
@workspace_files ||= Dir.chdir(filesystem.root) do
|
80
|
+
if non_excluded_paths.empty?
|
81
|
+
[]
|
82
|
+
else
|
83
|
+
find_cmd = "find #{non_excluded_paths.map(&:shellescape).join(' ')} -type f -print0"
|
84
|
+
`#{find_cmd}`.strip.split("\0").map do |path|
|
85
|
+
path.sub(%r{^\.\/}, "")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
66
90
|
end
|
67
91
|
end
|
68
92
|
end
|
data/lib/cc/cli/init.rb
CHANGED
@@ -10,11 +10,11 @@ module CC
|
|
10
10
|
def run
|
11
11
|
if !upgrade? && filesystem.exist?(CODECLIMATE_YAML)
|
12
12
|
warn "Config file .codeclimate.yml already present.\nTry running 'validate-config' to check configuration."
|
13
|
-
|
13
|
+
create_default_engine_configs if engines_enabled?
|
14
14
|
elsif upgrade? && engines_enabled?
|
15
15
|
fatal "--upgrade should not be used on a .codeclimate.yml configured for the Platform.\nTry running 'validate-config' to check configuration."
|
16
16
|
else
|
17
|
-
|
17
|
+
generate_all_config
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -24,7 +24,7 @@ module CC
|
|
24
24
|
@args.include?("--upgrade")
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
27
|
+
def generate_all_config
|
28
28
|
unless config_generator.can_generate?
|
29
29
|
config_generator.errors.each do |error|
|
30
30
|
$stderr.puts colorize("ERROR: #{error}", :red)
|
@@ -34,10 +34,11 @@ module CC
|
|
34
34
|
|
35
35
|
create_codeclimate_yaml
|
36
36
|
success "Config file .codeclimate.yml successfully #{config_generator.post_generation_verb}.\nEdit and then try running 'validate-config' to check configuration."
|
37
|
-
|
37
|
+
create_default_engine_configs
|
38
38
|
end
|
39
39
|
|
40
40
|
def create_codeclimate_yaml
|
41
|
+
say "Generating .codeclimate.yml..."
|
41
42
|
config = CC::CLI::Config.new
|
42
43
|
|
43
44
|
config_generator.eligible_engines.each do |(engine_name, engine_config)|
|
@@ -48,8 +49,9 @@ module CC
|
|
48
49
|
filesystem.write_path(CODECLIMATE_YAML, config.to_yaml)
|
49
50
|
end
|
50
51
|
|
51
|
-
def
|
52
|
-
|
52
|
+
def create_default_engine_configs
|
53
|
+
say "Generating default configuration for engines..."
|
54
|
+
available_engine_configs.each do |config_path|
|
53
55
|
file_name = File.basename(config_path)
|
54
56
|
if filesystem.exist?(file_name)
|
55
57
|
say "Skipping generating #{file_name} file (already exists)."
|
@@ -60,29 +62,34 @@ module CC
|
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
|
-
def
|
64
|
-
|
65
|
+
def available_engine_configs
|
66
|
+
engine_names = existing_cc_config.engines.select do |_, config|
|
67
|
+
config.enabled?
|
68
|
+
end.keys
|
69
|
+
|
70
|
+
all_paths = engine_names.flat_map do |engine_name|
|
65
71
|
engine_directory = File.expand_path("../../../../config/#{engine_name}", __FILE__)
|
66
72
|
Dir.glob("#{engine_directory}/*", File::FNM_DOTMATCH)
|
67
73
|
end
|
68
|
-
|
69
|
-
|
74
|
+
all_paths.reject do |path|
|
75
|
+
%w[. ..].include?(File.basename(path))
|
76
|
+
end
|
70
77
|
end
|
71
78
|
|
72
79
|
def engines_enabled?
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
if filesystem.exist?(CODECLIMATE_YAML)
|
78
|
-
config = CC::Analyzer::Config.new(File.read(CODECLIMATE_YAML))
|
79
|
-
@engines_enabled ||= config.engine_names.any?
|
80
|
-
end
|
80
|
+
cc_config = existing_cc_config
|
81
|
+
cc_config.present? && cc_config.engines.present?
|
81
82
|
end
|
82
83
|
|
83
84
|
def config_generator
|
84
85
|
@config_generator ||= ConfigGenerator.for(filesystem, engine_registry, upgrade?)
|
85
86
|
end
|
87
|
+
|
88
|
+
def existing_cc_config
|
89
|
+
if filesystem.exist?(CODECLIMATE_YAML)
|
90
|
+
CC::Yaml.parse(filesystem.read_path(CODECLIMATE_YAML))
|
91
|
+
end
|
92
|
+
end
|
86
93
|
end
|
87
94
|
end
|
88
95
|
end
|
data/lib/cc/cli/runner.rb
CHANGED
@@ -10,9 +10,7 @@ module CC
|
|
10
10
|
rescue => ex
|
11
11
|
$stderr.puts("error: (#{ex.class}) #{ex.message}")
|
12
12
|
|
13
|
-
|
14
|
-
$stderr.puts("backtrace: #{ex.backtrace.join("\n\t")}")
|
15
|
-
end
|
13
|
+
CLI.debug("backtrace: #{ex.backtrace.join("\n\t")}")
|
16
14
|
end
|
17
15
|
|
18
16
|
def initialize(args)
|
data/lib/cc/workspace.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module CC
|
2
|
+
class Workspace
|
3
|
+
autoload :Exclusion, "cc/workspace/exclusion"
|
4
|
+
autoload :PathTree, "cc/workspace/path_tree"
|
5
|
+
|
6
|
+
def initialize(path_tree = PathTree.new("."))
|
7
|
+
@path_tree = path_tree
|
8
|
+
end
|
9
|
+
|
10
|
+
def clone
|
11
|
+
self.class.new(path_tree.clone)
|
12
|
+
end
|
13
|
+
|
14
|
+
def paths
|
15
|
+
path_tree.all_paths
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(paths)
|
19
|
+
if paths.present?
|
20
|
+
path_tree.include_paths(paths)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove(patterns)
|
25
|
+
Array(patterns).each do |pattern|
|
26
|
+
path_tree.exclude_paths(Exclusion.new(pattern).expand)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :path_tree
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module CC
|
2
|
+
class Workspace
|
3
|
+
class Exclusion
|
4
|
+
def initialize(pattern)
|
5
|
+
@pattern = simplify(pattern)
|
6
|
+
end
|
7
|
+
|
8
|
+
def expand
|
9
|
+
if glob?
|
10
|
+
Dir.glob(pattern)
|
11
|
+
else
|
12
|
+
[pattern]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def glob?
|
17
|
+
pattern.include?("*")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :pattern
|
23
|
+
|
24
|
+
def simplify(pattern)
|
25
|
+
pattern.to_s.sub(%r{(/\*\*)?(/\*)?$}, "")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "set"
|
3
|
+
|
4
|
+
module CC
|
5
|
+
class Workspace
|
6
|
+
class PathTree
|
7
|
+
def self.create(pathname)
|
8
|
+
if pathname.directory?
|
9
|
+
new(pathname.to_s)
|
10
|
+
else
|
11
|
+
FileNode.new(pathname.to_s)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(root_path, children = {})
|
16
|
+
@root_path = root_path.dup.freeze
|
17
|
+
@children = children
|
18
|
+
end
|
19
|
+
|
20
|
+
def clone
|
21
|
+
self.class.new(root_path, children.dup)
|
22
|
+
end
|
23
|
+
|
24
|
+
def exclude_paths(paths)
|
25
|
+
paths.each { |path| remove(*normalized_path_pieces(path)) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def include_paths(paths)
|
29
|
+
paths.each { |path| add(*normalized_path_pieces(path)) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def all_paths
|
33
|
+
if populated?
|
34
|
+
children.values.flat_map(&:all_paths)
|
35
|
+
else
|
36
|
+
[File.join(root_path, File::SEPARATOR)]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def populated?
|
43
|
+
children.present?
|
44
|
+
end
|
45
|
+
|
46
|
+
def remove(head = nil, *tail)
|
47
|
+
return if head.nil? && tail.empty?
|
48
|
+
populate_direct_children
|
49
|
+
|
50
|
+
if (child = children[head])
|
51
|
+
child.remove(*tail)
|
52
|
+
children.delete(head) unless child.populated?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def add(head = nil, *tail)
|
57
|
+
return if head.nil? && tail.empty?
|
58
|
+
|
59
|
+
if (entry = find_direct_child(head))
|
60
|
+
children[entry.basename.to_s] = self.class.create(entry)
|
61
|
+
children[entry.basename.to_s].add(*tail)
|
62
|
+
else
|
63
|
+
CLI.debug("Couldn't include because part of path doesn't exist.", path: File.join(root_path, head))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
attr_reader :children, :root_path
|
70
|
+
|
71
|
+
def populate_direct_children
|
72
|
+
return if populated?
|
73
|
+
|
74
|
+
Pathname.new(root_path).each_child do |child_path|
|
75
|
+
children[child_path.basename.to_s] = self.class.create(child_path)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_direct_child(name)
|
80
|
+
Pathname.new(root_path).children.detect { |c| c.basename.to_s == name }
|
81
|
+
end
|
82
|
+
|
83
|
+
def normalized_path_pieces(path)
|
84
|
+
Pathname.new(path).cleanpath.to_s.split(File::SEPARATOR).reject(&:blank?)
|
85
|
+
end
|
86
|
+
|
87
|
+
class FileNode
|
88
|
+
def initialize(root_path)
|
89
|
+
@root_path = root_path.dup.freeze
|
90
|
+
end
|
91
|
+
|
92
|
+
def all_paths
|
93
|
+
[@root_path]
|
94
|
+
end
|
95
|
+
|
96
|
+
def populated?
|
97
|
+
false
|
98
|
+
end
|
99
|
+
|
100
|
+
def remove(*)
|
101
|
+
# this space intentionally left blank
|
102
|
+
end
|
103
|
+
|
104
|
+
def add(*)
|
105
|
+
# this space intentionally left blank
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: codeclimate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code Climate
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01
|
11
|
+
date: 2016-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -50,14 +50,14 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.
|
53
|
+
version: 0.7.0
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.
|
60
|
+
version: 0.7.0
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: faraday
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -216,15 +216,10 @@ files:
|
|
216
216
|
- lib/cc/analyzer/formatters/json_formatter.rb
|
217
217
|
- lib/cc/analyzer/formatters/plain_text_formatter.rb
|
218
218
|
- lib/cc/analyzer/formatters/spinner.rb
|
219
|
-
- lib/cc/analyzer/include_paths_builder.rb
|
220
219
|
- lib/cc/analyzer/issue.rb
|
221
220
|
- lib/cc/analyzer/issue_sorter.rb
|
222
221
|
- lib/cc/analyzer/location_description.rb
|
223
222
|
- lib/cc/analyzer/logging_container_listener.rb
|
224
|
-
- lib/cc/analyzer/path_entries.rb
|
225
|
-
- lib/cc/analyzer/path_filter.rb
|
226
|
-
- lib/cc/analyzer/path_minimizer.rb
|
227
|
-
- lib/cc/analyzer/path_patterns.rb
|
228
223
|
- lib/cc/analyzer/raising_container_listener.rb
|
229
224
|
- lib/cc/analyzer/source_buffer.rb
|
230
225
|
- lib/cc/analyzer/statsd_container_listener.rb
|
@@ -248,7 +243,9 @@ files:
|
|
248
243
|
- lib/cc/cli/upgrade_config_generator.rb
|
249
244
|
- lib/cc/cli/validate_config.rb
|
250
245
|
- lib/cc/cli/version.rb
|
251
|
-
- lib/
|
246
|
+
- lib/cc/workspace.rb
|
247
|
+
- lib/cc/workspace/exclusion.rb
|
248
|
+
- lib/cc/workspace/path_tree.rb
|
252
249
|
homepage: https://codeclimate.com
|
253
250
|
licenses:
|
254
251
|
- MIT
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require "file_utils_ext"
|
2
|
-
require "cc/analyzer/path_minimizer"
|
3
|
-
require "cc/analyzer/path_filter"
|
4
|
-
|
5
|
-
module CC
|
6
|
-
module Analyzer
|
7
|
-
class IncludePathsBuilder
|
8
|
-
IGNORE_PATHS = [".", "..", ".git"].freeze
|
9
|
-
|
10
|
-
attr_reader :cc_include_paths
|
11
|
-
|
12
|
-
def initialize(cc_exclude_paths, cc_include_paths = [])
|
13
|
-
@cc_exclude_paths = cc_exclude_paths
|
14
|
-
@cc_include_paths = cc_include_paths
|
15
|
-
end
|
16
|
-
|
17
|
-
def build
|
18
|
-
PathMinimizer.new(paths_filter.paths).minimize.uniq
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def paths_filter
|
24
|
-
@_paths =
|
25
|
-
PathFilter.new(include_paths).
|
26
|
-
reject_paths(ignored_files).
|
27
|
-
reject_unreadable_paths.
|
28
|
-
select_readable_files.
|
29
|
-
reject_symlinks
|
30
|
-
end
|
31
|
-
|
32
|
-
def include_paths
|
33
|
-
if @cc_include_paths.empty?
|
34
|
-
all_paths
|
35
|
-
else
|
36
|
-
@cc_include_paths.flat_map do |path|
|
37
|
-
PathEntries.new(path).entries
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def all_paths
|
43
|
-
Dir.glob("*", File::FNM_DOTMATCH).
|
44
|
-
reject { |path| IncludePathsBuilder::IGNORE_PATHS.include?(path) }.
|
45
|
-
flat_map { |path| PathEntries.new(path).entries }
|
46
|
-
end
|
47
|
-
|
48
|
-
def ignored_files
|
49
|
-
return @_ignored_files if @_ignored_files
|
50
|
-
|
51
|
-
Tempfile.open(".cc_gitignore") do |tmp|
|
52
|
-
tmp.write(File.read(".gitignore")) if File.file?(".gitignore")
|
53
|
-
tmp << @cc_exclude_paths.join("\n")
|
54
|
-
tmp.close
|
55
|
-
tracked_and_ignored = `git ls-files -zi -X #{tmp.path} 2>/dev/null`.split("\0")
|
56
|
-
untracked_and_ignored = `git ls-files -zio -X #{tmp.path} 2>/dev/null`.split("\0")
|
57
|
-
@_ignored_files = tracked_and_ignored + untracked_and_ignored
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module CC
|
2
|
-
module Analyzer
|
3
|
-
class PathEntries
|
4
|
-
def initialize(initial_path)
|
5
|
-
@initial_path = initial_path.gsub(%r{/$}, "")
|
6
|
-
end
|
7
|
-
|
8
|
-
def entries
|
9
|
-
if File.directory?(initial_path)
|
10
|
-
all_entries.reject do |path|
|
11
|
-
path.end_with?("/.") || path.start_with?(".git/")
|
12
|
-
end
|
13
|
-
else
|
14
|
-
initial_path
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
attr_reader :initial_path
|
21
|
-
|
22
|
-
def all_entries
|
23
|
-
Dir.glob("#{initial_path}/**/*", File::FNM_DOTMATCH).push(initial_path)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module CC
|
2
|
-
module Analyzer
|
3
|
-
class PathFilter
|
4
|
-
attr_reader :paths
|
5
|
-
|
6
|
-
def initialize(paths)
|
7
|
-
@paths = paths
|
8
|
-
end
|
9
|
-
|
10
|
-
def reject_unreadable_paths
|
11
|
-
@paths = paths - unreadable_path_entries
|
12
|
-
self
|
13
|
-
end
|
14
|
-
|
15
|
-
def reject_paths(ignore_paths)
|
16
|
-
@paths = paths - ignore_paths
|
17
|
-
self
|
18
|
-
end
|
19
|
-
|
20
|
-
def select_readable_files
|
21
|
-
@paths = paths.select { |path| File.exist?(path) && FileUtils.readable_by_all?(path) }
|
22
|
-
self
|
23
|
-
end
|
24
|
-
|
25
|
-
def reject_symlinks
|
26
|
-
@paths = paths.reject { |path| File.symlink?(path) }
|
27
|
-
self
|
28
|
-
end
|
29
|
-
|
30
|
-
def reject_globs(globs)
|
31
|
-
patterns = PathPatterns.new(globs)
|
32
|
-
@paths = paths.reject { |path| patterns.match?(pathpatterns.match?(path)) }
|
33
|
-
self
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def unreadable_path_entries
|
39
|
-
@_unreadable_path_entries ||=
|
40
|
-
unreadable_paths.flat_map { |path| PathEntries.new(path).entries }
|
41
|
-
end
|
42
|
-
|
43
|
-
def unreadable_paths
|
44
|
-
paths.select do |path|
|
45
|
-
File.directory?(path) && !FileUtils.readable_by_all?(path)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
require "cc/analyzer/path_entries"
|
2
|
-
require "cc/analyzer/include_paths_builder"
|
3
|
-
|
4
|
-
module CC
|
5
|
-
module Analyzer
|
6
|
-
class PathMinimizer
|
7
|
-
def initialize(paths)
|
8
|
-
@paths = paths
|
9
|
-
@to_remove = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def minimize
|
13
|
-
if diff.empty?
|
14
|
-
["./"]
|
15
|
-
else
|
16
|
-
filtered_paths
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
attr_reader :paths
|
23
|
-
|
24
|
-
def diff
|
25
|
-
@_diff ||=
|
26
|
-
(all_files - paths).
|
27
|
-
reject { |path| File.symlink?(path) }.
|
28
|
-
flat_map { |path| build_entry_combinations(path) }
|
29
|
-
end
|
30
|
-
|
31
|
-
def filtered_paths
|
32
|
-
filtered_paths = @paths - paths_to_remove
|
33
|
-
filtered_paths.map { |path| add_trailing_slash(path) }
|
34
|
-
end
|
35
|
-
|
36
|
-
def paths_to_remove
|
37
|
-
@paths.reduce([]) do |to_remove, path|
|
38
|
-
if File.directory?(path)
|
39
|
-
to_remove + removable_paths_for(path)
|
40
|
-
else
|
41
|
-
to_remove
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def removable_paths_for(path)
|
47
|
-
file_paths = PathEntries.new(path).entries
|
48
|
-
|
49
|
-
if all_paths_match?(file_paths)
|
50
|
-
file_paths - [path]
|
51
|
-
else
|
52
|
-
[path]
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def all_paths_match?(paths)
|
57
|
-
paths.all? { |path| @paths.include?(path) }
|
58
|
-
end
|
59
|
-
|
60
|
-
def add_trailing_slash(path)
|
61
|
-
if File.directory?(path) && !path.end_with?("/")
|
62
|
-
"#{path}/"
|
63
|
-
else
|
64
|
-
path
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def build_entry_combinations(path)
|
69
|
-
split = path.split("/")
|
70
|
-
|
71
|
-
0.upto(split.length - 1).map do |n|
|
72
|
-
split[0..n].join("/")
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def all_files
|
77
|
-
@_all_files ||=
|
78
|
-
Dir.glob("*", File::FNM_DOTMATCH).
|
79
|
-
reject { |path| IncludePathsBuilder::IGNORE_PATHS.include?(path) }.
|
80
|
-
flat_map { |path| PathEntries.new(path).entries }
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module CC
|
2
|
-
module Analyzer
|
3
|
-
class PathPatterns
|
4
|
-
def initialize(patterns, root = Dir.pwd)
|
5
|
-
@patterns = patterns
|
6
|
-
@root = root
|
7
|
-
end
|
8
|
-
|
9
|
-
def match?(path)
|
10
|
-
expanded.include?(path)
|
11
|
-
end
|
12
|
-
|
13
|
-
def expanded
|
14
|
-
@expanded ||= expand
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def expand
|
20
|
-
results = Dir.chdir(@root) do
|
21
|
-
@patterns.flat_map do |pattern|
|
22
|
-
value = glob_value(pattern)
|
23
|
-
Dir.glob(value)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
results.sort.uniq
|
28
|
-
end
|
29
|
-
|
30
|
-
def glob_value(pattern)
|
31
|
-
# FIXME: there exists a temporary workaround whereby **-style globs
|
32
|
-
# are translated to **/*-style globs within cc-yaml's custom
|
33
|
-
# Glob#value method. It was thought that that would work correctly
|
34
|
-
# with Dir.glob but it turns out we have to actually invoke #value
|
35
|
-
# directrly for this to work. We need to guard this on class (not
|
36
|
-
# respond_to?) because our mocking framework adds a #value method to
|
37
|
-
# all objects, apparently.
|
38
|
-
if pattern.is_a?(CC::Yaml::Nodes::Glob)
|
39
|
-
pattern.value
|
40
|
-
else
|
41
|
-
pattern
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|