codeclimate-fede 0.85.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/check +18 -0
- data/bin/codeclimate +21 -0
- data/bin/prep-release +45 -0
- data/bin/publish +47 -0
- data/bin/release +41 -0
- data/bin/validate-release +18 -0
- data/config/engines.yml +322 -0
- data/lib/cc/analyzer/bridge.rb +106 -0
- data/lib/cc/analyzer/composite_container_listener.rb +21 -0
- data/lib/cc/analyzer/container/result.rb +74 -0
- data/lib/cc/analyzer/container.rb +208 -0
- data/lib/cc/analyzer/container_listener.rb +9 -0
- data/lib/cc/analyzer/engine.rb +125 -0
- data/lib/cc/analyzer/engine_output.rb +74 -0
- data/lib/cc/analyzer/engine_output_filter.rb +36 -0
- data/lib/cc/analyzer/engine_output_overrider.rb +31 -0
- data/lib/cc/analyzer/filesystem.rb +50 -0
- data/lib/cc/analyzer/formatters/formatter.rb +53 -0
- data/lib/cc/analyzer/formatters/html_formatter.rb +415 -0
- data/lib/cc/analyzer/formatters/json_formatter.rb +38 -0
- data/lib/cc/analyzer/formatters/plain_text_formatter.rb +101 -0
- data/lib/cc/analyzer/formatters/spinner.rb +35 -0
- data/lib/cc/analyzer/formatters.rb +21 -0
- data/lib/cc/analyzer/issue.rb +69 -0
- data/lib/cc/analyzer/issue_sorter.rb +30 -0
- data/lib/cc/analyzer/issue_validations/category_validation.rb +32 -0
- data/lib/cc/analyzer/issue_validations/check_name_presence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/content_validation.rb +21 -0
- data/lib/cc/analyzer/issue_validations/description_presence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/location_format_validation.rb +72 -0
- data/lib/cc/analyzer/issue_validations/other_locations_format_validation.rb +41 -0
- data/lib/cc/analyzer/issue_validations/path_existence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/path_is_file_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/path_presence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/relative_path_validation.rb +32 -0
- data/lib/cc/analyzer/issue_validations/remediation_points_validation.rb +25 -0
- data/lib/cc/analyzer/issue_validations/severity_validation.rb +39 -0
- data/lib/cc/analyzer/issue_validations/type_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/validation.rb +35 -0
- data/lib/cc/analyzer/issue_validations.rb +26 -0
- data/lib/cc/analyzer/issue_validator.rb +11 -0
- data/lib/cc/analyzer/location_description.rb +45 -0
- data/lib/cc/analyzer/logging_container_listener.rb +24 -0
- data/lib/cc/analyzer/measurement.rb +22 -0
- data/lib/cc/analyzer/measurement_validations/name_validation.rb +23 -0
- data/lib/cc/analyzer/measurement_validations/type_validation.rb +15 -0
- data/lib/cc/analyzer/measurement_validations/validation.rb +27 -0
- data/lib/cc/analyzer/measurement_validations/value_validation.rb +21 -0
- data/lib/cc/analyzer/measurement_validations.rb +16 -0
- data/lib/cc/analyzer/measurement_validator.rb +11 -0
- data/lib/cc/analyzer/mounted_path.rb +80 -0
- data/lib/cc/analyzer/raising_container_listener.rb +32 -0
- data/lib/cc/analyzer/source_buffer.rb +47 -0
- data/lib/cc/analyzer/source_extractor.rb +79 -0
- data/lib/cc/analyzer/source_fingerprint.rb +40 -0
- data/lib/cc/analyzer/statsd_container_listener.rb +51 -0
- data/lib/cc/analyzer/validator.rb +38 -0
- data/lib/cc/analyzer.rb +50 -0
- data/lib/cc/cli/analyze/engine_failure.rb +11 -0
- data/lib/cc/cli/analyze.rb +90 -0
- data/lib/cc/cli/command.rb +85 -0
- data/lib/cc/cli/console.rb +12 -0
- data/lib/cc/cli/engines/engine_command.rb +15 -0
- data/lib/cc/cli/engines/install.rb +35 -0
- data/lib/cc/cli/engines/list.rb +18 -0
- data/lib/cc/cli/engines.rb +5 -0
- data/lib/cc/cli/file_store.rb +42 -0
- data/lib/cc/cli/global_cache.rb +47 -0
- data/lib/cc/cli/global_config.rb +35 -0
- data/lib/cc/cli/help.rb +51 -0
- data/lib/cc/cli/output.rb +34 -0
- data/lib/cc/cli/prepare.rb +98 -0
- data/lib/cc/cli/runner.rb +75 -0
- data/lib/cc/cli/validate_config.rb +84 -0
- data/lib/cc/cli/version.rb +16 -0
- data/lib/cc/cli/version_checker.rb +107 -0
- data/lib/cc/cli.rb +39 -0
- data/lib/cc/config/checks_adapter.rb +40 -0
- data/lib/cc/config/default_adapter.rb +54 -0
- data/lib/cc/config/engine.rb +41 -0
- data/lib/cc/config/engine_set.rb +47 -0
- data/lib/cc/config/json_adapter.rb +17 -0
- data/lib/cc/config/prepare.rb +92 -0
- data/lib/cc/config/validation/check_validator.rb +34 -0
- data/lib/cc/config/validation/engine_validator.rb +93 -0
- data/lib/cc/config/validation/fetch_validator.rb +78 -0
- data/lib/cc/config/validation/file_validator.rb +112 -0
- data/lib/cc/config/validation/hash_validations.rb +52 -0
- data/lib/cc/config/validation/json.rb +31 -0
- data/lib/cc/config/validation/prepare_validator.rb +40 -0
- data/lib/cc/config/validation/yaml.rb +66 -0
- data/lib/cc/config/yaml_adapter.rb +73 -0
- data/lib/cc/config.rb +70 -0
- data/lib/cc/engine_registry.rb +74 -0
- data/lib/cc/resolv.rb +39 -0
- data/lib/cc/workspace/exclusion.rb +34 -0
- data/lib/cc/workspace/path_tree/dir_node.rb +67 -0
- data/lib/cc/workspace/path_tree/file_node.rb +31 -0
- data/lib/cc/workspace/path_tree.rb +49 -0
- data/lib/cc/workspace.rb +39 -0
- metadata +279 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module CC
|
2
|
+
module CLI
|
3
|
+
module Engines
|
4
|
+
class List < EngineCommand
|
5
|
+
SHORT_HELP = "List all available engines".freeze
|
6
|
+
|
7
|
+
def run
|
8
|
+
say "Available engines:"
|
9
|
+
engine_registry.
|
10
|
+
sort_by { |engine, _| engine.name }.
|
11
|
+
each do |engine, metadata|
|
12
|
+
say "- #{engine.name}: #{metadata.description}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
module CC
|
5
|
+
module CLI
|
6
|
+
class FileStore
|
7
|
+
# This class is not supposed to be directly used. It should be sublcassed
|
8
|
+
# and a few constants need to be defined on the sublass to be usable.
|
9
|
+
#
|
10
|
+
# FILE_NAME is the name of the file this class wraps.
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
load_data
|
14
|
+
end
|
15
|
+
|
16
|
+
def save
|
17
|
+
return false unless File.exist? self.class::FILE_NAME
|
18
|
+
|
19
|
+
File.open(self.class::FILE_NAME, "w") do |f|
|
20
|
+
YAML.dump data, f
|
21
|
+
end
|
22
|
+
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :data
|
29
|
+
|
30
|
+
def load_data
|
31
|
+
@data =
|
32
|
+
if File.exist? self.class::FILE_NAME
|
33
|
+
File.open(self.class::FILE_NAME, "r:bom|utf-8") do |f|
|
34
|
+
YAML.safe_load(f, [Time], [], false, self.class::FILE_NAME) || {}
|
35
|
+
end
|
36
|
+
else
|
37
|
+
{}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "cc/cli/file_store"
|
2
|
+
|
3
|
+
module CC
|
4
|
+
module CLI
|
5
|
+
class GlobalCache < FileStore
|
6
|
+
FILE_NAME = "/cache.yml".freeze
|
7
|
+
|
8
|
+
# Cache entries
|
9
|
+
|
10
|
+
def last_version_check
|
11
|
+
data["last-version-check"] || Time.at(0)
|
12
|
+
end
|
13
|
+
|
14
|
+
def last_version_check=(value)
|
15
|
+
data["last-version-check"] =
|
16
|
+
if value.is_a? Time
|
17
|
+
value
|
18
|
+
else
|
19
|
+
Time.at(0)
|
20
|
+
end
|
21
|
+
save
|
22
|
+
value
|
23
|
+
end
|
24
|
+
|
25
|
+
def latest_version
|
26
|
+
data["latest-version"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def latest_version=(value)
|
30
|
+
data["latest-version"] = value
|
31
|
+
save
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
def outdated
|
36
|
+
data["outdated"] == true
|
37
|
+
end
|
38
|
+
alias outdated? outdated
|
39
|
+
|
40
|
+
def outdated=(value)
|
41
|
+
data["outdated"] = value == true
|
42
|
+
save
|
43
|
+
value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "cc/cli/file_store"
|
2
|
+
require "uuid"
|
3
|
+
|
4
|
+
module CC
|
5
|
+
module CLI
|
6
|
+
class GlobalConfig < FileStore
|
7
|
+
FILE_NAME = "/config.yml".freeze
|
8
|
+
|
9
|
+
DEFAULT_CONFIG = {
|
10
|
+
"check-version" => true,
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
# Config entries
|
14
|
+
|
15
|
+
def check_version
|
16
|
+
data["check-version"]
|
17
|
+
end
|
18
|
+
alias check_version? check_version
|
19
|
+
|
20
|
+
def check_version=(value)
|
21
|
+
data["check-version"] = value == true
|
22
|
+
end
|
23
|
+
|
24
|
+
def uuid
|
25
|
+
data["uuid"] ||= UUID.new.generate
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def load_data
|
31
|
+
@data = DEFAULT_CONFIG.merge(super)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/cc/cli/help.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require "rainbow"
|
2
|
+
|
3
|
+
module CC
|
4
|
+
module CLI
|
5
|
+
class Help < Command
|
6
|
+
ARGUMENT_LIST = "[command]".freeze
|
7
|
+
SHORT_HELP = "Display help information.".freeze
|
8
|
+
HELP = "#{SHORT_HELP}\n" \
|
9
|
+
"\n" \
|
10
|
+
" no arguments Show help summary for all commands.\n" \
|
11
|
+
" [command] Show help for specific commands. Can be specified multiple times.".freeze
|
12
|
+
|
13
|
+
def run
|
14
|
+
if @args.any?
|
15
|
+
@args.each do |command|
|
16
|
+
show_help(command)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
show_help_summary
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def show_help(command_name)
|
26
|
+
if (command = Command[command_name])
|
27
|
+
say "Usage: codeclimate #{command.synopsis}\n"
|
28
|
+
say "\n"
|
29
|
+
say "#{command.help}\n"
|
30
|
+
say "\n\n"
|
31
|
+
else
|
32
|
+
say "Unknown command: #{command_name}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def show_help_summary
|
37
|
+
short_helps =
|
38
|
+
Command.all.sort_by(&:command_name).map do |command|
|
39
|
+
[command.synopsis, command.short_help]
|
40
|
+
end.compact.to_h
|
41
|
+
|
42
|
+
longest_command_length = short_helps.keys.map(&:length).max
|
43
|
+
|
44
|
+
say "Usage: codeclimate COMMAND ...\n\nAvailable commands:\n"
|
45
|
+
short_helps.each do |command, help|
|
46
|
+
say format(" %-#{longest_command_length}s %s\n", command, help)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module CC
|
2
|
+
module CLI
|
3
|
+
module Output
|
4
|
+
def success(message)
|
5
|
+
terminal.say colorize(message, :green)
|
6
|
+
end
|
7
|
+
|
8
|
+
def say(message)
|
9
|
+
terminal.say message
|
10
|
+
end
|
11
|
+
|
12
|
+
def warn(message)
|
13
|
+
terminal.say colorize("WARNING: #{message}", :yellow)
|
14
|
+
end
|
15
|
+
|
16
|
+
def fatal(message)
|
17
|
+
$stderr.puts colorize(message, :red)
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def colorize(string, *args)
|
22
|
+
rainbow.wrap(string).color(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def rainbow
|
26
|
+
@rainbow ||= Rainbow.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def terminal
|
30
|
+
@terminal ||= HighLine.new($stdin, $stdout)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "ipaddr"
|
3
|
+
require "json"
|
4
|
+
require "net/http"
|
5
|
+
require "pathname"
|
6
|
+
require "uri"
|
7
|
+
|
8
|
+
require "cc/resolv"
|
9
|
+
|
10
|
+
module CC
|
11
|
+
module CLI
|
12
|
+
class Prepare < Command
|
13
|
+
ARGUMENT_LIST = "[--allow-internal-ips]".freeze
|
14
|
+
SHORT_HELP = "Run the commands in your prepare step.".freeze
|
15
|
+
HELP = "#{SHORT_HELP}\n" \
|
16
|
+
"\n" \
|
17
|
+
" --allow-internal-ips Allow fetching from internal IPs.".freeze
|
18
|
+
|
19
|
+
InternalHostError = Class.new(StandardError)
|
20
|
+
FetchError = Class.new(StandardError)
|
21
|
+
|
22
|
+
PRIVATE_ADDRESS_SUBNETS = [
|
23
|
+
IPAddr.new("10.0.0.0/8"),
|
24
|
+
IPAddr.new("172.16.0.0/12"),
|
25
|
+
IPAddr.new("192.168.0.0/16"),
|
26
|
+
IPAddr.new("fd00::/8"),
|
27
|
+
IPAddr.new("127.0.0.1"),
|
28
|
+
IPAddr.new("0:0:0:0:0:0:0:1"),
|
29
|
+
].freeze
|
30
|
+
|
31
|
+
def run
|
32
|
+
::CC::Resolv.with_fixed_dns { fetch_all }
|
33
|
+
rescue FetchError, InternalHostError => ex
|
34
|
+
fatal(ex.message)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def allow_internal_ips?
|
40
|
+
@args.include?("--allow-internal-ips")
|
41
|
+
end
|
42
|
+
|
43
|
+
def fetches
|
44
|
+
@fetches ||= config.prepare.fetch
|
45
|
+
end
|
46
|
+
|
47
|
+
def config
|
48
|
+
@config ||= CC::Config.load
|
49
|
+
end
|
50
|
+
|
51
|
+
def fetch_all
|
52
|
+
fetches.each do |entry|
|
53
|
+
fetch(entry.url, entry.path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def fetch(url, target_path)
|
58
|
+
ensure_external!(url) unless allow_internal_ips?
|
59
|
+
|
60
|
+
uri = URI.parse(url)
|
61
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
62
|
+
http.use_ssl = uri.scheme == "https"
|
63
|
+
resp = http.get(uri)
|
64
|
+
if resp.code == "200"
|
65
|
+
write_file(target_path, resp.body)
|
66
|
+
say("Wrote #{url} to #{target_path}")
|
67
|
+
else
|
68
|
+
raise FetchError, "Failed fetching #{url}: code=#{resp.code} body=#{resp.body}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def write_file(target_path, content)
|
73
|
+
FileUtils.mkdir_p(Pathname.new(target_path).parent.to_s)
|
74
|
+
File.write(target_path, content)
|
75
|
+
end
|
76
|
+
|
77
|
+
def ensure_external!(url)
|
78
|
+
uri = URI.parse(url)
|
79
|
+
|
80
|
+
if internal?(uri.host)
|
81
|
+
raise InternalHostError, "Won't fetch #{url.inspect}: it maps to an internal address"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# rubocop:disable Style/CaseEquality
|
86
|
+
def internal?(host)
|
87
|
+
address = ::Resolv.getaddress(host)
|
88
|
+
|
89
|
+
PRIVATE_ADDRESS_SUBNETS.any? do |subnet|
|
90
|
+
subnet === IPAddr.new(address.to_s)
|
91
|
+
end
|
92
|
+
rescue ::Resolv::ResolvError
|
93
|
+
true # localhost
|
94
|
+
end
|
95
|
+
# rubocop:enable Style/CaseEquality
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "active_support/core_ext"
|
3
|
+
require "cc/cli/version_checker"
|
4
|
+
|
5
|
+
module CC
|
6
|
+
module CLI
|
7
|
+
class Runner
|
8
|
+
def self.run(argv)
|
9
|
+
new(argv).run
|
10
|
+
rescue => ex
|
11
|
+
$stderr.puts("error: (#{ex.class}) #{ex.message}")
|
12
|
+
CLI.logger.debug("backtrace: #{ex.backtrace.join("\n\t")}")
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(args)
|
17
|
+
@args = args
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
VersionChecker.new.check if check_version?
|
22
|
+
|
23
|
+
if command_class
|
24
|
+
command = command_class.new(command_arguments)
|
25
|
+
command.execute
|
26
|
+
else
|
27
|
+
command_not_found
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def command_not_found
|
32
|
+
$stderr.puts "unknown command #{command}"
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def command_class
|
37
|
+
command_const = Command[command]
|
38
|
+
if command_const.abstract?
|
39
|
+
nil
|
40
|
+
else
|
41
|
+
command_const
|
42
|
+
end
|
43
|
+
rescue NameError
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def command_arguments
|
48
|
+
Array(@args[1..-1])
|
49
|
+
end
|
50
|
+
|
51
|
+
def command
|
52
|
+
command_name = @args.first
|
53
|
+
case command_name
|
54
|
+
when nil, "-h", "-?", "--help"
|
55
|
+
"help"
|
56
|
+
when "-v", "--version"
|
57
|
+
"version"
|
58
|
+
else
|
59
|
+
command_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def check_version?
|
66
|
+
if ARGV.first == "--no-check-version"
|
67
|
+
ARGV.shift
|
68
|
+
false
|
69
|
+
else
|
70
|
+
true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module CC
|
2
|
+
module CLI
|
3
|
+
class ValidateConfig < Command
|
4
|
+
NO_CONFIG_MESSAGE = "No checked in config: nothing to validate.".freeze
|
5
|
+
TOO_MANY_CONFIG_MESSAGE = "Don't commit both .codeclimate.yml & .codeclimate.json: only the JSON will be used.".freeze
|
6
|
+
SHORT_HELP = "Validate your .codeclimate.yml or .codeclimate.json.".freeze
|
7
|
+
VALID_CONFIG_MESSAGE = "No errors or warnings found in %s.".freeze
|
8
|
+
|
9
|
+
def run
|
10
|
+
require_json_or_yaml
|
11
|
+
process_args
|
12
|
+
|
13
|
+
if any_issues?
|
14
|
+
display_issues
|
15
|
+
else
|
16
|
+
puts format(VALID_CONFIG_MESSAGE, validator.path)
|
17
|
+
end
|
18
|
+
|
19
|
+
exit 1 unless validator.valid?
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :config, :registry_path, :registry_prefix, :validator
|
25
|
+
|
26
|
+
def process_args
|
27
|
+
@registry_path = EngineRegistry::DEFAULT_MANIFEST_PATH
|
28
|
+
@registry_prefix = ""
|
29
|
+
|
30
|
+
# Undocumented; we only need these from Builder so we can validate
|
31
|
+
# engines/channels against our own registry and prefix.
|
32
|
+
while (arg = @args.shift)
|
33
|
+
case arg
|
34
|
+
when "--registry" then @registry_path = @args.shift
|
35
|
+
when "--registry-prefix" then @registry_prefix = @args.shift
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def any_issues?
|
41
|
+
validator.errors.any? ||
|
42
|
+
validator.warnings.any?
|
43
|
+
end
|
44
|
+
|
45
|
+
def display_issues
|
46
|
+
validator.errors.each do |error|
|
47
|
+
puts "#{colorize("ERROR", :red)}: #{error}"
|
48
|
+
end
|
49
|
+
|
50
|
+
validator.warnings.each do |warning|
|
51
|
+
puts "#{colorize("WARNING", :yellow)}: #{warning}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def require_json_or_yaml
|
56
|
+
if !filesystem.exist?(Config::YAMLAdapter::DEFAULT_PATH) && !filesystem.exist?(Config::JSONAdapter::DEFAULT_PATH)
|
57
|
+
puts NO_CONFIG_MESSAGE
|
58
|
+
exit 0
|
59
|
+
elsif filesystem.exist?(Config::YAMLAdapter::DEFAULT_PATH) && filesystem.exist?(Config::JSONAdapter::DEFAULT_PATH)
|
60
|
+
puts "#{colorize("WARNING", :yellow)}: #{TOO_MANY_CONFIG_MESSAGE}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def validator
|
65
|
+
@validator =
|
66
|
+
if filesystem.exist?(Config::JSONAdapter::DEFAULT_PATH)
|
67
|
+
Config::Validation::JSON.new(
|
68
|
+
Config::JSONAdapter::DEFAULT_PATH,
|
69
|
+
engine_registry,
|
70
|
+
)
|
71
|
+
elsif filesystem.exist?(Config::YAMLAdapter::DEFAULT_PATH)
|
72
|
+
Config::Validation::YAML.new(
|
73
|
+
Config::YAMLAdapter::DEFAULT_PATH,
|
74
|
+
engine_registry,
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def engine_registry
|
80
|
+
EngineRegistry.new(registry_path, registry_prefix)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CC
|
2
|
+
module CLI
|
3
|
+
class Version < Command
|
4
|
+
SHORT_HELP = "Display the CLI version.".freeze
|
5
|
+
|
6
|
+
def run
|
7
|
+
say version
|
8
|
+
end
|
9
|
+
|
10
|
+
def version
|
11
|
+
path = File.expand_path("../../../../VERSION", __FILE__)
|
12
|
+
@version ||= File.read(path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "cc/cli/global_config"
|
2
|
+
require "cc/cli/global_cache"
|
3
|
+
|
4
|
+
module CC
|
5
|
+
module CLI
|
6
|
+
class VersionChecker
|
7
|
+
include CC::CLI::Output
|
8
|
+
|
9
|
+
VERSION_CHECK_TIMEOUT = 60 * 60 # 1 Hour in seconds
|
10
|
+
DEFAULT_VERSIONS_URL = "https://versions.codeclimate.com".freeze
|
11
|
+
|
12
|
+
def check
|
13
|
+
return unless global_config.check_version? && version_check_is_due?
|
14
|
+
|
15
|
+
print_new_version_message if outdated?
|
16
|
+
|
17
|
+
global_config.save
|
18
|
+
rescue => error
|
19
|
+
CLI.logger.debug(error)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def version_check_is_due?
|
25
|
+
Time.now > global_cache.last_version_check + VERSION_CHECK_TIMEOUT
|
26
|
+
end
|
27
|
+
|
28
|
+
def outdated?
|
29
|
+
api_response["outdated"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def latest_version
|
33
|
+
api_response["latest"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def print_new_version_message
|
37
|
+
warn "A new version (v#{latest_version}) is available. Upgrade instructions are available at: https://github.com/codeclimate/codeclimate#packages"
|
38
|
+
end
|
39
|
+
|
40
|
+
def api_response
|
41
|
+
@api_response ||=
|
42
|
+
begin
|
43
|
+
cache! JSON.parse(api_response_body)
|
44
|
+
rescue JSON::ParserError => error
|
45
|
+
CLI.logger.debug(error)
|
46
|
+
{
|
47
|
+
"outdated" => false,
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def api_response_body
|
53
|
+
if http_response.is_a? Net::HTTPSuccess
|
54
|
+
http_response.body
|
55
|
+
else
|
56
|
+
raise Net::HTTPFatalError.new("HTTP Error", http_response)
|
57
|
+
end
|
58
|
+
rescue Net::HTTPFatalError => error
|
59
|
+
CLI.logger.debug(error)
|
60
|
+
""
|
61
|
+
end
|
62
|
+
|
63
|
+
def http_response
|
64
|
+
@http_response ||=
|
65
|
+
begin
|
66
|
+
uri = URI.parse(ENV.fetch("CODECLIMATE_VERSIONS_URL", DEFAULT_VERSIONS_URL))
|
67
|
+
uri.query = { version: version, uid: global_config.uuid }.to_query
|
68
|
+
|
69
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
70
|
+
http.open_timeout = 5
|
71
|
+
http.read_timeout = 5
|
72
|
+
http.ssl_timeout = 5
|
73
|
+
http.use_ssl = uri.scheme == "https"
|
74
|
+
|
75
|
+
http.get(uri, "User-Agent" => user_agent)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def cache!(data)
|
80
|
+
global_cache.latest_version = data["latest"]
|
81
|
+
global_cache.outdated = data["outdated"] == true
|
82
|
+
global_cache.last_version_check = Time.now
|
83
|
+
data
|
84
|
+
end
|
85
|
+
|
86
|
+
def version
|
87
|
+
@version ||= Version.new.version
|
88
|
+
end
|
89
|
+
|
90
|
+
def user_agent
|
91
|
+
"Code Climate CLI #{version}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def global_config
|
95
|
+
@global_config ||= GlobalConfig.new
|
96
|
+
end
|
97
|
+
|
98
|
+
def global_cache
|
99
|
+
@global_cache ||= GlobalCache.new
|
100
|
+
end
|
101
|
+
|
102
|
+
def terminal
|
103
|
+
@terminal ||= HighLine.new(nil, $stderr)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
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
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CC
|
2
|
+
class Config
|
3
|
+
class ChecksAdapter
|
4
|
+
attr_reader :config
|
5
|
+
|
6
|
+
def initialize(data = {})
|
7
|
+
@config = data
|
8
|
+
|
9
|
+
return unless checks.present?
|
10
|
+
copy_qm_checks_config
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def copy_qm_checks_config
|
16
|
+
DefaultAdapter::ENGINES.keys.each do |name|
|
17
|
+
copy_checks(name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def copy_checks(engine_name)
|
22
|
+
engine = config.fetch("plugins", {}).fetch(engine_name, {})
|
23
|
+
engine["config"] ||= {}
|
24
|
+
|
25
|
+
if engine["config"].is_a?(String)
|
26
|
+
engine["config"] = {
|
27
|
+
"file" => engine["config"],
|
28
|
+
"checks" => checks,
|
29
|
+
}
|
30
|
+
elsif engine["config"].is_a?(Hash)
|
31
|
+
engine["config"]["checks"] = checks
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def checks
|
36
|
+
config["checks"]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|