codeclimate 0.14.2 → 0.14.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 72cddaaaf2d406b672e5dcf23810a2c3c12d5bf1
4
- data.tar.gz: 8d59b60cd8907a9ac2f797c355aaf74cc8c28e1e
3
+ metadata.gz: 10bc38c06b10a955c8f01ebb2275e7940b8c79c4
4
+ data.tar.gz: ed11b6c4343ab1a54a70b63d08b474700735d905
5
5
  SHA512:
6
- metadata.gz: dcae9739365b050502e5dbeded10610040236b0f9c8ca84b5a5559955f28c34101be489363874bd469748ec61218365f8cfd4fa0b89e6f67dfba122ae72b6609
7
- data.tar.gz: ffa9d0a75f6fdd2e615e5c1dc02b156c03f35e3f723d40845b9063f4016dbc4d09435fb0c43603cbeaf7cd9905378106bca83fb28409e0b630d8204a0c45ebb0
6
+ metadata.gz: 626e8011b55617172497200db09a1bf25401ad70805d17fe850d1ff1a67ab223cb294ea6a80fa46dc2502bc68ef91cb8d04fa547899a1b4c1ba408e64e507ebe
7
+ data.tar.gz: 0a99283ef527994d1ba32e29d84331549afd06c38cc3f580c6f0c8650c640b73b5a3c95e2c27689763b5a1e99e2b07a88d603271a9e24bb832fbba0dd8000fbe
data/config/engines.yml CHANGED
@@ -18,8 +18,12 @@ brakeman:
18
18
  enable_regexps:
19
19
  - ^script\/rails$
20
20
  default_ratings_paths:
21
- - "app/**"
21
+ - "Gemfile.lock"
22
+ - "**.erb"
23
+ - "**.haml"
22
24
  - "**.rb"
25
+ - "**.rhtml"
26
+ - "**.slim"
23
27
  bundler-audit:
24
28
  image: codeclimate/codeclimate-bundler-audit
25
29
  description: Patch-level verification for Bundler.
@@ -245,3 +245,9 @@ rules:
245
245
  yoda:
246
246
  - 0
247
247
  - never
248
+ env:
249
+ browser: true
250
+ node: true
251
+ jquery: true
252
+ amd: true
253
+ commonjs: true
data/lib/cc/analyzer.rb CHANGED
@@ -16,6 +16,7 @@ module CC
16
16
  autoload :LocationDescription, "cc/analyzer/location_description"
17
17
  autoload :LoggingContainerListener, "cc/analyzer/logging_container_listener"
18
18
  autoload :PathPatterns, "cc/analyzer/path_patterns"
19
+ autoload :PathMinimizer, "cc/analyzer/path_minimizer"
19
20
  autoload :RaisingContainerListener, "cc/analyzer/raising_container_listener"
20
21
  autoload :SourceBuffer, "cc/analyzer/source_buffer"
21
22
  autoload :StatsdContainerListener, "cc/analyzer/statsd_container_listener"
@@ -60,6 +60,7 @@ module CC
60
60
  duration = timeout
61
61
  @listener.timed_out(container_data(duration: duration))
62
62
  else
63
+ sleep 0.01 until !t_out.alive? && !t_err.alive?
63
64
  duration = ((Time.now - started) * 1000).round
64
65
  @listener.finished(container_data(duration: duration, status: status))
65
66
  end
@@ -30,9 +30,21 @@ module CC
30
30
  end
31
31
 
32
32
  def ignore_issue?(json)
33
+ check_disabled?(json) || ignore_fingerprint?(json)
34
+ end
35
+
36
+ def check_disabled?(json)
33
37
  !check_config(json["check_name"]).fetch("enabled", true)
34
38
  end
35
39
 
40
+ def ignore_fingerprint?(json)
41
+ if (fingerprint = json["fingerprint"])
42
+ @config.fetch("exclude_fingerprints", []).include?(fingerprint)
43
+ else
44
+ false
45
+ end
46
+ end
47
+
36
48
  def check_config(check_name)
37
49
  @checks ||= @config.fetch("checks", {})
38
50
  @checks.fetch(check_name, {})
@@ -29,6 +29,8 @@ module CC
29
29
 
30
30
  private
31
31
 
32
+ attr_reader :include_paths
33
+
32
34
  def engine_config(raw_engine_config)
