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,38 @@
1
+ module CC
2
+ module Analyzer
3
+ module Formatters
4
+ class JSONFormatter < Formatter
5
+ def initialize(filesystem)
6
+ @filesystem = filesystem
7
+ @has_begun = false
8
+ end
9
+
10
+ def started
11
+ print "["
12
+ end
13
+
14
+ def finished
15
+ print "]\n"
16
+ end
17
+
18
+ def write(data)
19
+ document = JSON.parse(data)
20
+ document["engine_name"] = current_engine.name
21
+
22
+ if @has_begun
23
+ print ",\n"
24
+ end
25
+
26
+ print document.to_json
27
+ @has_begun = true
28
+ end
29
+
30
+ def failed(output)
31
+ $stderr.puts "\nAnalysis failed with the following output:"
32
+ $stderr.puts output
33
+ exit 1
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,101 @@
1
+ require "rainbow"
2
+ require "tty/spinner"
3
+ require "active_support/number_helper"
4
+
5
+ module CC
6
+ module Analyzer
7
+ module Formatters
8
+ class PlainTextFormatter < Formatter
9
+ def started
10
+ puts colorize("Starting analysis", :green)
11
+ end
12
+
13
+ def finished
14
+ puts
15
+
16
+ issues_by_path.each do |path, file_issues|
17
+ puts colorize("== #{path} (#{pluralize(file_issues.size, "issue")}) ==", :yellow)
18
+
19
+ IssueSorter.new(file_issues).by_location.each do |issue|
20
+ if (location = issue["location"])
21
+ source_buffer = @filesystem.source_buffer_for(location["path"])
22
+ print(colorize(LocationDescription.new(source_buffer, location, ": "), :cyan))
23
+ end
24
+
25
+ print(issue["description"])
26
+ print(colorize(" [#{issue["engine_name"]}]", "#333333"))
27
+ puts
28
+ end
29
+ puts
30
+ end
31
+
32
+ print(colorize("Analysis complete! Found #{pluralize(issues.size, "issue")}", :green))
33
+ unless warnings.empty?
34
+ print(colorize(" and #{pluralize(warnings.size, "warning")}", :green))
35
+ end
36
+ puts(colorize(".", :green))
37
+ end
38
+
39
+ def engine_running(engine, &block)
40
+ super(engine) do
41
+ result = with_spinner("Running #{current_engine.name}: ", &block)
42
+ if result.skipped?
43
+ puts(colorize("Skipped #{current_engine.name}: #{result.stderr}", :yellow))
44
+ end
45
+ end
46
+ end
47
+
48
+ def failed(output)
49
+ spinner.stop("Failed")
50
+ puts colorize("\nAnalysis failed with the following output:", :red)
51
+ puts output
52
+ exit 1
53
+ end
54
+
55
+ private
56
+
57
+ def spinner(text = nil)
58
+ @spinner ||= Spinner.new(text)
59
+ end
60
+
61
+ def with_spinner(text)
62
+ spinner(text).start
63
+ yield
64
+ ensure
65
+ spinner.stop
66
+ @spinner = nil
67
+ end
68
+
69
+ def colorize(string, *args)
70
+ rainbow.wrap(string).color(*args)
71
+ end
72
+
73
+ def rainbow
74
+ @rainbow ||= Rainbow.new.tap do |rainbow|
75
+ rainbow.enabled = false unless @output.tty?
76
+ end
77
+ end
78
+
79
+ def issues
80
+ @issues ||= []
81
+ end
82
+
83
+ def issues_by_path
84
+ issues.group_by { |i| i["location"]["path"] }.sort
85
+ end
86
+
87
+ def warnings
88
+ @warnings ||= []
89
+ end
90
+
91
+ def measurements
92
+ @measurements ||= []
93
+ end
94
+
95
+ def pluralize(number, noun)
96
+ "#{ActiveSupport::NumberHelper.number_to_delimited(number)} #{noun.pluralize(number)}"
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,35 @@
1
+ module CC
2
+ module Analyzer
3
+ module Formatters
4
+ class Spinner
5
+ def initialize(text)
6
+ @spinner = TTY::Spinner.new(text)
7
+ end
8
+
9
+ def start
10
+ return unless $stdout.tty? && !CLI.debug?
11
+ @thread = Thread.new do
12
+ loop do
13
+ @spinning = true
14
+ spinner.spin
15
+ sleep 0.075
16
+ end
17
+ end
18
+ end
19
+
20
+ def stop(text = "Done!")
21
+ if @spinning
22
+ spinner.stop(text)
23
+ print("\n")
24
+ @thread.kill
25
+ end
26
+ @spinning = false
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :spinner
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,69 @@
1
+ module CC
2
+ module Analyzer
3
+ class Issue
4
+ DEFAULT_SEVERITY = IssueValidations::SeverityValidation::MINOR
5
+ DEPRECATED_SEVERITY = IssueValidations::SeverityValidation::NORMAL
6
+
7
+ SPEC_ISSUE_ATTRIBUTES = %w[
8
+ categories
9
+ check_name
10
+ content
11
+ description
12
+ location
13
+ other_locations
14
+ remediation_points
15
+ severity
16
+ type
17
+ ]
18
+
19
+ def initialize(engine_name, output)
20
+ @engine_name = engine_name
21
+ @output = output
22
+ end
23
+
24
+ def as_json(*)
25
+ parsed_output.reverse_merge!(
26
+ "engine_name" => engine_name,
27
+ "fingerprint" => fingerprint,
28
+ ).merge!("severity" => severity)
29
+ end
30
+
31
+ def fingerprint
32
+ parsed_output.fetch("fingerprint") { default_fingerprint }
33
+ end
34
+
35
+ # Allow access to hash keys as methods
36
+ SPEC_ISSUE_ATTRIBUTES.each do |key|
37
+ define_method(key) do
38
+ parsed_output[key]
39
+ end
40
+ end
41
+
42
+ def path
43
+ parsed_output.fetch("location", {}).fetch("path", "")
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :engine_name, :output
49
+
50
+ def default_fingerprint
51
+ SourceFingerprint.new(self).compute
52
+ end
53
+
54
+ def severity
55
+ severity = parsed_output.fetch("severity", DEFAULT_SEVERITY)
56
+
57
+ if severity == DEPRECATED_SEVERITY
58
+ DEFAULT_SEVERITY
59
+ else
60
+ severity
61
+ end
62
+ end
63
+
64
+ def parsed_output
65
+ @parsed_output ||= JSON.parse(output)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,30 @@
1
+ module CC
2
+ module Analyzer
3
+ class IssueSorter
4
+ def initialize(issues)
5
+ @issues = issues
6
+ end
7
+
8
+ def by_location
9
+ @issues.sort_by { |i| line_or_offset(i) }
10
+ end
11
+
12
+ private
13
+
14
+ def line_or_offset(issue)
15
+ location = issue["location"]
16
+
17
+ case
18
+ when location["lines"]
19
+ [location["lines"]["begin"].to_i]
20
+ when location["positions"] && location["positions"]["begin"]["line"]
21
+ [location["positions"]["begin"]["line"].to_i, location["positions"]["begin"]["column"].to_i]
22
+ when location["positions"] && location["positions"]["begin"]["offset"]
23
+ [1_000_000_000] # push offsets to end of list
24
+ else
25
+ [0] # whole-file issues are first
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ autoload :CategoryValidation, "cc/analyzer/issue_validations/category_validation"
5
+ autoload :CheckNamePresenceValidation, "cc/analyzer/issue_validations/check_name_presence_validation"
6
+ autoload :ContentValidation, "cc/analyzer/issue_validations/content_validation"
7
+ autoload :DescriptionPresenceValidation, "cc/analyzer/issue_validations/description_presence_validation"
8
+ autoload :LocationFormatValidation, "cc/analyzer/issue_validations/location_format_validation"
9
+ autoload :OtherLocationsFormatValidation, "cc/analyzer/issue_validations/other_locations_format_validation"
10
+ autoload :PathExistenceValidation, "cc/analyzer/issue_validations/path_existence_validation"
11
+ autoload :PathIsFileValidation, "cc/analyzer/issue_validations/path_is_file_validation"
12
+ autoload :PathPresenceValidation, "cc/analyzer/issue_validations/path_presence_validation"
13
+ autoload :RelativePathValidation, "cc/analyzer/issue_validations/relative_path_validation"
14
+ autoload :RemediationPointsValidation, "cc/analyzer/issue_validations/remediation_points_validation"
15
+ autoload :SeverityValidation, "cc/analyzer/issue_validations/severity_validation"
16
+ autoload :TypeValidation, "cc/analyzer/issue_validations/type_validation"
17
+ autoload :Validation, "cc/analyzer/issue_validations/validation"
18
+
19
+ def self.validations
20
+ constants.sort.map(&method(:const_get)).select do |klass|
21
+ klass.is_a?(Class) && klass.superclass == Validation
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class CategoryValidation < Validation
5
+ CATEGORIES = [
6
+ "Bug Risk".freeze,
7
+ "Clarity".freeze,
8
+ "Compatibility".freeze,
9
+ "Complexity".freeze,
10
+ "Duplication".freeze,
11
+ "Performance".freeze,
12
+ "Security".freeze,
13
+ "Style".freeze,
14
+ ].freeze
15
+
16
+ def valid?
17
+ object["categories"].present? && no_invalid_categories?
18
+ end
19
+
20
+ def message
21
+ "Category must be at least one of #{CATEGORIES.join(", ")}"
22
+ end
23
+
24
+ private
25
+
26
+ def no_invalid_categories?
27
+ (CATEGORIES | object["categories"]) == CATEGORIES
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class CheckNamePresenceValidation < Validation
5
+ def valid?
6
+ object["check_name"].present?
7
+ end
8
+
9
+ def message
10
+ "Check name must be present"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class ContentValidation < Validation
5
+ def valid?
6
+ !has_content? || (content.is_a?(Hash) && content["body"].is_a?(String))
7
+ end
8
+
9
+ def message
10
+ "Content must be a hash containing a 'body' key with string contents"
11
+ end
12
+
13
+ private
14
+
15
+ def has_content?
16
+ object.key?("content")
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class DescriptionPresenceValidation < Validation
5
+ def valid?
6
+ object["description"].present?
7
+ end
8
+
9
+ def message
10
+ "Description must be present"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,72 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class LocationFormatValidation < Validation
5
+ class Validator
6
+ def initialize(location)
7
+ @location = location
8
+ check_validity
9
+ end
10
+
11
+ def valid?
12
+ error.nil?
13
+ end
14
+
15
+ def message
16
+ if error
17
+ "Location is not formatted correctly: #{error}"
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_accessor :error
24
+
25
+ attr_reader :location
26
+
27
+ def check_validity
28
+ if location["lines"]
29
+ self.error = "location.lines is not valid: #{JSON.dump(location["lines"])}" unless valid_lines?(location["lines"])
30
+ elsif location["positions"]
31
+ self.error = "location.positions is not valid: #{JSON.dump(location["positions"])}" unless valid_positions?(location["positions"])
32
+ else
33
+ self.error = "location.lines or location.positions must be present"
34
+ end
35
+ end
36
+
37
+ def valid_positions?(positions)
38
+ positions.is_a?(Hash) &&
39
+ valid_position?(positions["begin"]) &&
40
+ valid_position?(positions["end"])
41
+ end
42
+
43
+ def valid_position?(position)
44
+ position &&
45
+ (
46
+ [position["line"], position["column"]].all? { |value| value.is_a?(Integer) } ||
47
+ position["offset"].is_a?(Integer)
48
+ )
49
+ end
50
+
51
+ def valid_lines?(lines)
52
+ lines.is_a?(Hash) && [lines["begin"], lines["end"]].all? { |value| value.is_a?(Integer) }
53
+ end
54
+ end
55
+
56
+ def valid?
57
+ validation.valid?
58
+ end
59
+
60
+ def message
61
+ validation.message
62
+ end
63
+
64
+ private
65
+
66
+ def validation
67
+ @validation ||= Validator.new(object.fetch("location", {}))
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end