codeclimate-fede 0.85.23

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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/bin/check +18 -0
  3. data/bin/codeclimate +21 -0
  4. data/bin/prep-release +45 -0
  5. data/bin/release +41 -0
  6. data/bin/validate-release +18 -0
  7. data/config/engines.yml +322 -0
  8. data/lib/cc/analyzer.rb +50 -0
  9. data/lib/cc/analyzer/bridge.rb +106 -0
  10. data/lib/cc/analyzer/composite_container_listener.rb +21 -0
  11. data/lib/cc/analyzer/container.rb +208 -0
  12. data/lib/cc/analyzer/container/result.rb +74 -0
  13. data/lib/cc/analyzer/container_listener.rb +9 -0
  14. data/lib/cc/analyzer/engine.rb +125 -0
  15. data/lib/cc/analyzer/engine_output.rb +74 -0
  16. data/lib/cc/analyzer/engine_output_filter.rb +36 -0
  17. data/lib/cc/analyzer/engine_output_overrider.rb +31 -0
  18. data/lib/cc/analyzer/filesystem.rb +50 -0
  19. data/lib/cc/analyzer/formatters.rb +21 -0
  20. data/lib/cc/analyzer/formatters/formatter.rb +53 -0
  21. data/lib/cc/analyzer/formatters/html_formatter.rb +415 -0
  22. data/lib/cc/analyzer/formatters/json_formatter.rb +38 -0
  23. data/lib/cc/analyzer/formatters/plain_text_formatter.rb +101 -0
  24. data/lib/cc/analyzer/formatters/spinner.rb +35 -0
  25. data/lib/cc/analyzer/issue.rb +69 -0
  26. data/lib/cc/analyzer/issue_sorter.rb +30 -0
  27. data/lib/cc/analyzer/issue_validations.rb +26 -0
  28. data/lib/cc/analyzer/issue_validations/category_validation.rb +32 -0
  29. data/lib/cc/analyzer/issue_validations/check_name_presence_validation.rb +15 -0
  30. data/lib/cc/analyzer/issue_validations/content_validation.rb +21 -0
  31. data/lib/cc/analyzer/issue_validations/description_presence_validation.rb +15 -0
  32. data/lib/cc/analyzer/issue_validations/location_format_validation.rb +72 -0
  33. data/lib/cc/analyzer/issue_validations/other_locations_format_validation.rb +41 -0
  34. data/lib/cc/analyzer/issue_validations/path_existence_validation.rb +15 -0
  35. data/lib/cc/analyzer/issue_validations/path_is_file_validation.rb +15 -0
  36. data/lib/cc/analyzer/issue_validations/path_presence_validation.rb +15 -0
  37. data/lib/cc/analyzer/issue_validations/relative_path_validation.rb +32 -0
  38. data/lib/cc/analyzer/issue_validations/remediation_points_validation.rb +25 -0
  39. data/lib/cc/analyzer/issue_validations/severity_validation.rb +39 -0
  40. data/lib/cc/analyzer/issue_validations/type_validation.rb +15 -0
  41. data/lib/cc/analyzer/issue_validations/validation.rb +35 -0
  42. data/lib/cc/analyzer/issue_validator.rb +11 -0
  43. data/lib/cc/analyzer/location_description.rb +45 -0
  44. data/lib/cc/analyzer/logging_container_listener.rb +24 -0
  45. data/lib/cc/analyzer/measurement.rb +22 -0
  46. data/lib/cc/analyzer/measurement_validations.rb +16 -0
  47. data/lib/cc/analyzer/measurement_validations/name_validation.rb +23 -0
  48. data/lib/cc/analyzer/measurement_validations/type_validation.rb +15 -0
  49. data/lib/cc/analyzer/measurement_validations/validation.rb +27 -0
  50. data/lib/cc/analyzer/measurement_validations/value_validation.rb +21 -0
  51. data/lib/cc/analyzer/measurement_validator.rb +11 -0
  52. data/lib/cc/analyzer/mounted_path.rb +80 -0
  53. data/lib/cc/analyzer/raising_container_listener.rb +32 -0
  54. data/lib/cc/analyzer/source_buffer.rb +47 -0
  55. data/lib/cc/analyzer/source_extractor.rb +79 -0
  56. data/lib/cc/analyzer/source_fingerprint.rb +40 -0
  57. data/lib/cc/analyzer/statsd_container_listener.rb +51 -0
  58. data/lib/cc/analyzer/validator.rb +38 -0
  59. data/lib/cc/cli.rb +39 -0
  60. data/lib/cc/cli/analyze.rb +90 -0
  61. data/lib/cc/cli/analyze/engine_failure.rb +11 -0
  62. data/lib/cc/cli/command.rb +85 -0
  63. data/lib/cc/cli/console.rb +12 -0
  64. data/lib/cc/cli/engines.rb +5 -0
  65. data/lib/cc/cli/engines/engine_command.rb +15 -0
  66. data/lib/cc/cli/engines/install.rb +35 -0
  67. data/lib/cc/cli/engines/list.rb +18 -0
  68. data/lib/cc/cli/file_store.rb +42 -0
  69. data/lib/cc/cli/global_cache.rb +47 -0
  70. data/lib/cc/cli/global_config.rb +35 -0
  71. data/lib/cc/cli/help.rb +51 -0
  72. data/lib/cc/cli/output.rb +34 -0
  73. data/lib/cc/cli/prepare.rb +98 -0
  74. data/lib/cc/cli/runner.rb +75 -0
  75. data/lib/cc/cli/validate_config.rb +84 -0
  76. data/lib/cc/cli/version.rb +16 -0
  77. data/lib/cc/cli/version_checker.rb +107 -0
  78. data/lib/cc/config.rb +70 -0
  79. data/lib/cc/config/checks_adapter.rb +40 -0
  80. data/lib/cc/config/default_adapter.rb +54 -0
  81. data/lib/cc/config/engine.rb +41 -0
  82. data/lib/cc/config/engine_set.rb +47 -0
  83. data/lib/cc/config/json_adapter.rb +17 -0
  84. data/lib/cc/config/prepare.rb +92 -0
  85. data/lib/cc/config/validation/check_validator.rb +34 -0
  86. data/lib/cc/config/validation/engine_validator.rb +93 -0
  87. data/lib/cc/config/validation/fetch_validator.rb +78 -0
  88. data/lib/cc/config/validation/file_validator.rb +112 -0
  89. data/lib/cc/config/validation/hash_validations.rb +52 -0
  90. data/lib/cc/config/validation/json.rb +31 -0
  91. data/lib/cc/config/validation/prepare_validator.rb +40 -0
  92. data/lib/cc/config/validation/yaml.rb +66 -0
  93. data/lib/cc/config/yaml_adapter.rb +73 -0
  94. data/lib/cc/engine_registry.rb +74 -0
  95. data/lib/cc/resolv.rb +39 -0
  96. data/lib/cc/workspace.rb +39 -0
  97. data/lib/cc/workspace/exclusion.rb +34 -0
  98. data/lib/cc/workspace/path_tree.rb +49 -0
  99. data/lib/cc/workspace/path_tree/dir_node.rb +67 -0
  100. data/lib/cc/workspace/path_tree/file_node.rb +31 -0
  101. metadata +277 -0