33
35
  config = raw_engine_config.merge(
34
36
  exclude_paths: exclude_paths,
@@ -55,9 +57,7 @@ module CC
55
57
  end
56
58
 
57
59
  def include_paths
58
- IncludePathsBuilder.new(
59
- @config.exclude_paths || [], @requested_paths
60
- ).build
60
+ IncludePathsBuilder.new(exclude_paths, Array(@requested_paths)).build
61
61
  end
62
62
 
63
63
  def exclude_paths
@@ -47,7 +47,7 @@ module CC
47
47
  config: @config,
48
48
  container_label: @container_label,
49
49
  source_dir: @source_dir,
50
- requested_paths: @requested_paths,
50
+ requested_paths: requested_paths,
51
51
  ).run
52
52
  end
53
53
 
@@ -1,13 +1,11 @@
1
1
  require "file_utils_ext"
2
+ require "cc/analyzer/path_minimizer"
3
+ require "cc/analyzer/path_filter"
2
4
 
3
5
  module CC
4
6
  module Analyzer
5
7
  class IncludePathsBuilder
6
- def self.relevant_entries(path)
7
- Dir.entries(path).reject do |e|
8
- %w(. .. .git).include?(e) || File.symlink?(File.join(path, e))
9
- end
10
- end
8
+ IGNORE_PATHS = [".", "..", ".git"].freeze
11
9
 
12
10
  attr_reader :cc_include_paths
13
11
 
@@ -17,152 +15,47 @@ module CC
17
15
  end
18
16
 
19
17
  def build
20
- if cc_include_paths.any?
21
- paths = filter_by_cc_includes
22
- else
23
- root = Directory.new(".", ignored_files)
24
- paths = root.included_paths
25
- end
26
-
27
- paths.each do |path|
28
- raise_on_unreadable_files(path)
29
- end
18
+ PathMinimizer.new(paths_filter.paths).minimize.uniq
30
19
  end
31
20
 
32
- protected
21
+ private
22
+
23
+ def paths_filter
24
+ @_paths =
25
+ PathFilter.new(include_paths).
26
+ reject_paths(ignored_files).
27
+ raise_if_any_unreadable_files.
28
+ reject_unreadable_paths.
29
+ select_readable_files.
30
+ reject_symlinks
31
+ end
33
32
 
34
- def filter_by_cc_includes
35
- paths = []
36
- cc_include_paths.each do |path|
37
- if File.directory?(path)
38
- root = Directory.new(path, ignored_files)
39
- paths += root.included_paths
40
- elsif !ignored_files.include?(path)
41
- paths << path
33
+ def include_paths
34
+ if @cc_include_paths.empty?
35
+ all_paths
36
+ else
37
+ @cc_include_paths.flat_map do |path|
38
+ PathEntries.new(path).entries
42
39
  end
43
40
  end
44
- paths.uniq
41
+ end
42
+
43
+ def all_paths
44
+ Dir.glob("*", File::FNM_DOTMATCH).
45
+ reject { |path| IncludePathsBuilder::IGNORE_PATHS.include?(path) }.
46
+ flat_map { |path| PathEntries.new(path).entries }
45
47
  end
46
48
 
47
49
  def ignored_files
50
+ return @_ignored_files if @_ignored_files
51
+
48
52
  Tempfile.open(".cc_gitignore") do |tmp|
49
53
  tmp.write(File.read(".gitignore")) if File.file?(".gitignore")
50
54
  tmp << @cc_exclude_paths.join("\n")
51
55
  tmp.close
52
56
  tracked_and_ignored = `git ls-files -zi -X #{tmp.path} 2>/dev/null`.split("\0")
53
57
  untracked_and_ignored = `git ls-files -zio -X #{tmp.path} 2>/dev/null`.split("\0")
