codeclimate 0.2.7 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 89202f61cd85559f4e0531916fa59183a2ea9a01
4
- data.tar.gz: 1d7073a763b74d1813b28d2b892f43c2e3ffeced
3
+ metadata.gz: b5b6caa0a6dc7642c6e5abb6533c8c24c7bd49f4
4
+ data.tar.gz: 98bb65ce704a03ba8ed98a4ff697d2a424ef0fd3
5
5
  SHA512:
6
- metadata.gz: 2ec65cca81cf694dd51200dc44367bba0044afca7c48f90f5305b1ba8685f29da5b3c993f98350b36b64832321fd4521c017e8b09e75e8d11eb09c4c6d026251
7
- data.tar.gz: 1833d8881ea7881a34bc9ed565af19fee320755b1b7a739610dcecb00f845ec404fb8229a84e7d40c373eccacc64c2fccde076e37533275bccc0a5879d1c3a82
6
+ metadata.gz: 17ecabe1ace73fbd5f37c83a78b2bd1e5a683aa1b518684a33ebd8885246c8bb289f804c692d63bd443b35ef1f0f576cfbc382691c6c89368516c8aa8a6edc1c
7
+ data.tar.gz: f62c7be59d492698e22496c265b4f6c3c9993100ec861bce94227f9e4ffceda8bc8809ba2c75be9fae94a3d7d355c5b167ba30119e03ee42835d0e80b77e6906
@@ -2,6 +2,7 @@ module CC
2
2
  module Analyzer
3
3
  autoload :Accumulator, "cc/analyzer/accumulator"
4
4
  autoload :Config, "cc/analyzer/config"
5
+ autoload :Container, "cc/analyzer/container"
5
6
  autoload :Engine, "cc/analyzer/engine"
6
7
  autoload :EngineClient, "cc/analyzer/engine_client"
7
8
  autoload :EngineOutputFilter, "cc/analyzer/engine_output_filter"
@@ -12,6 +13,7 @@ module CC
12
13
  autoload :IssueSorter, "cc/analyzer/issue_sorter"
13
14
  autoload :LocationDescription,"cc/analyzer/location_description"
14
15
  autoload :NullConfig, "cc/analyzer/null_config"
16
+ autoload :NullContainerLog, "cc/analyzer/null_container_log"
15
17
  autoload :PathPatterns, "cc/analyzer/path_patterns"
16
18
  autoload :SourceBuffer, "cc/analyzer/source_buffer"
17
19
  autoload :UnitName, "cc/analyzer/unit_name"
