codeclimate 0.69.0 → 0.70.0
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.
- checksums.yaml +4 -4
- data/bin/prep-release +1 -1
- data/config/engines.yml +32 -323
- data/lib/cc/analyzer.rb +5 -4
- data/lib/cc/analyzer/bridge.rb +106 -0
- data/lib/cc/analyzer/composite_container_listener.rb +4 -8
- data/lib/cc/analyzer/container.rb +44 -41
- data/lib/cc/analyzer/container/result.rb +74 -0
- data/lib/cc/analyzer/container_listener.rb +2 -7
- data/lib/cc/analyzer/engine.rb +53 -45
- data/lib/cc/analyzer/engine_output.rb +40 -10
- data/lib/cc/analyzer/formatters/formatter.rb +2 -0
- data/lib/cc/analyzer/formatters/html_formatter.rb +4 -0
- data/lib/cc/analyzer/formatters/json_formatter.rb +1 -0
- data/lib/cc/analyzer/formatters/plain_text_formatter.rb +8 -1
- data/lib/cc/analyzer/issue.rb +4 -2
- data/lib/cc/analyzer/issue_validations/relative_path_validation.rb +6 -2
- data/lib/cc/analyzer/issue_validator.rb +3 -32
- data/lib/cc/analyzer/logging_container_listener.rb +9 -7
- data/lib/cc/analyzer/measurement.rb +22 -0
- data/lib/cc/analyzer/measurement_validations.rb +16 -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_validator.rb +11 -0
- data/lib/cc/analyzer/raising_container_listener.rb +18 -18
- data/lib/cc/analyzer/statsd_container_listener.rb +22 -22
- data/lib/cc/analyzer/validator.rb +38 -0
- data/lib/cc/cli.rb +12 -12
- data/lib/cc/cli/analyze.rb +42 -60
- data/lib/cc/cli/analyze/engine_failure.rb +11 -0
- data/lib/cc/cli/command.rb +0 -10
- data/lib/cc/cli/engines.rb +0 -3
- data/lib/cc/cli/engines/engine_command.rb +2 -34
- data/lib/cc/cli/engines/install.rb +11 -17
- data/lib/cc/cli/engines/list.rb +5 -3
- data/lib/cc/cli/prepare.rb +5 -11
- data/lib/cc/cli/runner.rb +1 -2
- data/lib/cc/cli/test.rb +0 -1
- data/lib/cc/cli/validate_config.rb +49 -63
- data/lib/cc/cli/version_checker.rb +3 -3
- data/lib/cc/config.rb +70 -0
- data/lib/cc/config/checks_adapter.rb +40 -0
- data/lib/cc/config/default_adapter.rb +52 -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 +89 -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/engine_registry.rb +74 -0
- data/lib/cc/workspace/path_tree/dir_node.rb +1 -1
- metadata +36 -55
- data/bin/codeclimate-init +0 -6
- data/config/coffeelint/coffeelint.json +0 -129
- data/config/csslint/.csslintrc +0 -2
- data/config/eslint/.eslintignore +0 -1
- data/config/eslint/.eslintrc.yml +0 -277
- data/config/rubocop/.rubocop.yml +0 -1156
- data/lib/cc/analyzer/config.rb +0 -86
- data/lib/cc/analyzer/engine_registry.rb +0 -36
- data/lib/cc/analyzer/engines_config_builder.rb +0 -97
- data/lib/cc/analyzer/engines_runner.rb +0 -64
- data/lib/cc/cli/config.rb +0 -44
- data/lib/cc/cli/config_generator.rb +0 -108
- data/lib/cc/cli/engines/disable.rb +0 -38
- data/lib/cc/cli/engines/enable.rb +0 -41
- data/lib/cc/cli/engines/remove.rb +0 -35
- data/lib/cc/cli/init.rb +0 -117
- data/lib/cc/cli/prepare/quality.rb +0 -64
- data/lib/cc/cli/upgrade_config_generator.rb +0 -42
data/lib/cc/analyzer.rb
CHANGED
@@ -2,17 +2,14 @@ require "yaml"
|
|
2
2
|
|
3
3
|
module CC
|
4
4
|
module Analyzer
|
5
|
+
autoload :Bridge, "cc/analyzer/bridge"
|
5
6
|
autoload :CompositeContainerListener, "cc/analyzer/composite_container_listener"
|
6
|
-
autoload :Config, "cc/analyzer/config"
|
7
7
|
autoload :Container, "cc/analyzer/container"
|
8
8
|
autoload :ContainerListener, "cc/analyzer/container_listener"
|
9
9
|
autoload :Engine, "cc/analyzer/engine"
|
10
10
|
autoload :EngineOutput, "cc/analyzer/engine_output"
|
11
11
|
autoload :EngineOutputFilter, "cc/analyzer/engine_output_filter"
|
12
12
|
autoload :EngineOutputOverrider, "cc/analyzer/engine_output_overrider"
|
13
|
-
autoload :EngineRegistry, "cc/analyzer/engine_registry"
|
14
|
-
autoload :EnginesConfigBuilder, "cc/analyzer/engines_config_builder"
|
15
|
-
autoload :EnginesRunner, "cc/analyzer/engines_runner"
|
16
13
|
autoload :Filesystem, "cc/analyzer/filesystem"
|
17
14
|
autoload :Formatters, "cc/analyzer/formatters"
|
18
15
|
autoload :Issue, "cc/analyzer/issue"
|
@@ -21,12 +18,16 @@ module CC
|
|
21
18
|
autoload :IssueValidator, "cc/analyzer/issue_validator"
|
22
19
|
autoload :LocationDescription, "cc/analyzer/location_description"
|
23
20
|
autoload :LoggingContainerListener, "cc/analyzer/logging_container_listener"
|
21
|
+
autoload :Measurement, "cc/analyzer/measurement"
|
22
|
+
autoload :MeasurementValidations, "cc/analyzer/measurement_validations"
|
23
|
+
autoload :MeasurementValidator, "cc/analyzer/measurement_validator"
|
24
24
|
autoload :MountedPath, "cc/analyzer/mounted_path"
|
25
25
|
autoload :RaisingContainerListener, "cc/analyzer/raising_container_listener"
|
26
26
|
autoload :SourceBuffer, "cc/analyzer/source_buffer"
|
27
27
|
autoload :SourceExtractor, "cc/analyzer/source_extractor"
|
28
28
|
autoload :SourceFingerprint, "cc/analyzer/source_fingerprint"
|
29
29
|
autoload :StatsdContainerListener, "cc/analyzer/statsd_container_listener"
|
30
|
+
autoload :Validator, "cc/analyzer/validator"
|
30
31
|
|
31
32
|
class DummyStatsd
|
32
33
|
def method_missing(*)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module CC
|
2
|
+
module Analyzer
|
3
|
+
# The shared interface, invoked by Builder or CLI::Analyze
|
4
|
+
#
|
5
|
+
# Input:
|
6
|
+
# - config
|
7
|
+
# - engines
|
8
|
+
# - exclude_patterns
|
9
|
+
# - development?
|
10
|
+
# - analysis_paths
|
11
|
+
# - formatter
|
12
|
+
# - started
|
13
|
+
# - engine_running
|
14
|
+
# - finished
|
15
|
+
# - close
|
16
|
+
# - listener
|
17
|
+
# - started(engine, details)
|
18
|
+
# - finished(engine, details, result)
|
19
|
+
# - registry
|
20
|
+
#
|
21
|
+
# Only raises if Listener raises
|
22
|
+
#
|
23
|
+
class Bridge
|
24
|
+
def initialize(config:, formatter:, listener:, registry:)
|
25
|
+
@config = config
|
26
|
+
@formatter = formatter
|
27
|
+
@listener = listener
|
28
|
+
@registry = registry
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
formatter.started
|
33
|
+
|
34
|
+
config.engines.each do |engine|
|
35
|
+
next unless engine.enabled?
|
36
|
+
|
37
|
+
formatter.engine_running(engine) do
|
38
|
+
result = nil
|
39
|
+
engine_details = nil
|
40
|
+
|
41
|
+
begin
|
42
|
+
engine_details = registry.fetch_engine_details(
|
43
|
+
engine,
|
44
|
+
development: config.development?,
|
45
|
+
)
|
46
|
+
listener.started(engine, engine_details)
|
47
|
+
result = run_engine(engine, engine_details)
|
48
|
+
rescue CC::EngineRegistry::EngineDetailsNotFoundError => ex
|
49
|
+
result = Container::Result.skipped(ex)
|
50
|
+
end
|
51
|
+
|
52
|
+
listener.finished(engine, engine_details, result)
|
53
|
+
result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
formatter.finished
|
58
|
+
ensure
|
59
|
+
formatter.close
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
attr_reader :config, :formatter, :listener, :registry
|
65
|
+
|
66
|
+
def run_engine(engine, engine_details)
|
67
|
+
# Analyzer::Engine doesn't have the best interface, but we're limiting
|
68
|
+
# our refactors for now.
|
69
|
+
Engine.new(
|
70
|
+
engine.name,
|
71
|
+
{
|
72
|
+
"image" => engine_details.image,
|
73
|
+
"command" => engine_details.command,
|
74
|
+
"memory" => engine_details.memory,
|
75
|
+
},
|
76
|
+
engine.config.merge(
|
77
|
+
"channel" => engine.channel,
|
78
|
+
"include_paths" => engine_workspace(engine).paths,
|
79
|
+
),
|
80
|
+
engine.container_label,
|
81
|
+
).run(formatter)
|
82
|
+
end
|
83
|
+
|
84
|
+
def engine_workspace(engine)
|
85
|
+
if engine.exclude_patterns.any?
|
86
|
+
workspace.clone.tap do |engine_workspace|
|
87
|
+
engine_workspace.remove(engine.exclude_patterns)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
workspace
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def workspace
|
95
|
+
@workspace ||= Workspace.new.tap do |workspace|
|
96
|
+
workspace.add(config.analysis_paths)
|
97
|
+
|
98
|
+
unless config.analysis_paths.any?
|
99
|
+
workspace.remove([".git"])
|
100
|
+
workspace.remove(config.exclude_patterns)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -5,16 +5,12 @@ module CC
|
|
5
5
|
@listeners = listeners
|
6
6
|
end
|
7
7
|
|
8
|
-
def started(
|
9
|
-
listeners.each { |listener| listener.started(
|
8
|
+
def started(*args)
|
9
|
+
listeners.each { |listener| listener.started(*args) }
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
listeners.each { |listener| listener.
|
14
|
-
end
|
15
|
-
|
16
|
-
def finished(data)
|
17
|
-
listeners.each { |listener| listener.finished(data) }
|
12
|
+
def finished(*args)
|
13
|
+
listeners.each { |listener| listener.finished(*args) }
|
18
14
|
end
|
19
15
|
|
20
16
|
private
|
@@ -1,42 +1,47 @@
|
|
1
1
|
require "posix/spawn"
|
2
2
|
require "thread"
|
3
3
|
|
4
|
+
require "cc/analyzer/container/result"
|
5
|
+
|
4
6
|
module CC
|
5
7
|
module Analyzer
|
8
|
+
#
|
9
|
+
# Running an abstract docker container
|
10
|
+
#
|
11
|
+
# Input:
|
12
|
+
# - image
|
13
|
+
# - name
|
14
|
+
# - command (Optional)
|
15
|
+
#
|
16
|
+
# Output:
|
17
|
+
# - Result
|
18
|
+
# - exit_status
|
19
|
+
# - timed_out?
|
20
|
+
# - duration
|
21
|
+
# - maximum_output_exceeded?
|
22
|
+
# - output_byte_count
|
23
|
+
# - stderr
|
24
|
+
#
|
25
|
+
# Never raises (unless broken)
|
26
|
+
#
|
6
27
|
class Container
|
7
|
-
ContainerData = Struct.new(
|
8
|
-
:image, # image used to create the container
|
9
|
-
:name, # name given to the container when created
|
10
|
-
:duration, # duration, for a finished event
|
11
|
-
:status, # status, for a finished event
|
12
|
-
:stderr, # stderr, for a finished event
|
13
|
-
)
|
14
|
-
ImageRequired = Class.new(StandardError)
|
15
|
-
Result = Struct.new(
|
16
|
-
:exit_status,
|
17
|
-
:timed_out?,
|
18
|
-
:duration,
|
19
|
-
:maximum_output_exceeded?,
|
20
|
-
:output_byte_count,
|
21
|
-
:stderr,
|
22
|
-
)
|
23
|
-
|
24
28
|
DEFAULT_TIMEOUT = 15 * 60 # 15m
|
25
29
|
DEFAULT_MAXIMUM_OUTPUT_BYTES = 500_000_000
|
26
30
|
|
27
|
-
def initialize(image:, name:, command: nil
|
28
|
-
raise ImageRequired if image.blank?
|
31
|
+
def initialize(image:, name:, command: nil)
|
29
32
|
@image = image
|
30
33
|
@name = name
|
31
34
|
@command = command
|
32
|
-
@listener = listener
|
33
|
-
@output_delimeter = "\n"
|
34
|
-
@on_output = ->(*) {}
|
35
35
|
@timed_out = false
|
36
36
|
@maximum_output_exceeded = false
|
37
|
+
@stdout_io = StringIO.new
|
37
38
|
@stderr_io = StringIO.new
|
38
39
|
@output_byte_count = 0
|
39
40
|
@counter_mutex = Mutex.new
|
41
|
+
|
42
|
+
# By default accumulate and include stdout in result
|
43
|
+
@output_delimeter = "\n"
|
44
|
+
@on_output = ->(output) { @stdout_io.puts(output) }
|
40
45
|
end
|
41
46
|
|
42
47
|
def on_output(delimeter = "\n", &block)
|
@@ -46,10 +51,9 @@ module CC
|
|
46
51
|
|
47
52
|
def run(options = [])
|
48
53
|
started = Time.now
|
49
|
-
@listener.started(container_data)
|
50
54
|
|
51
55
|
command = docker_run_command(options)
|
52
|
-
|
56
|
+
Analyzer.logger.debug("docker run: #{command.inspect}")
|
53
57
|
pid, _, out, err = POSIX::Spawn.popen4(*command)
|
54
58
|
|
55
59
|
@t_out = read_stdout(out)
|
@@ -70,21 +74,22 @@ module CC
|
|
70
74
|
# will unblock with the correct value in @timed_out
|
71
75
|
[@t_out, @t_err].each(&:join)
|
72
76
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
77
|
+
duration =
|
78
|
+
if @timed_out
|
79
|
+
timeout * 1000
|
80
|
+
else
|
81
|
+
((Time.now - started) * 1000).round
|
82
|
+
end
|
80
83
|
|
81
84
|
Result.new(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
@maximum_output_exceeded,
|
86
|
-
output_byte_count,
|
87
|
-
@stderr_io.string,
|
85
|
+
container_name: @name,
|
86
|
+
duration: duration,
|
87
|
+
exit_status: @status && @status.exitstatus,
|
88
|
+
maximum_output_exceeded: @maximum_output_exceeded,
|
89
|
+
output_byte_count: output_byte_count,
|
90
|
+
stderr: @stderr_io.string,
|
91
|
+
stdout: @stdout_io.string,
|
92
|
+
timed_out: @timed_out,
|
88
93
|
)
|
89
94
|
ensure
|
90
95
|
kill_reader_threads
|
@@ -117,6 +122,7 @@ module CC
|
|
117
122
|
out.each_line(@output_delimeter) do |chunk|
|
118
123
|
output = chunk.chomp(@output_delimeter)
|
119
124
|
|
125
|
+
Analyzer.logger.debug("engine stdout: #{output}")
|
120
126
|
@on_output.call(output)
|
121
127
|
check_output_bytes(output.bytesize)
|
122
128
|
end
|
@@ -130,6 +136,7 @@ module CC
|
|
130
136
|
Thread.new do
|
131
137
|
begin
|
132
138
|
err.each_line do |line|
|
139
|
+
Analyzer.logger.debug("engine stderr: #{line.chomp}")
|
133
140
|
@stderr_io.write(line)
|
134
141
|
check_output_bytes(line.bytesize)
|
135
142
|
end
|
@@ -166,10 +173,6 @@ module CC
|
|
166
173
|
end
|
167
174
|
end
|
168
175
|
|
169
|
-
def container_data(duration: nil, status: nil)
|
170
|
-
ContainerData.new(@image, @name, duration, status, @stderr_io.string)
|
171
|
-
end
|
172
|
-
|
173
176
|
def kill_reader_threads
|
174
177
|
@t_out.kill if @t_out
|
175
178
|
@t_err.kill if @t_err
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module CC
|
2
|
+
module Analyzer
|
3
|
+
class Container
|
4
|
+
class Result
|
5
|
+
attr_reader \
|
6
|
+
:container_name,
|
7
|
+
:duration,
|
8
|
+
:exit_status,
|
9
|
+
:output_byte_count,
|
10
|
+
:stderr,
|
11
|
+
:stdout
|
12
|
+
|
13
|
+
def initialize(
|
14
|
+
container_name: "",
|
15
|
+
duration: 0,
|
16
|
+
exit_status: 0,
|
17
|
+
maximum_output_exceeded: false,
|
18
|
+
output_byte_count: 0,
|
19
|
+
skipped: false,
|
20
|
+
stderr: "",
|
21
|
+
stdout: "",
|
22
|
+
timed_out: false
|
23
|
+
)
|
24
|
+
@container_name = container_name
|
25
|
+
@duration = duration
|
26
|
+
@exit_status = exit_status
|
27
|
+
@maximum_output_exceeded = maximum_output_exceeded
|
28
|
+
@output_byte_count = output_byte_count
|
29
|
+
@skipped = skipped
|
30
|
+
@stderr = stderr
|
31
|
+
@stdout = stdout
|
32
|
+
@timed_out = timed_out
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.skipped(ex)
|
36
|
+
new(
|
37
|
+
exit_status: 0,
|
38
|
+
skipped: true,
|
39
|
+
stderr: ex.message,
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def merge_from_exception(ex)
|
44
|
+
self.exit_status = 99
|
45
|
+
self.stderr = ex.message
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def timed_out?
|
50
|
+
@timed_out
|
51
|
+
end
|
52
|
+
|
53
|
+
def maximum_output_exceeded?
|
54
|
+
@maximum_output_exceeded
|
55
|
+
end
|
56
|
+
|
57
|
+
def errored?
|
58
|
+
timed_out? ||
|
59
|
+
maximum_output_exceeded? ||
|
60
|
+
exit_status.nil? ||
|
61
|
+
exit_status.nonzero?
|
62
|
+
end
|
63
|
+
|
64
|
+
def skipped?
|
65
|
+
@skipped
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
attr_writer :exit_status, :stderr
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -1,14 +1,9 @@
|
|
1
1
|
module CC
|
2
2
|
module Analyzer
|
3
3
|
class ContainerListener
|
4
|
-
def started(
|
5
|
-
end
|
4
|
+
def started(_engine, _details); end
|
6
5
|
|
7
|
-
def
|
8
|
-
end
|
9
|
-
|
10
|
-
def finished(_data)
|
11
|
-
end
|
6
|
+
def finished(_engine, _details, _result); end
|
12
7
|
end
|
13
8
|
end
|
14
9
|
end
|
data/lib/cc/analyzer/engine.rb
CHANGED
@@ -2,67 +2,73 @@ require "securerandom"
|
|
2
2
|
|
3
3
|
module CC
|
4
4
|
module Analyzer
|
5
|
+
#
|
6
|
+
# Running specifically an Engine container
|
7
|
+
#
|
8
|
+
# Input:
|
9
|
+
# - name
|
10
|
+
# - metadata
|
11
|
+
# - image
|
12
|
+
# - command (optional)
|
13
|
+
# - config (becomes /config.json)
|
14
|
+
# - label
|
15
|
+
# - io (to write filtered, validated output)
|
16
|
+
#
|
17
|
+
# Output:
|
18
|
+
# - Container::Result
|
19
|
+
#
|
5
20
|
class Engine
|
6
|
-
|
7
|
-
EngineTimeout = Class.new(StandardError)
|
21
|
+
Error = Class.new(StandardError)
|
8
22
|
|
9
|
-
|
10
|
-
|
11
|
-
DEFAULT_MEMORY_LIMIT = 512_000_000.freeze
|
12
|
-
|
13
|
-
def initialize(name, metadata, code_path, config, label)
|
23
|
+
def initialize(name, metadata, config, label)
|
14
24
|
@name = name
|
15
25
|
@metadata = metadata
|
16
|
-
@code_path = code_path
|
17
26
|
@config = config
|
18
27
|
@label = label.to_s
|
28
|
+
@error = nil
|
19
29
|
end
|
20
30
|
|
21
|
-
def run(
|
22
|
-
|
23
|
-
container_listener,
|
24
|
-
LoggingContainerListener.new(qualified_name, Analyzer.logger),
|
25
|
-
StatsdContainerListener.new(qualified_name.tr(":", "."), Analyzer.statsd),
|
26
|
-
RaisingContainerListener.new(qualified_name, EngineFailure, EngineTimeout),
|
27
|
-
)
|
31
|
+
def run(io)
|
32
|
+
write_config_file
|
28
33
|
|
29
34
|
container = Container.new(
|
30
|
-
image:
|
31
|
-
command:
|
35
|
+
image: metadata.fetch("image"),
|
36
|
+
command: metadata["command"],
|
32
37
|
name: container_name,
|
33
|
-
listener: composite_listener,
|
34
38
|
)
|
35
39
|
|
36
|
-
container.on_output("\0") do |
|
37
|
-
|
38
|
-
output = EngineOutput.new(raw_output)
|
39
|
-
|
40
|
-
unless output.valid?
|
41
|
-
stdout_io.failed("#{qualified_name} produced invalid output: #{output.error[:message]}")
|
42
|
-
container.stop
|
43
|
-
end
|
44
|
-
|
45
|
-
unless output_filter.filter?(output)
|
46
|
-
stdout_io.write(output_overrider.apply(output).to_json) || container.stop
|
47
|
-
end
|
40
|
+
container.on_output("\0") do |output|
|
41
|
+
handle_output(container, io, output)
|
48
42
|
end
|
49
43
|
|
50
|
-
write_config_file
|
51
|
-
CLI.debug("#{qualified_name} engine config: #{config_file.read}")
|
52
44
|
container.run(container_options).tap do |result|
|
53
|
-
|
45
|
+
result.merge_from_exception(error) if error.present?
|
54
46
|
end
|
55
|
-
rescue Container::ImageRequired
|
56
|
-
# Provide a clearer message given the context we have
|
57
|
-
message = "Unable to find an image for #{qualified_name}."
|
58
|
-
message << " Available channels: #{@metadata["channels"].keys.inspect}."
|
59
|
-
raise Container::ImageRequired, message
|
60
47
|
ensure
|
61
48
|
delete_config_file
|
62
49
|
end
|
63
50
|
|
64
51
|
private
|
65
52
|
|
53
|
+
attr_reader :name, :metadata
|
54
|
+
attr_accessor :error
|
55
|
+
|
56
|
+
def handle_output(container, io, raw_output)
|
57
|
+
output = EngineOutput.new(name, raw_output)
|
58
|
+
|
59
|
+
return if output_filter.filter?(output)
|
60
|
+
|
61
|
+
unless output.valid?
|
62
|
+
self.error = Error.new("engine produced invalid output: #{output.error}")
|
63
|
+
container.stop("output invalid")
|
64
|
+
end
|
65
|
+
|
66
|
+
unless io.write(output_overrider.apply(output).to_json)
|
67
|
+
self.error = Error.new("#{io.class}#write returned false, indicating an error")
|
68
|
+
container.stop("output error")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
66
72
|
def qualified_name
|
67
73
|
"#{name}:#{@config.fetch("channel", "stable")}"
|
68
74
|
end
|
@@ -71,11 +77,12 @@ module CC
|
|
71
77
|
[
|
72
78
|
"--cap-drop", "all",
|
73
79
|
"--label", "com.codeclimate.label=#{@label}",
|
74
|
-
"--
|
80
|
+
"--log-driver", "none",
|
81
|
+
"--memory", metadata["memory"].to_s,
|
75
82
|
"--memory-swap", "-1",
|
76
83
|
"--net", "none",
|
77
84
|
"--rm",
|
78
|
-
"--volume", "#{
|
85
|
+
"--volume", "#{code.host_path}:/code:ro",
|
79
86
|
"--volume", "#{config_file.host_path}:/config.json:ro",
|
80
87
|
"--user", "9000:9000"
|
81
88
|
]
|
@@ -86,6 +93,8 @@ module CC
|
|
86
93
|
end
|
87
94
|
|
88
95
|
def write_config_file
|
96
|
+
@config["debug"] = ENV["CODECLIMATE_DEBUG"]
|
97
|
+
Analyzer.logger.debug "/config.json content: #{@config.inspect}"
|
89
98
|
config_file.write(@config.to_json)
|
90
99
|
end
|
91
100
|
|
@@ -93,6 +102,10 @@ module CC
|
|
93
102
|
config_file.delete if config_file.file?
|
94
103
|
end
|
95
104
|
|
105
|
+
def code
|
106
|
+
@code ||= MountedPath.code
|
107
|
+
end
|
108
|
+
|
96
109
|
def config_file
|
97
110
|
@config_file ||= MountedPath.tmp.join(SecureRandom.uuid)
|
98
111
|
end
|
@@ -104,11 +117,6 @@ module CC
|
|
104
117
|
def output_overrider
|
105
118
|
@output_overrider ||= EngineOutputOverrider.new(@config)
|
106
119
|
end
|
107
|
-
|
108
|
-
# Memory limit for a running engine in bytes
|
109
|
-
def memory_limit
|
110
|
-
(ENV["ENGINE_MEMORY_LIMIT_BYTES"] || DEFAULT_MEMORY_LIMIT).to_s
|
111
|
-
end
|
112
120
|
end
|
113
121
|
end
|
114
122
|
end
|