codeclimate-fede 0.85.23

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