@@ -0,0 +1,98 @@
1
+ require "posix/spawn"
2
+
3
+ module CC
4
+ module Analyzer
5
+ class Container
6
+ DEFAULT_TIMEOUT = 15 * 60 # 15m
7
+
8
+ def initialize(
9
+ image:,
10
+ name:,
11
+ command: nil,
12
+ log: NullContainerLog.new,
13
+ timeout: DEFAULT_TIMEOUT
14
+ )
15
+ @image = image
16
+ @name = name
17
+ @command = command
18
+ @log = log
19
+ @timeout = timeout
20
+
21
+ @output_delimeter = "\n"
22
+ @on_output = ->(*) { }
23
+
24
+ @timed_out = false
25
+ @stderr_io = StringIO.new
26
+ end
27
+
28
+ def on_output(delimeter = "\n", &block)
29
+ @output_delimeter = delimeter
30
+ @on_output = block
31
+ end
32
+
33
+ def run(options = [])
34
+ @log.started(@image, @name)
35
+
36
+ pid, _, out, err = POSIX::Spawn.popen4(*docker_run_command(options))
37
+
38
+ t_out = read_stdout(out)
39
+ t_err = read_stderr(err)
40
+ t_timeout = timeout_thread(pid)
41
+
42
+ _, status = Process.waitpid2(pid)
43
+
44
+ @log.finished(@image, @name, status, @stderr_io.string)
45
+
46
+ t_timeout.kill
47
+ ensure
48
+ t_timeout.kill if t_timeout
49
+
50
+ if @timed_out
51
+ @log.timed_out(@image, @name, @timeout)
52
+ t_out.kill if t_out
53
+ t_err.kill if t_err
54
+ else
55
+ t_out.join if t_out
56
+ t_err.join if t_err
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def docker_run_command(options)
63
+ [
64
+ "docker", "run",
65
+ "--rm",
66
+ "--name", @name,
67
+ options,
68
+ @image,
69
+ @command,
70
+ ].flatten.compact
71
+ end
72
+
73
+ def read_stdout(out)
74
+ Thread.new do
75
+ out.each_line(@output_delimeter) do |chunk|
76
+ output = chunk.chomp(@output_delimeter)
77
+
78
+ @on_output.call(output)
79
+ end
80
+ end
81
+ end
82
+
83
+ def read_stderr(err)
84
+ Thread.new do
85
+ err.each_line { |line| @stderr_io.write(line) }
86
+ end
87
+ end
88
+
89
+ def timeout_thread(pid)
90
+ Thread.new do
91
+ sleep @timeout
92
+ @timed_out = true
93
+ Process.kill("KILL", pid)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -1,12 +1,11 @@
1
- require "posix/spawn"
2
1
  require "securerandom"
3
2
 
4
3
  module CC
5
4
  module Analyzer
6
5
  class Engine
7
- attr_reader :name
6
+ autoload :ContainerLog, "cc/analyzer/engine/container_log"
8
7
 
9
- TIMEOUT = 15 * 60 # 15m
8
+ attr_reader :name
10
9
 
11
10
  def initialize(name, metadata, code_path, config, label)
12
11
  @name = name
@@ -16,88 +15,40 @@ module CC
16
15
  @label = label.to_s
17
16
  end
18
17
 
19
- def run(stdout_io, stderr_io = StringIO.new)
20
- timed_out = false
21
- pid, _, out, err = POSIX::Spawn.popen4(*docker_run_command)
22
- Analyzer.statsd.increment("cli.engines.started")
23
-
24
- t_out = Thread.new do
25
- out.each_line("\0") do |chunk|
26
- output = chunk.chomp("\0")
27
-
28
- unless output_filter.filter?(output)
29
- stdout_io.write(output)
30
- end
31
- end
32
- end
33
-
34
- t_err = Thread.new do
35
- err.each_line do |line|
36
- if stderr_io
37
- stderr_io.write(line)
38
- end
18
+ def run(stdout_io:, container_log: NullContainerLog.new)
19
+ container = Container.new(
20
+ image: @metadata["image"],
21
+ command: @metadata["command"],
22
+ name: container_name,
23
+ log: ContainerLog.new(name, container_log)
24
+ )
25
+
26
+ container.on_output("\0") do |output|
27
+ unless output_filter.filter?(output)
28
+ stdout_io.write(output)
39
29
  end
40
30
  end
41
31
 
42
- t_timeout = Thread.new do
43
- sleep TIMEOUT
44
- run_command("docker kill #{container_name} || true")
45
- timed_out = true
46
- end
47
-
48
- pid, status = Process.waitpid2(pid)
49
- t_timeout.kill
50
-
51
- Analyzer.statsd.increment("cli.engines.finished")
52
-
53
- if timed_out
54
- Analyzer.statsd.increment("cli.engines.result.error")
55
- Analyzer.statsd.increment("cli.engines.result.error.timeout")
56
- Analyzer.statsd.increment("cli.engines.names.#{name}.result.error")
57
- Analyzer.statsd.increment("cli.engines.names.#{name}.result.error.timeout")
58
- raise EngineTimeout, "engine #{name} ran past #{TIMEOUT} seconds and was killed"
59
- elsif status.success?
60
- Analyzer.statsd.increment("cli.engines.names.#{name}.result.success")
61
- Analyzer.statsd.increment("cli.engines.result.success")
62
- else
63
- Analyzer.statsd.increment("cli.engines.names.#{name}.result.error")
64
- Analyzer.statsd.increment("cli.engines.result.error")
65
- raise EngineFailure, "engine #{name} failed with status #{status.exitstatus} and stderr \n#{stderr_io.string}"
66
- end
67
- ensure
68
- t_timeout.kill if t_timeout
69
-
70
- if timed_out
71
- t_out.kill if t_out
72
- t_err.kill if t_err
73
- else
74
- t_out.join if t_out
75
- t_err.join if t_err
76
- end
32
+ container.run(container_options)
77
33
  end