@@ -0,0 +1,21 @@
1
+ module CC
2
+ module Analyzer
3
+ module MeasurementValidations
4
+ class ValueValidation < Validation
5
+ def valid?
6
+ value&.is_a?(Numeric)
7
+ end
8
+
9
+ def message
10
+ "Value must be present and numeric"
11
+ end
12
+
13
+ private
14
+
15
+ def value
16
+ object["value"]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module CC
2
+ module Analyzer
3
+ class MeasurementValidator
4
+ include Validator
5
+
6
+ def self.validations
7
+ MeasurementValidations.validations
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,80 @@
1
+ module CC
2
+ module Analyzer
3
+ class MountedPath
4
+ DEFAULT_CODECLIMATE_TMP = "/tmp/cc".freeze
5
+
6
+ def self.code
7
+ host_prefix = ENV["CODECLIMATE_CODE"]
8
+ host_prefix ||= ENV["CODE_PATH"] # deprecated
9
+
10
+ if ENV["CODECLIMATE_DOCKER"]
11
+ new(host_prefix, "/code")
12
+ else
13
+ host_prefix ||= Dir.pwd
14
+
15
+ new(host_prefix, host_prefix)
16
+ end
17
+ end
18
+
19
+ def self.tmp
20
+ host_prefix = ENV["CODECLIMATE_TMP"]
21
+ host_prefix ||= DEFAULT_CODECLIMATE_TMP
22
+
23
+ if ENV["CODECLIMATE_DOCKER"]
24
+ new(host_prefix, "/tmp/cc")
25
+ else
26
+ new(host_prefix, host_prefix)
27
+ end
28
+ end
29
+
30
+ def initialize(host_prefix, container_prefix, path = nil)
31
+ @host_prefix = host_prefix
32
+ @container_prefix = container_prefix
33
+ @path = path
34
+ end
35
+
36
+ def host_path
37
+ if path
38
+ File.join(host_prefix, path)
39
+ else
40
+ host_prefix
41
+ end
42
+ end
43
+
44
+ def container_path
45
+ if path
46
+ File.join(container_prefix, path)
47
+ else
48
+ container_prefix
49
+ end
50
+ end
51
+
52
+ def join(path)
53
+ @path = path
54
+
55
+ self
56
+ end
57
+
58
+ def file?
59
+ File.file?(container_path)
60
+ end
61
+
62
+ def read
63
+ File.read(container_path)
64
+ end
65
+
66
+ def write(content)
67
+ FileUtils.mkdir_p(File.dirname(container_path))
68
+ File.write(container_path, content)
69
+ end
70
+
71
+ def delete
72
+ File.delete(container_path)
73
+ end
74
+
75
+ private
76
+
77
+ attr_reader :host_prefix, :container_prefix, :path
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,32 @@
1
+ module CC
2
+ module Analyzer
3
+ class RaisingContainerListener < ContainerListener
4
+ def initialize(failure_ex, timeout_ex = nil, maximum_output_ex = nil)
5
+ @failure_ex = failure_ex
6
+ @timeout_ex = timeout_ex || failure_ex
7
+ @maximum_output_ex = maximum_output_ex || failure_ex
8
+ end
9
+
10
+ def finished(engine, _details, result)
11
+ if result.timed_out?
12
+ message = "engine #{engine.name} ran for #{result.duration / 1000}"
13
+ message << " seconds and was killed"
14
+ raise timeout_ex.new(message, engine.name)
15
+ elsif result.maximum_output_exceeded?
16
+ message = "engine #{engine.name} produced too much output"
17
+ message << " (#{result.output_byte_count} bytes)"
18
+ raise maximum_output_ex.new(message, engine.name)
19
+ elsif result.exit_status.nonzero?
20
+ message = "engine #{engine.name} failed"
21
+ message << " with status #{result.exit_status}"
22
+ message << " and stderr \n#{result.stderr}"
23
+ raise failure_ex.new(message, engine.name)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :failure_ex, :timeout_ex, :maximum_output_ex
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,47 @@
1
+ # Adapted from https://github.com/whitequark/parser/blob/master/lib/parser/source/buffer.rb
2
+ module CC
3
+ module Analyzer
4
+ class SourceBuffer
5
+ attr_reader :name
6
+ attr_reader :source
7
+
8
+ def initialize(name, source)
9
+ @name = name
10
+ @source = source
11
+ end
12
+
13
+ def decompose_position(position)
14
+ line_no, line_begin = line_for(position)
15
+
16
+ [1 + line_no, position - line_begin]
17
+ end
18
+
19
+ def line_count
20
+ @source.lines.count
21
+ end
22
+
23
+ private
24
+
25
+ def line_for(position)
26
+ line_begins.bsearch do |_, line_begin|
27
+ line_begin <= position
28
+ end
29
+ end
30
+
31
+ def line_begins
32
+ unless @line_begins
33
+ @line_begins = [[0, 0]]
34
+ index = 1
35
+
36
+ @source.each_char do |char|
37
+ @line_begins.unshift [@line_begins.length, index] if char == "\n"
38
+
39
+ index += 1
40
+ end
41
+ end
42
+
43
+ @line_begins
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,79 @@
1
+ module CC
2
+ module Analyzer
3
+ class SourceExtractor
4
+ InvalidLocation = Class.new(StandardError)
5
+
6
+ def initialize(source)
7
+ @source = source
8
+ end
9
+
10
+ def extract(location)
11
+ validate_location(location)
12
+
13
+ if (lines = location["lines"])
14
+ extract_from_lines(lines)
15
+ elsif (positions = location["positions"])
16
+ extract_from_positions(positions)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :source
23
+
24
+ def validate_location(location)
25
+ validator = IssueValidations::LocationFormatValidation::Validator.new(location)
26
+ unless validator.valid?
27
+ raise InvalidLocation, validator.message
28
+ end
29
+ end
30
+
31
+ def extract_from_lines(lines)
32
+ begin_index = lines.fetch("begin") - 1
33
+ end_index = lines.fetch("end") - 1
34
+ range = (begin_index..end_index)
35
+
36
+ source.each_line.with_object("").with_index do |(source_line, memo), index|
37
+ memo << source_line if range.include?(index)
38
+ end
39
+ end
40
+
41
+ def extract_from_positions(positions)
42
+ positions = convert_to_offsets(positions)
43
+ begin_offset = positions.fetch("begin").fetch("offset")
44
+ end_offset = positions.fetch("end").fetch("offset")
45
+ length = end_offset - begin_offset
46
+
47
+ source[begin_offset, length + 1]
48
+ end
49
+
50
+ def convert_to_offsets(positions)
51
+ positions.each_with_object({}) do |(key, value), memo|
52
+ memo[key] =
53
+ if value.key?("offset")
54
+ value
55
+ else
56
+ {
57
+ "offset" => to_offset(value["line"] - 1, value["column"] - 1),
58
+ }
59
+ end
60
+ end
61
+ end
62
+
63
+ def to_offset(line, column, offset = 0)
64
+ source.each_line.with_index do |source_line, index|
65
+ offset +=
66
+ if line == index
67
+ column
68
+ else
69
+ source_line.length
70
+ end
71
+
72
+ break if index >= line
73
+ end
74
+
75
+ offset
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,40 @@
1
+ require "digest/md5"
2
+
3
+ module CC
4
+ module Analyzer
5
+ class SourceFingerprint
6
+ def initialize(issue)
7
+ @issue = issue
8
+ end
9
+
10
+ def compute
11
+ md5 = Digest::MD5.new
12
+ md5 << issue.path
13
+ md5 << issue.check_name.to_s
14
+ md5 << relevant_source.gsub(/\s+/, "") if relevant_source
15
+ md5.hexdigest
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :issue
21
+
22
+ def relevant_source
23
+ source = SourceExtractor.new(raw_source).extract(issue.location)
24
+
25
+ if source && !source.empty?
26
+ source.encode(Encoding::UTF_8, "binary", invalid: :replace, undef: :replace, replace: "")
27
+ end
28
+ end
29
+
30
+ def raw_source
31
+ @raw_source ||=
32
+ if File.file?(issue.path)
33
+ File.read(issue.path)
34
+ else
35
+ ""
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,51 @@
1
+ module CC
2
+ module Analyzer
3
+ class StatsdContainerListener < ContainerListener
4
+ def initialize(statsd)
5
+ @statsd = statsd
6
+ end
7
+
8
+ def started(engine, _details)
9
+ increment(engine, "started")
10
+ end
11
+
12
+ def finished(engine, _details, result)
13
+ timing(engine, "time", result.duration)
14
+ increment(engine, "finished")
15
+
16
+ if result.timed_out?
17
+ timing(engine, "time", result.duration)
18
+ increment(engine, "result.error")
19
+ increment(engine, "result.error.timeout")
20
+ elsif result.maximum_output_exceeded?
21
+ increment(engine, "result.error")
22
+ increment(engine, "result.error.output_exceeded")
23
+ elsif result.exit_status.nonzero?
24
+ increment(engine, "result.error")
25
+ else
26
+ increment(engine, "result.success")
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :statsd
33
+
34
+ def increment(engine, metric)
35
+ statsd.increment("engines.#{metric}")
36
+ statsd.increment("engines.names.#{engine.name}.#{metric}")
37
+ if engine.respond_to?(:channel) && engine.channel
38
+ statsd.increment("engines.names.#{engine.name}.#{engine.channel}.#{metric}")
39
+ end
40
+ end
41
+
42
+ def timing(engine, metric, ms)
43
+ statsd.timing("engines.#{metric}", ms)
44
+ statsd.timing("engines.names.#{engine.name}.#{metric}", ms)
45
+ if engine.respond_to?(:channel) && engine.channel
46
+ statsd.timing("engines.names.#{engine.name}.#{engine.channel}.#{metric}", ms)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,38 @@
1
+ module CC
2
+ module Analyzer
3
+ module Validator
4
+ attr_reader :error
5
+
6
+ def initialize(document)
7
+ @document = document
8
+ validate
9
+ end
10
+
11
+ def validate
12
+ return @valid unless @valid.nil?
13
+
14
+ if document && invalid_messages.any?
15
+ @error = {
16
+ message: "#{invalid_messages.join("; ")}: `#{document}`.",
17
+ document: document,
18
+ }
19
+ @valid = false
20
+ else
21
+ @valid = true
22
+ end
23
+ end
24
+ alias valid? validate
25
+
26
+ private
27
+
28
+ attr_reader :document
29
+
30
+ def invalid_messages
31
+ @invalid_messages ||= self.class.validations.each_with_object([]) do |check, result|
32
+ validator = check.new(document)
33
+ result << validator.message unless validator.valid?
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
data/lib/cc/cli.rb ADDED
@@ -0,0 +1,39 @@
1
+ require "active_support"
2
+ require "active_support/core_ext"
3
+ require "yaml"
4
+ require "cc/analyzer"
5
+ require "cc/config"
6
+ require "cc/engine_registry"
7
+ require "cc/workspace"
8
+
9
+ require "cc/cli/analyze"
10
+ require "cc/cli/command"
11
+ require "cc/cli/console"
12
+ require "cc/cli/engines"
13
+ require "cc/cli/help"
14
+ require "cc/cli/output"
15
+ require "cc/cli/prepare"
16
+ require "cc/cli/runner"
17
+ require "cc/cli/validate_config"
18
+ require "cc/cli/version"
19
+
20
+ module CC
21
+ module CLI
22
+ def self.debug?
23
+ ENV["CODECLIMATE_DEBUG"].present?
24
+ end
25
+
26
+ def self.logger
27
+ @logger ||= ::Logger.new(STDERR).tap do |logger|
28
+ logger.level =
29
+ if debug?
30
+ ::Logger::DEBUG
31
+ else
32
+ ::Logger::ERROR
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ Analyzer.logger = CLI.logger
39
+ end