foreman 0.0.1

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.
@@ -0,0 +1,77 @@
1
+ = Foreman
2
+
3
+ === Procfile
4
+
5
+ alpha ./bin/alpha
6
+ bravo ./bin/bravo some args
7
+ charlie ./bin/charlie -n 5
8
+
9
+ == Development mode
10
+
11
+ === Running
12
+
13
+ $ foreman start
14
+ [foreman] [Tue May 18 01:27:08 UTC 2010] [alpha] started with pid 4393
15
+ [foreman] [Tue May 18 01:27:08 UTC 2010] [bravo] started with pid 4394
16
+ [foreman] [Tue May 18 01:27:08 UTC 2010] [charlie] started with pid 4395
17
+
18
+ === Standardized Logging
19
+
20
+ log/alpha.log
21
+ log/bravo.log
22
+ log/charlie.log
23
+
24
+ == Upstart
25
+
26
+ === Export to upstart scripts
27
+
28
+ $ foreman export sampleapp
29
+
30
+ $ initctl list | grep sampleapp
31
+ sampleapp start/running
32
+ sampleapp-alpha (1) start/running, process 4204
33
+ sampleapp-bravo (1) start/running, process 4589
34
+ sampleapp-charlie (1) start/running, process 4597
35
+
36
+ === Change process concurrency levels
37
+
38
+ $ foreman scale sampleapp alpha 4
39
+ sampleapp-alpha (2) start/running, process 4164
40
+ sampleapp-alpha (3) start/running, process 4166
41
+ sampleapp-alpha (4) start/running, process 4168
42
+
43
+ $ initctl list | grep sampleapp
44
+ sampleapp start/running
45
+ sampleapp-alpha (4) start/running, process 4168
46
+ sampleapp-alpha (3) start/running, process 4166
47
+ sampleapp-alpha (2) start/running, process 4164
48
+ sampleapp-alpha (1) start/running, process 4204
49
+ sampleapp-bravo (1) start/running, process 4589
50
+ sampleapp-charlie (1) start/running, process 4597
51
+
52
+ $ foreman scale sampleapp alpha 1
53
+ sampleapp-alpha stop/waiting
54
+ sampleapp-alpha stop/waiting
55
+ sampleapp-alpha stop/waiting
56
+
57
+ === Good Upstart citizen
58
+
59
+ All Upstart commands work as expected
60
+
61
+ $ start sampleapp
62
+ $ stop sampleapp
63
+ $ restart sampleapp
64
+
65
+ === Standardized Logging
66
+
67
+ /var/log/sampleapp/alpha.log
68
+ /var/log/sampleapp/bravo.log
69
+ /var/log/sampleapp/charlie.log
70
+
71
+ == License
72
+
73
+ MIT
74
+
75
+ == Copyright
76
+
77
+ (c) 2010 David Dollar
@@ -0,0 +1,60 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "rspec/core/rake_task"
4
+
5
+ $:.unshift File.expand_path("../lib", __FILE__)
6
+ require "foreman"
7
+
8
+ task :default => :spec
9
+
10
+ desc "Run all specs"
11
+ Rspec::Core::RakeTask.new(:spec) do |t|
12
+ t.pattern = 'spec/**/*_spec.rb'
13
+ end
14
+
15
+ desc "Generate RCov code coverage report"
16
+ task :rcov => "rcov:build" do
17
+ %x{ open coverage/index.html }
18
+ end
19
+
20
+ Rspec::Core::RakeTask.new("rcov:build") do |t|
21
+ t.pattern = 'spec/**/*_spec.rb'
22
+ t.rcov = true
23
+ t.rcov_opts = [ "--exclude", Gem.default_dir , "--exclude", "spec" ]
24
+ end
25
+
26
+ ######################################################
27
+
28
+ begin
29
+ require 'jeweler'
30
+ Jeweler::Tasks.new do |s|
31
+ s.name = "foreman"
32
+ s.version = Foreman::VERSION
33
+
34
+ s.summary = "Process manager for applications with multiple components"
35
+ s.description = s.summary
36
+ s.author = "David Dollar"
37
+ s.email = "ddollar@gmail.com"
38
+ s.homepage = "http://github.com/ddollar/foreman"
39
+
40
+ s.platform = Gem::Platform::RUBY
41
+ s.has_rdoc = false
42
+
43
+ s.files = %w(Rakefile README.md) + Dir["{bin,lib,spec}/**/*"]
44
+ s.require_path = "lib"
45
+
46
+ # #s.bindir = "bin"
47
+ # s.executables = Dir["bin/*"]
48
+ s.default_executable = "foreman"
49
+
50
+ s.add_development_dependency 'fakefs', '~> 0.2.1'
51
+ s.add_development_dependency 'rake', '~> 0.8.7'
52
+ s.add_development_dependency 'rcov', '~> 0.9.8'
53
+ s.add_development_dependency 'rr', '~> 0.10.11'
54
+ s.add_development_dependency 'rspec', '~> 2.0.0'
55
+
56
+ s.add_dependency 'thor', '~> 0.13.6'
57
+ end
58
+ rescue LoadError
59
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
60
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+
5
+ require "foreman/cli"
6
+
7
+ Foreman::CLI.start
@@ -0,0 +1,8 @@
1
+ module Foreman
2
+
3
+ VERSION = "0.0.1"
4
+
5
+ class AppDoesNotExist < Exception; end
6
+
7
+ end
8
+
@@ -0,0 +1,50 @@
1
+ require "foreman"
2
+ require "foreman/configuration"
3
+ require "foreman/engine"
4
+ require "foreman/export"
5
+ require "thor"
6
+
7
+ class Foreman::CLI < Thor
8
+
9
+ desc "start [PROCFILE]", "Run the app described in PROCFILE"
10
+
11
+ def start(procfile="Procfile")
12
+ error "#{procfile} does not exist." unless procfile_exists?(procfile)
13
+ Foreman::Engine.new(procfile).start
14
+ end
15
+
16
+ desc "export APP [PROCFILE] [FORMAT]", "Export the app described in PROCFILE as APP to another FORMAT"
17
+
18
+ def export(app, procfile="Procfile", format="upstart")
19
+ error "#{procfile} does not exist." unless procfile_exists?(procfile)
20
+
21
+ formatter = case format
22
+ when "upstart" then Foreman::Export::Upstart
23
+ else error "Unknown export format: #{format}."
24
+ end
25
+
26
+ formatter.new(Foreman::Engine.new(procfile)).export(app)
27
+ end
28
+
29
+ desc "scale APP PROCESS AMOUNT", "Change the concurrency of a given process type"
30
+
31
+ def scale(app, process, amount)
32
+ config = Foreman::Configuration.new(app)
33
+ error "No such process: #{process}." unless config.processes[process]
34
+ config.scale(process, amount)
35
+ rescue Foreman::AppDoesNotExist
36
+ error "No such app: #{app}."
37
+ end
38
+
39
+ private ######################################################################
40
+
41
+ def error(message)
42
+ puts "ERROR: #{message}"
43
+ exit 1
44
+ end
45
+
46
+ def procfile_exists?(procfile)
47
+ File.exist?(procfile)
48
+ end
49
+
50
+ end
@@ -0,0 +1,59 @@
1
+ require "foreman"
2
+
3
+ class Foreman::Configuration
4
+
5
+ attr_reader :app
6
+ attr_reader :processes
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ @processes = {}
11
+ read_initial_config
12
+ end
13
+
14
+ def scale(process, amount)
15
+ old_amount = processes[process].to_i
16
+ processes[process] = amount.to_i
17
+ amount = amount.to_i
18
+
19
+ if (old_amount < amount)
20
+ ((old_amount + 1) .. amount).each { |num| run "start #{app}-#{process} NUM=#{num}" }
21
+ elsif (amount < old_amount)
22
+ ((amount + 1) .. old_amount).each { |num| run "stop #{app}-#{process} NUM=#{num}" }
23
+ end
24
+
25
+ write
26
+ end
27
+
28
+ def write
29
+ write_file "/etc/foreman/#{app}.conf", <<-UPSTART_CONFIG
30
+ #{app}_processes="#{processes.keys.join(' ')}"
31
+ #{processes.keys.map { |k| "#{app}_#{k}=\"#{processes[k]}\"" }.join("\n")}
32
+ UPSTART_CONFIG
33
+ end
34
+
35
+ private ######################################################################
36
+
37
+ def read_initial_config
38
+ config = File.read("/etc/foreman/#{app}.conf").split("\n").inject({}) do |accum, line|
39
+ key, value = line.match(/^(.+?)\s*=\s*"(.+?)"\s*$/).captures
40
+ #accum.update(parts(1) => parts(2))
41
+ accum.update(key => value)
42
+ end
43
+ config["#{app}_processes"].split(" ").each do |process|
44
+ processes[process] = config["#{app}_#{process}"].to_i
45
+ end
46
+ rescue Errno::ENOENT
47
+ end
48
+
49
+ def run(command)
50
+ system command
51
+ end
52
+
53
+ def write_file(filename, contents)
54
+ File.open(filename, "w") do |file|
55
+ file.puts contents
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,91 @@
1
+ require "foreman"
2
+ require "foreman/process"
3
+
4
+ class Foreman::Engine
5
+
6
+ attr_reader :procfile
7
+ attr_reader :directory
8
+
9
+ def initialize(procfile)
10
+ @procfile = read_procfile(procfile)
11
+ @directory = File.expand_path(File.dirname(procfile))
12
+ end
13
+
14
+ def processes
15
+ @processes ||= begin
16
+ procfile.split("\n").inject({}) do |hash, line|
17
+ next if line.strip == ""
18
+ process = Foreman::Process.new(*line.split(" ", 2))
19
+ hash.update(process.name => process)
20
+ end
21
+ end
22
+ end
23
+
24
+ def start
25
+ proctitle "ruby: foreman master"
26
+
27
+ processes.each do |name, process|
28
+ fork process
29
+ end
30
+
31
+ trap("TERM") { kill_and_exit("TERM") }
32
+ trap("INT") { kill_and_exit("INT") }
33
+
34
+ while true
35
+ pid, status = Process.wait2
36
+ process = running_processes.delete(pid)
37
+ info "exited with code #{status}", process
38
+ fork process
39
+ end
40
+ end
41
+
42
+ private ######################################################################
43
+
44
+ def fork(process)
45
+ pid = Process.fork do
46
+ proctitle "ruby: foreman #{process.name}"
47
+
48
+ Dir.chdir directory do
49
+ FileUtils.mkdir_p "log"
50
+ system "#{process.command} >>log/#{process.name}.log 2>&1"
51
+ exit $?.exitstatus || 255
52
+ end
53
+ end
54
+
55
+ info "started with pid #{pid}", process
56
+ running_processes[pid] = process
57
+ end
58
+
59
+ def kill_and_exit(signal="TERM")
60
+ info "termination requested"
61
+ running_processes.each do |pid, process|
62
+ info "killing pid #{pid}", process
63
+ Process.kill(signal, pid)
64
+ end
65
+ exit 0
66
+ end
67
+
68
+ def info(message, process=nil)
69
+ puts "[foreman] [#{Time.now.utc}] [#{process ? process.name : "system"}] #{message}"
70
+ end
71
+
72
+ def print_info
73
+ info "currently running processes:"
74
+ running_processes.each do |pid, process|
75
+ info "pid #{pid}", process
76
+ end
77
+ end
78
+
79
+ def read_procfile(procfile)
80
+ File.read(procfile)
81
+ end
82
+
83
+ def running_processes
84
+ @running_processes ||= {}
85
+ end
86
+
87
+ def proctitle(title)
88
+ $0 = title
89
+ end
90
+
91
+ end
@@ -0,0 +1,6 @@
1
+ require "foreman"
2
+
3
+ module Foreman::Export
4
+ end
5
+
6
+ require "foreman/export/upstart"
@@ -0,0 +1,66 @@
1
+ require "foreman/configuration"
2
+ require "foreman/export"
3
+
4
+ class Foreman::Export::Upstart
5
+
6
+ attr_reader :engine
7
+
8
+ def initialize(engine)
9
+ @engine = engine
10
+ end
11
+
12
+ def export(app)
13
+ FileUtils.mkdir_p "/etc/foreman"
14
+ FileUtils.mkdir_p "/etc/init"
15
+
16
+ config = Foreman::Configuration.new(app)
17
+
18
+ engine.processes.each do |name, process|
19
+ config.scale(name, 1)
20
+ end
21
+ config.write
22
+
23
+ write_file "/etc/init/#{app}.conf", <<-UPSTART_MASTER
24
+ pre-start script
25
+
26
+ bash << "EOF"
27
+ mkdir -p /var/log/#{app}
28
+
29
+ if [ -f /etc/foreman/#{app}.conf ]; then
30
+ source /etc/foreman/#{app}.conf
31
+ fi
32
+
33
+ for process in $( echo "$#{app}_processes" ); do
34
+ process_count_config="#{app}_$process"
35
+ process_count=${!process_count_config}
36
+
37
+ for ((i=1; i<=${process_count:=1}; i+=1)); do
38
+ start #{app}-$process NUM=$i
39
+ done
40
+ done
41
+ EOF
42
+
43
+ end script
44
+ UPSTART_MASTER
45
+
46
+ engine.processes.values.each do |process|
47
+ write_file "/etc/init/#{app}-#{process.name}.conf", <<-UPSTART_CHILD
48
+ instance $NUM
49
+ stop on stopping #{app}
50
+ respawn
51
+
52
+ chdir #{engine.directory}
53
+ exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1
54
+ UPSTART_CHILD
55
+ end
56
+ end
57
+
58
+ private ######################################################################
59
+
60
+ def write_file(filename, contents)
61
+ File.open(filename, "w") do |file|
62
+ file.puts contents
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,13 @@
1
+ require "foreman"
2
+
3
+ class Foreman::Process
4
+
5
+ attr_reader :name
6
+ attr_reader :command
7
+
8
+ def initialize(name, command)
9
+ @name = name
10
+ @command = command
11
+ end
12
+
13
+ end
@@ -0,0 +1,88 @@
1
+ require "spec_helper"
2
+ require "foreman/cli"
3
+
4
+ describe "Foreman::CLI" do
5
+ subject { Foreman::CLI.new }
6
+
7
+ describe "start" do
8
+ #let(:engine) { stub_engine }
9
+
10
+ describe "with a non-existent Procifile" do
11
+ it "prints an error" do
12
+ mock_error(subject, "Procfile does not exist.") do
13
+ dont_allow.instance_of(Foreman::Engine).start
14
+ subject.start
15
+ end
16
+ end
17
+ end
18
+
19
+ describe "with a Procfile" do
20
+ before(:each) { write_procfile }
21
+
22
+ it "runs successfully" do
23
+ dont_allow(subject).error
24
+ mock.instance_of(Foreman::Engine).start
25
+ subject.start
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "export" do
31
+ describe "with a non-existent Procifile" do
32
+ it "prints an error" do
33
+ mock_error(subject, "Procfile does not exist.") do
34
+ dont_allow.instance_of(Foreman::Engine).export
35
+ subject.export("testapp")
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "with a Procfile" do
41
+ before(:each) { write_procfile }
42
+
43
+ describe "with an invalid formatter" do
44
+ it "prints an error" do
45
+ mock_error(subject, "Unknown export format: invalidformatter.") do
46
+ subject.export("testapp", "Procfile", "invalidformatter")
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "with a valid config" do
52
+ before(:each) { write_foreman_config("testapp") }
53
+
54
+ it "runs successfully" do
55
+ dont_allow(subject).error
56
+ subject.export("testapp")
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "scale" do
63
+ describe "without an existing configuration" do
64
+ it "displays an error" do
65
+ mock_error(subject, "No such app: testapp.") do
66
+ subject.scale("testapp", "alpha", "2")
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "with an existing configuration" do
72
+ before(:each) { write_foreman_config("testapp") }
73
+
74
+ it "scales a process that exists" do
75
+ mock.instance_of(Foreman::Configuration).scale("alpha", "2")
76
+ subject.scale("testapp", "alpha", "2")
77
+ end
78
+
79
+ it "errors if a process that does not exist is specified" do
80
+ mock_error(subject, "No such process: invalidprocess.") do
81
+ dont_allow.instance_of(Foreman::Configuration).scale
82
+ subject.scale("testapp", "invalidprocess", "2")
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ end
@@ -0,0 +1,2 @@
1
+ require "spec_helper"
2
+ require "foreman/configuration"
@@ -0,0 +1,2 @@
1
+ require "spec_helper"
2
+ require "foreman/engine"
@@ -0,0 +1,2 @@
1
+ require "spec_helper"
2
+ require "foreman/export/upstart"
@@ -0,0 +1,2 @@
1
+ require "spec_helper"
2
+ require "foreman/export"
@@ -0,0 +1,2 @@
1
+ require "spec_helper"
2
+ require "foreman/process"
@@ -0,0 +1,11 @@
1
+ require "spec_helper"
2
+ require "foreman"
3
+
4
+ describe Foreman do
5
+
6
+ describe "VERSION" do
7
+ subject { Foreman::VERSION }
8
+ it { should be_a String }
9
+ end
10
+
11
+ end
@@ -0,0 +1,36 @@
1
+ require "fakefs/spec_helpers"
2
+ require "rspec"
3
+
4
+ $:.unshift "lib"
5
+
6
+ def mock_error(subject, message)
7
+ mock_exit do
8
+ mock(subject).puts("ERROR: #{message}")
9
+ yield
10
+ end
11
+ end
12
+
13
+ def mock_exit(&block)
14
+ block.should raise_error(SystemExit)
15
+ end
16
+
17
+ def write_foreman_config(app)
18
+ File.open("/etc/foreman/#{app}.conf", "w") do |file|
19
+ file.puts %{#{app}_processes="alpha bravo"}
20
+ file.puts %{#{app}_alpha="1"}
21
+ file.puts %{#{app}_bravo="2"}
22
+ end
23
+ end
24
+
25
+ def write_procfile(procfile="Procfile")
26
+ File.open(procfile, "w") do |file|
27
+ file.puts "alpha ./alpha"
28
+ file.puts "bravo ./bravo"
29
+ end
30
+ end
31
+
32
+ Rspec.configure do |config|
33
+ config.color_enabled = true
34
+ config.include FakeFS::SpecHelpers
35
+ config.mock_with :rr
36
+ end
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: foreman
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - David Dollar
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-05-20 00:00:00 -04:00
19
+ default_executable: foreman
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: fakefs
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 21
30
+ segments:
31
+ - 0
32
+ - 2
33
+ - 1
34
+ version: 0.2.1
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 49
46
+ segments:
47
+ - 0
48
+ - 8
49
+ - 7
50
+ version: 0.8.7
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rcov
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 43
62
+ segments:
63
+ - 0
64
+ - 9
65
+ - 8
66
+ version: 0.9.8
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: rr
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ hash: 33
78
+ segments:
79
+ - 0
80
+ - 10
81
+ - 11
82
+ version: 0.10.11
83
+ type: :development
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: rspec
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ hash: 15
94
+ segments:
95
+ - 2
96
+ - 0
97
+ - 0
98
+ version: 2.0.0
99
+ type: :development
100
+ version_requirements: *id005
101
+ - !ruby/object:Gem::Dependency
102
+ name: thor
103
+ prerelease: false
104
+ requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ hash: 39
110
+ segments:
111
+ - 0
112
+ - 13
113
+ - 6
114
+ version: 0.13.6
115
+ type: :runtime
116
+ version_requirements: *id006
117
+ description: Process manager for applications with multiple components
118
+ email: ddollar@gmail.com
119
+ executables:
120
+ - foreman
121
+ extensions: []
122
+
123
+ extra_rdoc_files:
124
+ - README.rdoc
125
+ files:
126
+ - Rakefile
127
+ - bin/foreman
128
+ - lib/foreman.rb
129
+ - lib/foreman/cli.rb
130
+ - lib/foreman/configuration.rb
131
+ - lib/foreman/engine.rb
132
+ - lib/foreman/export.rb
133
+ - lib/foreman/export/upstart.rb
134
+ - lib/foreman/process.rb
135
+ - spec/foreman/cli_spec.rb
136
+ - spec/foreman/configuration_spec.rb
137
+ - spec/foreman/engine_spec.rb
138
+ - spec/foreman/export/upstart_spec.rb
139
+ - spec/foreman/export_spec.rb
140
+ - spec/foreman/process_spec.rb
141
+ - spec/foreman_spec.rb
142
+ - spec/spec_helper.rb
143
+ - README.rdoc
144
+ has_rdoc: false
145
+ homepage: http://github.com/ddollar/foreman
146
+ licenses: []
147
+
148
+ post_install_message:
149
+ rdoc_options:
150
+ - --charset=UTF-8
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ hash: 3
159
+ segments:
160
+ - 0
161
+ version: "0"
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ hash: 3
168
+ segments:
169
+ - 0
170
+ version: "0"
171
+ requirements: []
172
+
173
+ rubyforge_project:
174
+ rubygems_version: 1.3.7
175
+ signing_key:
176
+ specification_version: 3
177
+ summary: Process manager for applications with multiple components
178
+ test_files:
179
+ - spec/foreman/cli_spec.rb
180
+ - spec/foreman/configuration_spec.rb
181
+ - spec/foreman/engine_spec.rb
182
+ - spec/foreman/export/upstart_spec.rb
183
+ - spec/foreman/export_spec.rb
184
+ - spec/foreman/process_spec.rb
185
+ - spec/foreman_spec.rb
186
+ - spec/spec_helper.rb