78
34
 
79
35
  private
80
36
 
81
- def container_name
82
- @container_name ||= "cc-engines-#{name}-#{SecureRandom.uuid}"
83
- end
84
-
85
- def docker_run_command
37
+ def container_options
86
38
  [
87
- "docker", "run",
88
- "--rm",
89
39
  "--cap-drop", "all",
90
40
  "--label", "com.codeclimate.label=#{@label}",
91
- "--name", container_name,
92
41
  "--memory", 512_000_000.to_s, # bytes
93
42
  "--memory-swap", "-1",
94
43
  "--net", "none",
95
44
  "--volume", "#{@code_path}:/code:ro",
96
45
  "--volume", "#{config_file}:/config.json:ro",
97
46
  "--user", "9000:9000",
98
- @metadata["image"],
99
- @metadata["command"], # String or Array
100
- ].flatten.compact
47
+ ]
48
+ end
49
+
50
+ def container_name
51
+ @container_name ||= "cc-engines-#{name}-#{SecureRandom.uuid}"
101
52
  end
102
53
 
103
54
  def config_file
@@ -106,21 +57,9 @@ module CC
106
57
  path
107
58
  end
108
59
 
109
- def run_command(command)
110
- spawn = POSIX::Spawn::Child.new(command)
111
-
112
- unless spawn.status.success?
113
- raise CommandFailure, "command '#{command}' failed with status #{spawn.status.exitstatus} and output #{spawn.err}"
114
- end
115
- end
116
-
117
60
  def output_filter
118
61
  @output_filter ||= EngineOutputFilter.new(@config)
119
62
  end
120
-
121
- CommandFailure = Class.new(StandardError)
122
- EngineFailure = Class.new(StandardError)
123
- EngineTimeout = Class.new(StandardError)
124
63
  end
125
64
  end
126
65
  end
@@ -0,0 +1,48 @@
1
+ module CC
2
+ module Analyzer
3
+ class Engine
4
+ EngineFailure = Class.new(StandardError)
5
+ EngineTimeout = Class.new(StandardError)
6
+
7
+ class ContainerLog
8
+ def initialize(name, inner_log)
9
+ @name = name
10
+ @inner_log = inner_log
11
+ end
12
+
13
+ def started(image, name)
14
+ @inner_log.started(image, name)
15
+
16
+ Analyzer.statsd.increment("cli.engines.started")
17
+ end
18
+
19
+ def timed_out(image, name, timeout)
20
+ @inner_log.timed_out(image, name, timeout)
21
+
22
+ Analyzer.statsd.increment("cli.engines.result.error")
23
+ Analyzer.statsd.increment("cli.engines.result.error.timeout")
24
+ Analyzer.statsd.increment("cli.engines.names.#{@name}.result.error")
25
+ Analyzer.statsd.increment("cli.engines.names.#{@name}.result.error.timeout")
26
+
27
+ raise EngineTimeout, "engine #{@name} ran past #{timeout} seconds and was killed"
28
+ end
29
+
30
+ def finished(image, name, status, stderr)
31
+ @inner_log.finished(image, name, status, stderr)
32
+
33
+ Analyzer.statsd.increment("cli.engines.finished")
34
+
35
+ if status.success?
36
+ Analyzer.statsd.increment("cli.engines.result.success")
37
+ Analyzer.statsd.increment("cli.engines.names.#{@name}.result.success")
38
+ else
39
+ Analyzer.statsd.increment("cli.engines.result.error")
40
+ Analyzer.statsd.increment("cli.engines.names.#{@name}.result.error")
41
+
42
+ raise EngineFailure, "engine #{@name} failed with status #{status.exitstatus} and stderr \n#{stderr}"
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -14,14 +14,14 @@ module CC
14
14
  @container_label = container_label