54
- tracked_and_ignored + untracked_and_ignored
55
- end
56
- end
57
-
58
- def raise_on_unreadable_files(path)
59
- if File.directory?(path)
60
- raise_on_unreadable_files_in_directory(path)
61
- elsif !FileUtils.readable_by_all?(path)
62
- raise CC::Analyzer::UnreadableFileError, "Can't read #{path}"
63
- end
64
- end
65
-
66
- def raise_on_unreadable_files_in_directory(path)
67
- IncludePathsBuilder.relevant_entries(path).each do |entry|
68
- sub_path = File.join(path, entry)
69
- raise_on_unreadable_files(sub_path)
70
- end
71
- end
72
-
73
- class Directory
74
- def initialize(path, excluded_files)
75
- @path = path
76
- @excluded_files = ensure_hashified(excluded_files)
77
- end
78
-
79
- def all_included?
80
- readable_by_all? &&
81
- files_all_included? &&
82
- subdirectories_all_included?
83
- end
84
-
85
- def included_paths
86
- if all_included?
87
- [@path + "/"]
88
- elsif readable_by_all?
89
- result = []
90
- result += included_file_entries
91
- result += included_subdirectory_results
92
- result
93
- else
94
- []
95
- end
96
- end
97
-
98
- protected
99
-
100
- def ensure_hashified(obj)
101
- if obj.is_a?(Array)
102
- obj.each_with_object({}) do |included, result|
103
- result[included] = true
104
- end
105
- else
106
- obj
107
- end
108
- end
109
-
110
- def files_all_included?
111
- file_entries.none? { |e| @excluded_files[e] }
112
- end
113
-
114
- def file_entries
115
- @file_entries ||= relevant_full_entries.reject do |e|
116
- File.directory?(e)
117
- end
118
- end
119
-
120
- def full_entry(entry)
121
- if @path == "."
122
- entry
123
- else
124
- File.join(@path, entry)
125
- end
126
- end
127
-
128
- def included_file_entries
129
- file_entries.reject { |file_entry| @excluded_files[file_entry] }
130
- end
131
-
132
- def included_subdirectory_results
133
- subdirectories.each_with_object([]) do |subdirectory, result|
134
- result.concat(subdirectory.included_paths)
135
- end
136
- end
137
-
138
- def readable_by_all?
139
- FileUtils.readable_by_all?(@path)
140
- end
141
-
142
- def relevant_full_entries
143
- unless @relevant_full_entries
144
- raw_entries = IncludePathsBuilder.relevant_entries(@path)
145
- @relevant_full_entries = raw_entries.map do |e|
146
- full_entry(e)
147
- end
148
- end
149
- @relevant_full_entries
150
- end
151
-
152
- def subdirectories
153
- unless @subdirectories
154
- entries = relevant_full_entries.select do |e|
155
- File.directory?(e)
156
- end
157
- @subdirectories = entries.map do |e|
158
- Directory.new(e, @excluded_files)
159
- end
160
- end
161
- @subdirectories
162
- end
163
-
164
- def subdirectories_all_included?
165
- subdirectories.all?(&:all_included?)
58
+ @_ignored_files = tracked_and_ignored + untracked_and_ignored
166
59
  end
167
60
  end
168
61
  end
@@ -16,13 +16,13 @@ module CC
16
16
 
17
17
  case
18
18
  when location["lines"]
19
- location["lines"]["begin"].to_i
19
+ [location["lines"]["begin"].to_i]
20
20
  when location["positions"] && location["positions"]["begin"]["line"]
21
- location["positions"]["begin"]["line"].to_i + location["positions"]["begin"]["column"].to_i
21
+ [location["positions"]["begin"]["line"].to_i, location["positions"]["begin"]["column"].to_i]
22
22
  when location["positions"] && location["positions"]["begin"]["offset"]
23
- location["positions"]["begin"]["offset"].to_i + 1_000_000_000 # push offsets to end of list
23
+ [1_000_000_000] # push offsets to end of list
24
24
  else
25
- 0 # whole-file issues are first
25
+ [0] # whole-file issues are first
26
26
  end
27
27
  end
28
28
  end
@@ -0,0 +1,27 @@
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
@@ -0,0 +1,60 @@
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 raise_if_any_unreadable_files
11
+ paths.each do |path|
12
+ if !File.directory?(path) && !FileUtils.readable_by_all?(path)
13
+ raise CC::Analyzer::UnreadableFileError, "Can't read #{path}"
14
+ end
15
+ end
16
+
17
+ self
18
+ end
19
+
20
+ def reject_unreadable_paths
21
+ @paths = paths - unreadable_path_entries
22
+ self
23
+ end
24
+
25
+ def reject_paths(ignore_paths)
26
+ @paths = paths - ignore_paths
27
+ self
28
+ end
29
+
30
+ def select_readable_files
31
+ @paths = paths.select { |path| FileUtils.readable_by_all?(path) }
32
+ self
33
+ end
34
+
35
+ def reject_symlinks
36
+ @paths = paths.reject { |path| File.symlink?(path) }
37
+ self
38
+ end
39
+
40
+ def reject_globs(globs)
41
+ patterns = PathPatterns.new(globs)
42
+ @paths = paths.reject { |path| patterns.match?(pathpatterns.match?(path)) }
43
+ self
44
+ end
45
+
46
+ private
47
+
48
+ def unreadable_path_entries
49
+ @_unreadable_path_entries ||=
50
+ unreadable_paths.flat_map { |path| PathEntries.new(path).entries }
51
+ end
52
+
53
+ def unreadable_paths
54
+ paths.select do |path|
55
+ File.directory?(path) && !FileUtils.readable_by_all?(path)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,84 @@
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
@@ -6,6 +6,10 @@ module CC
6
6
  @root = root
7
7
  end
8
8
 
9
+ def match?(path)
10
+ expanded.include?(path)
11
+ end
12
+
9
13
  def expanded
