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,112 @@
1
+ module CC
2
+ class Config
3
+ module Validation
4
+ class FileValidator
5
+ include HashValidations
6
+
7
+ attr_reader :errors, :path, :warnings
8
+
9
+ def initialize(path, registry)
10
+ @path = path
11
+ @registry = registry
12
+
13
+ @errors = []
14
+ @warnings = []
15
+
16
+ validate
17
+ end
18
+
19
+ def valid?
20
+ errors.none?
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :data, :registry
26
+
27
+ def validate
28
+ raise NotImplementedError, "use a subclass"
29
+ end
30
+
31
+ def denormalize_subvalidator(validator, prefix)
32
+ validator.errors.each do |msg|
33
+ errors << "#{prefix}: #{msg}"
34
+ end
35
+ validator.warnings.each do |msg|
36
+ warnings << "#{prefix}: #{msg}"
37
+ end
38
+ end
39
+
40
+ def validate_prepare
41
+ return unless validate_key_type("prepare", Hash)
42
+
43
+ validator = PrepareValidator.new(data.fetch("prepare", {}))
44
+ denormalize_subvalidator(validator, "prepare section")
45
+ end
46
+
47
+ def validate_engines(key, legacy: false)
48
+ return unless validate_key_type(key, Hash)
49
+
50
+ data.fetch(key, {}).each do |engine_name, engine_data|
51
+ engine_validator = EngineValidator.new(engine_data, legacy: legacy)
52
+ denormalize_subvalidator(engine_validator, "engine #{engine_name}")
53
+
54
+ if engine_validator.valid?
55
+ validate_engine_existence(engine_name, engine_data)
56
+ end
57
+ end
58
+ end
59
+
60
+ def validate_engine_existence(engine_name, engine_data)
61
+ if [true, false].include?(engine_data)
62
+ engine_data = {
63
+ "enabled" => true,
64
+ "channel" => Engine::DEFAULT_CHANNEL,
65
+ }
66
+ end
67
+
68
+ engine = Engine.new(
69
+ engine_name,
70
+ enabled: engine_data.fetch("enabled", true),
71
+ channel: engine_data["channel"],
72
+ config: engine_data["config"],
73
+ )
74
+ unless engine_exists?(engine)
75
+ warnings << "unknown engine or channel <#{engine.name}:#{engine.channel}>"
76
+ end
77
+ end
78
+
79
+ def engine_exists?(engine)
80
+ !registry.fetch_engine_details(engine).nil?
81
+ rescue CC::EngineRegistry::EngineDetailsNotFoundError
82
+ false
83
+ end
84
+
85
+ def validate_checks
86
+ return unless validate_key_type("checks", Hash)
87
+
88
+ data.fetch("checks", {}).each do |check_name, check_data|
89
+ validator = CheckValidator.new(check_data)
90
+ denormalize_subvalidator(validator, "check #{check_name}")
91
+ end
92
+ end
93
+
94
+ def validate_exclude_pattern(key, legacy: false)
95
+ types =
96
+ if legacy
97
+ [Array, String]
98
+ else
99
+ Array
100
+ end
101
+ return unless validate_key_type(key, types)
102
+
103
+ Array(data.fetch(key, [])).each do |pattern|
104
+ unless pattern.is_a?(String)
105
+ errors << "each exclude pattern should be a string, but '#{pattern.inspect}' is a #{pattern.class.to_s.downcase}"
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,52 @@
1
+ module CC
2
+ class Config
3
+ module Validation
4
+ module HashValidations
5
+ def validate_hash_data
6
+ unless data.is_a?(Hash)
7
+ errors << "Config file should contain a hash, not a #{data.class.to_s.downcase}"
8
+ return false
9
+ end
10
+ true
11
+ end
12
+
13
+ def validate_key_type(key, types)
14
+ if types.is_a?(Class)
15
+ return validate_key_type(key, [types])
16
+ elsif data.key?(key)
17
+ unless types.include?(data[key].class)
18
+ errors << key_type_error_message(key, types)
19
+ return false
20
+ end
21
+ end
22
+ true
23
+ end
24
+
25
+ def key_type_error_message(key, types)
26
+ if types.one?
27
+ klass_name = types[0].to_s.downcase
28
+ article =
29
+ if klass_name[0] == "a"
30
+ "an"
31
+ else
32
+ "a"
33
+ end
34
+ "'#{key}' must be #{article} #{klass_name}"
35
+ elsif types == [TrueClass, FalseClass]
36
+ "'#{key}' must be a boolean"
37
+ else
38
+ type_names = types.map(&:to_s).map(&:downcase)
39
+ "'#{key}' must be one of #{type_names.join(", ")}"
40
+ end
41
+ end
42
+
43
+ def warn_unrecognized_keys(recognized_keys)
44
+ unknown_keys = data.keys.reject { |k| recognized_keys.include?(k) }
45
+ unknown_keys.each do |key|
46
+ warnings << "unrecognized key '#{key}'"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+ module CC
2
+ class Config
3
+ module Validation
4
+ class JSON < FileValidator
5
+ private
6
+
7
+ def validate
8
+ @data = ::JSON.parse(File.read(path))
9
+
10
+ return unless validate_hash_data
11
+
12
+ validate_version
13
+ validate_prepare
14
+ validate_engines("plugins")
15
+ validate_checks
16
+ validate_exclude_pattern("exclude_patterns")
17
+
18
+ warn_unrecognized_keys(%w[checks prepare plugins exclude_patterns version])
19
+ rescue ::JSON::ParserError => ex
20
+ errors << "Unable to parse: #{ex.message}"
21
+ end
22
+
23
+ def validate_version
24
+ unless data.key?("version")
25
+ warnings << %(missing 'version' key. Please add `"version": "2"`)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ module CC
2
+ class Config
3
+ module Validation
4
+ class PrepareValidator
5
+ include HashValidations
6
+
7
+ attr_reader :errors, :warnings
8
+
9
+ def initialize(data)
10
+ @data = data
11
+
12
+ @errors = []
13
+ @warnings = []
14
+
15
+ validate
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :data
21
+
22
+ def validate
23
+ return unless validate_key_type("fetch", Array)
24
+
25
+ data.fetch("fetch", []).each do |fetch_data|
26
+ validator = FetchValidator.new(fetch_data)
27
+ validator.errors.each do |msg|
28
+ errors << msg
29
+ end
30
+ validator.warnings.each do |msg|
31
+ warnings << msg
32
+ end
33
+ end
34
+
35
+ warn_unrecognized_keys(%w[fetch])
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,66 @@
1
+ module CC
2
+ class Config
3
+ module Validation
4
+ class YAML < FileValidator
5
+ private
6
+
7
+ def validate
8
+ @data = ::YAML.safe_load(File.read(path))
9
+
10
+ return unless validate_hash_data
11
+
12
+ validate_version
13
+ validate_prepare
14
+
15
+ validate_one_of(%w[engines plugins])
16
+ validate_one_of(%w[exclude_paths exclude_patterns])
17
+
18
+ validate_engines("engines", legacy: true)
19
+ validate_engines("plugins")
20
+
21
+ validate_checks
22
+
23
+ validate_exclude_pattern("exclude_patterns")
24
+ validate_exclude_pattern("exclude_paths", legacy: true)
25
+
26
+ deprecated_key_warnings
27
+ warn_unrecognized_keys(%w[checks prepare engines plugins ratings languages exclude_paths exclude_patterns version])
28
+ rescue Psych::SyntaxError => ex
29
+ errors << "Unable to parse: #{ex.message}"
30
+ end
31
+
32
+ def validate_version
33
+ if !data.key?("version") && (data.key?("plugins") || data.key?("exclude_patterns"))
34
+ warnings << %(missing 'version' key. Please add `version: "2"`)
35
+ end
36
+ end
37
+
38
+ def validate_one_of(keys)
39
+ num = keys.map { |k| data.key?(k) }.select(&:present?).count
40
+ if num > 1
41
+ wrapped_keys = keys.map { |k| "'#{k}'" }
42
+ errors << "only use one of #{wrapped_keys.join(", ")}"
43
+ end
44
+ end
45
+
46
+ def deprecated_key_warnings
47
+ deprecate_key("engines", "plugins")
48
+ deprecate_key("exclude_paths", "exclude_patterns")
49
+ deprecate_key("languages")
50
+ deprecate_key("ratings")
51
+ end
52
+
53
+ def deprecate_key(key, new_key = nil)
54
+ if data.key?(key)
55
+ warnings <<
56
+ if new_key.nil?
57
+ "'#{key}' has been deprecated, and will not be used"
58
+ else
59
+ "'#{key}' has been deprecated, please use '#{new_key}' instead"
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,73 @@
1
+ module CC
2
+ class Config
3
+ class YAMLAdapter
4
+ DEFAULT_PATH = ".codeclimate.yml".freeze
5
+
6
+ attr_reader :config
7
+
8
+ def self.load(path = DEFAULT_PATH)
9
+ new(::YAML.safe_load(File.read(path)))
10
+ end
11
+
12
+ def initialize(yaml = {})
13
+ @config = yaml || {}
14
+
15
+ upconvert_legacy_yaml!
16
+ end
17
+
18
+ private
19
+
20
+ def coerce_engine(data)
21
+ if [true, false].include?(data)
22
+ { "enabled" => data }
23
+ elsif data.is_a?(Hash)
24
+ data
25
+ else
26
+ {}
27
+ end
28
+ end
29
+
30
+ # Many of our plugins still expect:
31
+ #
32
+ # { config: PATH }
33
+ #
34
+ # But we document, and hope to eventually move to:
35
+ #
36
+ # { config: { file: PATH } }
37
+ #
38
+ # We need to munge from the latter to the former when/if we encounter it
39
+ def convert_to_legacy_file_config(config)
40
+ if config.is_a?(Hash) && config.keys.one? && config.key?("file")
41
+ config["file"]
42
+ else
43
+ config
44
+ end
45
+ end
46
+
47
+ def upconvert_legacy_yaml!
48
+ config.delete("ratings")
49
+
50
+ if config.key?("engines")
51
+ config["plugins"] ||= config.delete("engines")
52
+ end
53
+
54
+ plugins = config.fetch("plugins", {})
55
+ plugins.each do |engine, data|
56
+ plugins[engine] = coerce_engine(data)
57
+ if plugins.fetch(engine)["exclude_paths"]
58
+ plugins.fetch(engine)["exclude_patterns"] ||= Array(plugins.fetch(engine).delete("exclude_paths"))
59
+ end
60
+ if plugins.fetch(engine)["config"]
61
+ plugins.fetch(engine)["config"] = convert_to_legacy_file_config(
62
+ plugins.fetch(engine).fetch("config"),
63
+ )
64
+ end
65
+ end
66
+
67
+ if config.key?("exclude_paths")
68
+ config["exclude_patterns"] ||= Array(config.delete("exclude_paths"))
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,74 @@
1
+ module CC
2
+ class EngineRegistry
3
+ include Enumerable
4
+
5
+ DEFAULT_MEMORY_LIMIT = 1_024_000_000
6
+ DEFAULT_COMMAND = nil
7
+ DEFAULT_MANIFEST_PATH = File.expand_path("../../../config/engines.yml", __FILE__)
8
+
9
+ EngineDetails = Struct.new(:image, :command, :description, :memory)
10
+ EngineDetailsNotFoundError = Class.new(StandardError)
11
+
12
+ def initialize(path = DEFAULT_MANIFEST_PATH, prefix = nil)
13
+ @yaml = YAML.safe_load(File.read(path))
14
+ @prefix = prefix || ENV["CODECLIMATE_PREFIX"] || ""
15
+ end
16
+
17
+ def each
18
+ yaml.each do |name, metadata|
19
+ engine = Config::Engine.new(
20
+ name,
21
+ channel: metadata.fetch("channels").keys.first,
22
+ )
23
+ engine_details = fetch_engine_details(engine)
24
+
25
+ yield(engine, engine_details)
26
+ end
27
+ end
28
+
29
+ def fetch_engine_details(engine, development: false)
30
+ if development
31
+ EngineDetails.new("codeclimate/codeclimate-#{engine.name}", nil, "")
32
+ else
33
+ metadata = yaml.fetch(engine.name)
34
+ channels = metadata.fetch("channels")
35
+
36
+ EngineDetails.new(
37
+ [prefix, channels.fetch(engine.channel)].join,
38
+ metadata.fetch("command", DEFAULT_COMMAND),
39
+ metadata.fetch("description", "(No description available)"),
40
+ memory_limit(metadata["minimum_memory_limit"]),
41
+ )
42
+ end
43
+ rescue KeyError
44
+ raise EngineDetailsNotFoundError, not_found_message(engine, channels)
45
+ end
46
+
47
+ private
48
+
49
+ attr_reader :yaml, :prefix
50
+
51
+ def memory_limit(minimum_memory_limit)
52
+ [
53
+ minimum_memory_limit.to_i,
54
+ default_memory_limit.to_i,
55
+ ].max
56
+ end
57
+
58
+ def default_memory_limit
59
+ ENV["ENGINE_MEMORY_LIMIT_BYTES"] || DEFAULT_MEMORY_LIMIT
60
+ end
61
+
62
+ def not_found_message(engine, available_channels)
63
+ if available_channels
64
+ # Known engine, unknown channel
65
+ "Channel #{engine.channel} not found" \
66
+ " for #{engine.name}," \
67
+ " available channels: #{available_channels.keys.inspect}"
68
+ else
69
+ # Unknown engine
70
+ "No engine named #{engine.name} found"
71
+ end
72
+ end
73
+ end
74
+ end