15
15
  end
16
16
 
17
- def run
17
+ def run(container_log = NullContainerLog.new)
18
18
  raise NoEnabledEngines if engines.empty?
19
19
 
20
20
  Analyzer.logger.info("running #{engines.size} engines")
21
21
 
22
22
  @formatter.started
23
23
 
24
- engines.each { |engine| run_engine(engine) }
24
+ engines.each { |engine| run_engine(engine, container_log) }
25
25
 
26
26
  @formatter.finished
27
27
  ensure
@@ -30,13 +30,16 @@ module CC
30
30
 
31
31
  private
32
32
 
33
- def run_engine(engine)
33
+ def run_engine(engine, container_log)
34
34
  Analyzer.logger.info("starting engine #{engine.name}")
35
35
 
36
36
  Analyzer.statsd.time("engines.time") do
37
37
  Analyzer.statsd.time("engines.names.#{engine.name}.time") do
38
38
  @formatter.engine_running(engine) do
39
- engine.run(@formatter)
39
+ engine.run(
40
+ stdout_io: @formatter,
41
+ container_log: container_log
42
+ )
40
43
  end
41
44
  end
42
45
  end
@@ -80,7 +83,15 @@ module CC
80
83
  end
81
84
 
82
85
  def exclude_paths
83
- PathPatterns.new(@config.exclude_paths || []).expanded
86
+ PathPatterns.new(@config.exclude_paths || []).expanded + gitignore_paths
87
+ end
88
+
89
+ def gitignore_paths
90
+ if File.exist?(".gitignore")
91
+ `git ls-files --others -i -z --exclude-from .gitignore`.split("\0")
92
+ else
93
+ []
94
+ end
84
95
  end
85
96
  end
86
97
  end
@@ -0,0 +1,14 @@
1
+ module CC
2
+ module Analyzer
3
+ class NullContainerLog
4
+ def started(_image, _name)
5
+ end
6
+
7
+ def timed_out(_image, _name, _seconds)
8
+ end
9
+
10
+ def finished(_image, _name, _status, _stderr)
11
+ end
12
+ end
13
+ end
14
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codeclimate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code Climate
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-03 00:00:00.000000000 Z
11
+ date: 2015-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -191,7 +191,9 @@ files:
191
191
  - config/engines.yml
192
192
  - lib/cc/analyzer.rb
193
193
  - lib/cc/analyzer/config.rb
194
+ - lib/cc/analyzer/container.rb
194
195
  - lib/cc/analyzer/engine.rb
196
+ - lib/cc/analyzer/engine/container_log.rb
195
197
  - lib/cc/analyzer/engine_output_filter.rb
196
198
  - lib/cc/analyzer/engine_registry.rb
197
199
  - lib/cc/analyzer/engines_runner.rb
@@ -204,6 +206,7 @@ files:
204
206
  - lib/cc/analyzer/issue_sorter.rb
205
207
  - lib/cc/analyzer/location_description.rb
206
208
  - lib/cc/analyzer/null_config.rb
209
+ - lib/cc/analyzer/null_container_log.rb
207
210
  - lib/cc/analyzer/path_patterns.rb
208
211
  - lib/cc/analyzer/source_buffer.rb
209
212
  - lib/cc/analyzer/unit_name.rb