10
14
  @expanded ||= expand
11
15
  end
@@ -15,25 +19,28 @@ module CC
15
19
  def expand
16
20
  results = Dir.chdir(@root) do
17
21
  @patterns.flat_map do |pattern|
18
- # FIXME: there exists a temporary workaround whereby **-style globs
19
- # are translated to **/*-style globs within cc-yaml's custom
20
- # Glob#value method. It was thought that that would work correctly
21
- # with Dir.glob but it turns out we have to actually invoke #value
22
- # directory for this to work. We need to guard this on class (not
23
- # respond_to?) because our mocking framework adds a #value method to
24
- # all objects, apparently.
25
- if pattern.is_a?(CC::Yaml::Nodes::Glob)
26
- value = pattern.value
27
- else
28
- value = pattern
29
- end
30
-
22
+ value = glob_value(pattern)
31
23
  Dir.glob(value)
32
24
  end
33
25
  end
34
26
 
35
27
  results.sort.uniq
36
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
37
44
  end
38
45
  end
39
46
  end
@@ -24,6 +24,10 @@ module CC
24
24
  run
25
25
  end
26
26
 
27
+ def success(message)
28
+ terminal.say colorize(message, :green)
29
+ end
30
+
27
31
  def say(message)
28
32
  terminal.say message
29
33
  end
data/lib/cc/cli/help.rb CHANGED
@@ -14,7 +14,7 @@ module CC
14
14
 
15
15
  def commands
16
16
  [
17
- "analyze [-f format]",
17
+ "analyze [-f format] [-e engine] <path>",
18
18
  "console",
19
19
  "engines:disable #{underline('engine_name')}",
20
20
  "engines:enable #{underline('engine_name')}",
data/lib/cc/cli/init.rb CHANGED
@@ -9,7 +9,8 @@ module CC
9
9
 
10
10
  def run
11
11
  if !upgrade? && filesystem.exist?(CODECLIMATE_YAML)
12
- fatal "Config file .codeclimate.yml already present.\nTry running 'validate-config' to check configuration."
12
+ warn "Config file .codeclimate.yml already present.\nTry running 'validate-config' to check configuration."
13
+ create_default_configs
13
14
  elsif upgrade? && engines_enabled?
14
15
  fatal "--upgrade should not be used on a .codeclimate.yml configured for the Platform.\nTry running 'validate-config' to check configuration."
15
16
  else
@@ -32,7 +33,7 @@ module CC
32
33
  end
33
34
 
34
35
  create_codeclimate_yaml
35
- say "Config file .codeclimate.yml successfully #{config_generator.post_generation_verb}.\nEdit and then try running 'validate-config' to check configuration."
36
+ success "Config file .codeclimate.yml successfully #{config_generator.post_generation_verb}.\nEdit and then try running 'validate-config' to check configuration."
36
37
  create_default_configs
37
38
  end
38
39
 
@@ -54,7 +55,7 @@ module CC
54
55
  say "Skipping generating #{file_name} file (already exists)."
55
56
  else
56
57
  filesystem.write_path(file_name, File.read(config_path))
57
- say "Config file #{file_name} successfully generated."
58
+ success "Config file #{file_name} successfully generated."
58
59
  end
59
60
  end
60
61
  end
data/lib/cc/cli/test.rb CHANGED
@@ -163,7 +163,7 @@ module CC
163
163
  def validate_unexpected_issues(actual_issues)
164
164
  if actual_issues.any?
165
165
  say colorize("Actuals not empty after matching.", :red)
166
- say
166
+ say "\n"
167
167
  say colorize("#{actual_issues.size} remaining:", :yellow)
168
168
  say colorize(JSON.pretty_generate(actual_issues), :yellow)
169
169
  fatal "Unexpected issue found."
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.14.2
4
+ version: 0.14.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code Climate
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-10 00:00:00.000000000 Z
11
+ date: 2015-11-19 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.5.0
53
+ version: 0.6.1
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.5.0
60
+ version: 0.6.1
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: faraday
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -218,6 +218,9 @@ files:
218
218
  - lib/cc/analyzer/issue_sorter.rb
219
219
  - lib/cc/analyzer/location_description.rb
220
220
  - lib/cc/analyzer/logging_container_listener.rb
221
+ - lib/cc/analyzer/path_entries.rb
222
+ - lib/cc/analyzer/path_filter.rb
223
+ - lib/cc/analyzer/path_minimizer.rb
221
224
  - lib/cc/analyzer/path_patterns.rb
222
225
  - lib/cc/analyzer/raising_container_listener.rb
223
226
  - lib/cc/analyzer/source_buffer.rb