ruby_yacht 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile.lock +1 -1
  3. data/doc/TODO.md +16 -6
  4. data/doc/configuration_sample.rb +8 -9
  5. data/lib/ruby_yacht/dsl/app.rb +29 -1
  6. data/lib/ruby_yacht/dsl/app_type.rb +112 -0
  7. data/lib/ruby_yacht/dsl/configuration.rb +163 -2
  8. data/lib/ruby_yacht/dsl/dsl.rb +51 -9
  9. data/lib/ruby_yacht/dsl/hook.rb +105 -0
  10. data/lib/ruby_yacht/dsl/project.rb +17 -21
  11. data/lib/ruby_yacht/dsl.rb +2 -0
  12. data/lib/ruby_yacht/images/app/Dockerfile.erb +20 -13
  13. data/lib/ruby_yacht/images/app/before_startup.bash.erb +8 -0
  14. data/lib/ruby_yacht/images/app/checkout.bash +6 -0
  15. data/lib/ruby_yacht/images/app/startup.bash.erb +5 -0
  16. data/lib/ruby_yacht/images/app-dependencies/Dockerfile.erb +23 -5
  17. data/lib/ruby_yacht/images/database/Dockerfile.erb +25 -11
  18. data/lib/ruby_yacht/images/database/checkout.bash +10 -0
  19. data/lib/ruby_yacht/images/database/setup.bash +15 -0
  20. data/lib/ruby_yacht/images/web/Dockerfile.erb +4 -3
  21. data/lib/ruby_yacht/plugins/rails/scripts/install_gems.rb +3 -0
  22. data/lib/ruby_yacht/plugins/rails/scripts/load_seeds.rb +34 -0
  23. data/lib/ruby_yacht/{images/app/startup.rb → plugins/rails/scripts/prepare_rails_for_launch.rb} +2 -8
  24. data/lib/ruby_yacht/{images/app/update_database_config.rb → plugins/rails/scripts/update_rails_config.rb} +0 -1
  25. data/lib/ruby_yacht/plugins/rails.rb +40 -0
  26. data/lib/ruby_yacht/plugins.rb +6 -0
  27. data/lib/ruby_yacht/runner/build_images.rb +72 -5
  28. data/lib/ruby_yacht/runner/checkout.rb +1 -1
  29. data/lib/ruby_yacht.rb +2 -1
  30. data/ruby_yacht.gemspec +2 -1
  31. data/spec/docker/Dockerfile +1 -1
  32. data/spec/dsl/app_spec.rb +34 -0
  33. data/spec/dsl/app_type_spec.rb +176 -0
  34. data/spec/dsl/configuration_spec.rb +161 -2
  35. data/spec/dsl/dsl_spec.rb +3 -3
  36. data/spec/dsl/hook_spec.rb +111 -0
  37. data/spec/dsl/project_spec.rb +19 -83
  38. data/spec/fixtures/app-dependencies-dockerfile-generic +21 -0
  39. data/spec/fixtures/app-dependencies-dockerfile-generic-with-library-install +28 -0
  40. data/spec/fixtures/app-dependencies-dockerfile-rails +32 -0
  41. data/spec/fixtures/database-dockerfile +16 -15
  42. data/spec/fixtures/database-dockerfile-rails +35 -0
  43. data/spec/fixtures/database-dockerfile-with-seed-hooks +34 -0
  44. data/spec/fixtures/hooks/hook1.rb +0 -0
  45. data/spec/fixtures/hooks/hook2.rb +0 -0
  46. data/spec/fixtures/mars-before-startup +4 -0
  47. data/spec/fixtures/mars-before-startup-rails +7 -0
  48. data/spec/fixtures/mars-before-startup-with-before-startup-hooks +7 -0
  49. data/spec/fixtures/mars-dockerfile +9 -14
  50. data/spec/fixtures/mars-dockerfile-rails +33 -0
  51. data/spec/fixtures/mars-dockerfile-with-after-checkout-hooks +30 -0
  52. data/spec/fixtures/mars-dockerfile-with-before-startup-hooks +29 -0
  53. data/spec/fixtures/mars-startup +3 -0
  54. data/spec/fixtures/mars-startup-rails +3 -0
  55. data/spec/fixtures/multi-project-web-dockerfile +0 -10
  56. data/spec/fixtures/web-dockerfile +0 -6
  57. data/spec/plugins/rails_spec.rb +198 -0
  58. data/spec/runner/build_images_spec.rb +181 -15
  59. data/spec/runner/checkout_spec.rb +2 -2
  60. data/spec/support/test_project.rb +16 -8
  61. metadata +62 -30
  62. data/lib/ruby_yacht/images/app/checkout.rb +0 -7
  63. data/lib/ruby_yacht/images/app-dependencies/install_gems.rb +0 -12
  64. data/lib/ruby_yacht/images/database/load_seeds.rb +0 -42
  65. data/lib/ruby_yacht/images/database/setup.rb +0 -19
  66. data/lib/ruby_yacht/images/database/setup_database.sql.erb +0 -12
  67. data/spec/fixtures/app-dependencies-dockerfile +0 -25
@@ -0,0 +1,176 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyYacht::AppType do
4
+ let(:full_config_block) do
5
+ Proc.new do
6
+ baseline_image 'ubuntu'
7
+ project_attribute name: :environment, default: 'staging'
8
+ project_attribute name: :foo
9
+
10
+ app_attribute name: :bar, required: false
11
+
12
+ environment_variable :app, 'SECRET_KEY' do
13
+ @app.secret_key
14
+ end
15
+ end
16
+ end
17
+
18
+ before do
19
+ RubyYacht.configuration.clear
20
+ RubyYacht.configure do
21
+ app_type(:generic) { baseline_image 'ubuntu' }
22
+ end
23
+ end
24
+
25
+ describe "setting attributes on other DSL types" do
26
+ let(:project_configuration_block) do
27
+ Proc.new do
28
+ system_prefix 'test-project'
29
+ repository 'github.com'
30
+ domain 'test.com'
31
+ database do
32
+ host 'localhost'
33
+ name 'test'
34
+ username 'test'
35
+ password 'test'
36
+ end
37
+ end
38
+ end
39
+
40
+ before do
41
+ block = full_config_block
42
+ RubyYacht.configure do
43
+ app_type :app_type_test do
44
+ instance_eval(&block)
45
+ end
46
+ end
47
+ end
48
+
49
+ it "defines a method for adding an app with this type to the project" do
50
+ block = project_configuration_block
51
+ RubyYacht.configure do
52
+ project :test do
53
+ instance_eval &block
54
+ app_type_test_foo 'test value'
55
+
56
+ app_type_test_app :test do
57
+ repository_name 'brownleej/test'
58
+ end
59
+ end
60
+ end
61
+
62
+ app = RubyYacht.configuration.projects.last.apps.first
63
+ expect(app.name).to eq :test
64
+ expect(app.app_type).to eq :app_type_test
65
+ end
66
+
67
+ it "creates attributes for the project attributes on the Project DSL" do
68
+ block = project_configuration_block
69
+ RubyYacht.configure do
70
+ project :test do
71
+ instance_eval &block
72
+ app_type_test_foo 'test value'
73
+ end
74
+ end
75
+
76
+ project = RubyYacht.configuration.projects.last
77
+ expect(project.app_type_test_environment).to eq 'staging'
78
+ expect(project.app_type_test_foo).to eq 'test value'
79
+ end
80
+
81
+ it "creates attributes for the app attributes on apps of this type" do
82
+ block = project_configuration_block
83
+ RubyYacht.configure do
84
+ project :test do
85
+ instance_eval &block
86
+ app_type_test_foo 'test value'
87
+
88
+ app :test1, :app_type_test do
89
+ app_type_test_bar 'baz'
90
+ repository_name 'brownleej/test'
91
+ end
92
+ end
93
+ end
94
+
95
+ project = RubyYacht.configuration.projects.last
96
+ app = project.apps.last
97
+ expect(app.app_type_test_bar).to eq 'baz'
98
+ end
99
+
100
+ it "does not create attributes on apps of other types" do
101
+ raised_exception = false
102
+ block = project_configuration_block
103
+ RubyYacht.configure do
104
+ project :test do
105
+ instance_eval &block
106
+ app_type_test_foo 'test value'
107
+
108
+ app :test1, :generic do
109
+ begin
110
+ app_type_test_bar 'baz'
111
+ rescue
112
+ raised_exception = true
113
+ end
114
+ repository_name 'brownleej/test'
115
+ end
116
+ end
117
+ end
118
+
119
+ project = RubyYacht.configuration.projects.last
120
+ app = project.apps.last
121
+ expect(raised_exception).to be_truthy
122
+ expect(app.app_type_test_bar).to be_nil
123
+ end
124
+
125
+ context "with a missing required attribute" do
126
+ it "raises an exception" do
127
+ block = project_configuration_block
128
+ expect(lambda do
129
+ RubyYacht.configure do
130
+ project :test do
131
+ instance_eval &block
132
+ end
133
+ end
134
+ end).to raise_exception "Missing required attribute app_type_test_foo for RubyYacht::Project::DSL"
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "dsl" do
140
+ let(:dsl) { RubyYacht::AppType::DSL.new(:app_type_test) }
141
+ let(:app_type) { dsl.run(@config_block).create_object }
142
+
143
+ before do
144
+ @config_block = full_config_block
145
+ end
146
+
147
+ it "sets the information on the app type" do
148
+ expect(app_type.name).to eq :app_type_test
149
+ expect(app_type.baseline_image).to eq 'ubuntu'
150
+
151
+ expect(app_type.project_attributes.count).to eq 2
152
+ expect(app_type.project_attributes[0]).to eq(name: :environment, default: 'staging')
153
+ expect(app_type.project_attributes[1]).to eq(name: :foo)
154
+
155
+ expect(app_type.app_attributes.count).to eq 1
156
+ expect(app_type.app_attributes[0]).to eq(name: :bar, required: false)
157
+
158
+ @app = Object.new
159
+ @app.define_singleton_method :secret_key do
160
+ 'abc1234'
161
+ end
162
+
163
+ expect(app_type.environment_variables.count).to eq 1
164
+ expect(app_type.environment_variables[0][:name]).to eq 'SECRET_KEY'
165
+ expect(app_type.environment_variables[0][:image]).to eq :app
166
+ expect(instance_eval(&app_type.environment_variables[0][:block])).to eq 'abc1234'
167
+ end
168
+
169
+ context "with no baseline image" do
170
+ it "raises an exception" do
171
+ @config_block = Proc.new {}
172
+ expect { app_type }.to raise_exception "Missing required attribute baseline_image for RubyYacht::AppType::DSL"
173
+ end
174
+ end
175
+ end
176
+ end
@@ -6,13 +6,65 @@ describe RubyYacht::Configuration do
6
6
  RubyYacht.configuration.clear
7
7
  end
8
8
 
9
+ describe "reading configuration" do
10
+ describe "fetch_hooks" do
11
+ before do
12
+ RubyYacht.configure do
13
+ app_type :test do
14
+ baseline_image 'ubuntu'
15
+ end
16
+ app_type :php do
17
+ baseline_image 'ubuntu'
18
+ end
19
+ end
20
+
21
+ RubyYacht.configure do
22
+ add_hooks app_type: :test, folder: '.' do
23
+ before(:startup) { run_script 'a.rb' }
24
+ before(:install_libraries) { run_script 'a.rb' }
25
+
26
+ before :startup do
27
+ app_type :php
28
+ run_script 'c.rb'
29
+ end
30
+
31
+ before :startup do
32
+ app_type :test
33
+ run_script 'd.rb'
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ it "returns hooks with the matching attributes" do
40
+ hooks = RubyYacht.configuration.fetch_hooks(app_type: :test, event_type: :startup)
41
+ expect(hooks.count).to eq 2
42
+ expect(hooks[0].script_path).to eq './a.rb'
43
+ expect(hooks[1].script_path).to eq './d.rb'
44
+ end
45
+ end
46
+
47
+ describe "find_app_type" do
48
+ before do
49
+ RubyYacht.configure do
50
+ app_type(:generic) { baseline_image 'ubuntu' }
51
+ app_type(:debian) { baseline_image 'debian' }
52
+ end
53
+ end
54
+
55
+ it "returns the app type with that name" do
56
+ type = RubyYacht.configuration.find_app_type(:debian)
57
+ expect(type.baseline_image).to eq 'debian'
58
+ end
59
+ end
60
+ end
61
+
9
62
  describe "dsl" do
10
63
  let(:project_creation_block) do
11
64
  Proc.new do
12
65
  project :project1 do
13
66
  system_prefix :a
14
67
  domain "a.test.com"
15
- secret_key_base "a"
16
68
  repository "github.com"
17
69
 
18
70
  database do
@@ -26,7 +78,6 @@ describe RubyYacht::Configuration do
26
78
  project :project2 do
27
79
  system_prefix :b
28
80
  domain "b.test.com"
29
- secret_key_base "b"
30
81
  repository "github.com"
31
82
 
32
83
  database do
@@ -39,6 +90,33 @@ describe RubyYacht::Configuration do
39
90
  end
40
91
  end
41
92
 
93
+ let(:hook_creation_block) do
94
+ Proc.new do
95
+ add_hooks app_type: :configuration_test, folder: './scripts' do
96
+ before :startup do
97
+ run_script 'update_config.rb'
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ let(:app_type_creation_block) do
104
+ Proc.new do
105
+ app_type :second_configuration_test do
106
+ baseline_image 'debian'
107
+ app_attribute :test_attribute
108
+ end
109
+ end
110
+ end
111
+
112
+ before do
113
+ RubyYacht.configure do
114
+ app_type :configuration_test do
115
+ baseline_image 'ubuntu'
116
+ end
117
+ end
118
+ end
119
+
42
120
  it "can add projects" do
43
121
  configuration = RubyYacht::Configuration::DSL.new.run(project_creation_block).create_object
44
122
  expect(configuration.projects.count).to eq 2
@@ -46,6 +124,50 @@ describe RubyYacht::Configuration do
46
124
  expect(configuration.projects[1].name).to eq :project2
47
125
  end
48
126
 
127
+ it "can add hooks" do
128
+ configuration = RubyYacht::Configuration::DSL.new.run(hook_creation_block).create_object
129
+ expect(configuration.hooks.count).to eq 1
130
+ expect(configuration.hooks[0].event_time).to eq :before
131
+ expect(configuration.hooks[0].event_type).to eq :startup
132
+ expect(configuration.hooks[0].script_path).to eq './scripts/update_config.rb'
133
+ end
134
+
135
+ it "can add types" do
136
+ configuration = RubyYacht::Configuration::DSL.new.run(app_type_creation_block).create_object
137
+ expect(configuration.app_types.count).to eq 1
138
+ expect(configuration.app_types[0].name).to eq :second_configuration_test
139
+ expect(configuration.app_types[0].project_attributes.count).to eq 0
140
+ expect(configuration.app_types[0].app_attributes.count).to eq 1
141
+ end
142
+
143
+ it "can add `during` hooks" do
144
+ configuration = RubyYacht::Configuration::DSL.new.run(Proc.new do
145
+ add_hooks app_type: :configuration_test, folder: './scripts' do
146
+ during :startup do
147
+ run_script 'start_app.rb'
148
+ end
149
+ end
150
+ end).create_object
151
+ expect(configuration.hooks.count).to eq 1
152
+ expect(configuration.hooks[0].event_time).to eq :during
153
+ expect(configuration.hooks[0].event_type).to eq :startup
154
+ expect(configuration.hooks[0].script_path).to eq './scripts/start_app.rb'
155
+ end
156
+
157
+ it "can add `after` hooks" do
158
+ configuration = RubyYacht::Configuration::DSL.new.run(Proc.new do
159
+ add_hooks app_type: :configuration_test, folder: './scripts' do
160
+ after :startup do
161
+ run_script 'start_app.rb'
162
+ end
163
+ end
164
+ end).create_object
165
+ expect(configuration.hooks.count).to eq 1
166
+ expect(configuration.hooks[0].event_time).to eq :after
167
+ expect(configuration.hooks[0].event_type).to eq :startup
168
+ expect(configuration.hooks[0].script_path).to eq './scripts/start_app.rb'
169
+ end
170
+
49
171
  describe "configure method" do
50
172
  it "adds to the list of projects" do
51
173
  project = RubyYacht::Project.new
@@ -59,6 +181,43 @@ describe RubyYacht::Configuration do
59
181
  expect(configuration.projects[1].name).to eq :project1
60
182
  expect(configuration.projects[2].name).to eq :project2
61
183
  end
184
+
185
+ it "adds to the list of hooks" do
186
+ hook = RubyYacht::Hook.new
187
+ hook.event_time = :after
188
+ hook.event_type = :restart_application
189
+ hook.script_path = './scripts/log_success.rb'
190
+ RubyYacht.configuration.hooks << hook
191
+ RubyYacht.configure(&hook_creation_block)
192
+
193
+ configuration = RubyYacht.configuration
194
+ expect(configuration.hooks.count).to eq 2
195
+ expect(configuration.hooks[0].script_path).to eq './scripts/log_success.rb'
196
+ expect(configuration.hooks[1].script_path).to eq './scripts/update_config.rb'
197
+ end
198
+
199
+ it "adds to the list of app types" do
200
+ RubyYacht.configure(&app_type_creation_block)
201
+
202
+ configuration = RubyYacht.configuration
203
+ expect(configuration.app_types.count).to eq 2
204
+ expect(configuration.app_types[0].name).to eq :configuration_test
205
+ expect(configuration.app_types[1].name).to eq :second_configuration_test
206
+ end
207
+
208
+ context "with an app type that is already registered" do
209
+ before do
210
+ type = RubyYacht::AppType.new
211
+ type.name = :second_configuration_test
212
+ RubyYacht.configuration.app_types << type
213
+ end
214
+
215
+ it "raises an exception" do
216
+ expect(lambda do
217
+ RubyYacht.configure(&app_type_creation_block)
218
+ end).to raise_exception "App type already registered: second_configuration_test"
219
+ end
220
+ end
62
221
  end
63
222
  end
64
223
  end
data/spec/dsl/dsl_spec.rb CHANGED
@@ -161,7 +161,7 @@ describe RubyYacht::DSL::Base do
161
161
  before do
162
162
  DSLTestHelpers::SecondDSL.add_attribute :name
163
163
  DSLTestHelpers::SecondDSL.creates_object DSLTestHelpers::ThingOne
164
- DSLTestHelpers::DSL.add_object :thing, 'DSLTestHelpers::SecondDSL'
164
+ DSLTestHelpers::DSL.add_object :thing, DSLTestHelpers::SecondDSL
165
165
  end
166
166
 
167
167
  it "defines a method for constructing an object of the real type" do
@@ -182,7 +182,7 @@ describe RubyYacht::DSL::Base do
182
182
 
183
183
  it "can accept optional attributes" do
184
184
  DSLTestHelpers::DSL.clear
185
- DSLTestHelpers::DSL.add_object :thing, 'DSLTestHelpers::SecondDSL', required: false
185
+ DSLTestHelpers::DSL.add_object :thing, DSLTestHelpers::SecondDSL, required: false
186
186
  expect(DSLTestHelpers::DSL.required_attributes).to eq []
187
187
  end
188
188
  end
@@ -191,7 +191,7 @@ describe RubyYacht::DSL::Base do
191
191
  before do
192
192
  DSLTestHelpers::SecondDSL.add_attribute :name
193
193
  DSLTestHelpers::SecondDSL.creates_object DSLTestHelpers::ThingOne
194
- DSLTestHelpers::DSL.add_object_list :thing, 'DSLTestHelpers::SecondDSL'
194
+ DSLTestHelpers::DSL.add_object_list :thing, DSLTestHelpers::SecondDSL
195
195
  end
196
196
 
197
197
  it "defines methods for building a list of objects" do
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyYacht::Hook do
4
+ describe "script_name" do
5
+ context "with no script path" do
6
+ it "is an empty string" do
7
+ expect(subject.script_name).to eq ""
8
+ end
9
+ end
10
+
11
+ context "with a script path" do
12
+ before { subject.script_path = "./foo/bar.rb" }
13
+
14
+ it "gets the filename from the script path" do
15
+ expect(subject.script_name).to eq "bar.rb"
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "dsl" do
21
+ let(:dsl) { RubyYacht::Hook::DSL.new(:before, :startup) }
22
+ let(:hook) { dsl.run(@config_block).create_object }
23
+
24
+ before do
25
+ RubyYacht.configuration.clear
26
+
27
+ RubyYacht.configure do
28
+ app_type :test do
29
+ baseline_image 'ubuntu'
30
+ end
31
+ end
32
+
33
+ @config_block = Proc.new do
34
+ app_type :test
35
+ command 'curl google.com'
36
+ end
37
+ end
38
+
39
+ it "can create a hook for running a command" do
40
+ expect(hook.event_time).to eq :before
41
+ expect(hook.event_type).to eq :startup
42
+ expect(hook.app_type).to eq :test
43
+ expect(hook.command).to eq 'curl google.com'
44
+ end
45
+
46
+ it "can create a hook for running a command" do
47
+ @config_block = Proc.new do
48
+ app_type :test
49
+ script_folder './foo'
50
+ run_script 'bar.rb'
51
+ end
52
+ expect(hook.event_time).to eq :before
53
+ expect(hook.event_type).to eq :startup
54
+ expect(hook.app_type).to eq :test
55
+ expect(hook.script_path).to eq './foo/bar.rb'
56
+ expect(hook.command).to eq '/var/docker/bar.rb'
57
+ end
58
+
59
+ context "with no command" do
60
+ before do
61
+ @config_block = Proc.new do
62
+ app_type :test
63
+ end
64
+ end
65
+
66
+ it "raises an exception" do
67
+ expect { hook }.to raise_exception 'Missing required attribute command for RubyYacht::Hook::DSL'
68
+ end
69
+ end
70
+
71
+ context "with a script name and no script path" do
72
+ before do
73
+ @config_block = Proc.new do
74
+ app_type :test
75
+ run_script 'bar.rb'
76
+ end
77
+ end
78
+
79
+ it "creates a hook with with the script relative to the current folder" do
80
+ expect(hook.script_path).to eq './bar.rb'
81
+ expect(hook.command).to eq '/var/docker/bar.rb'
82
+ end
83
+ end
84
+
85
+ context "with no app type" do
86
+ before do
87
+ @config_block = Proc.new do
88
+ script_folder './foo'
89
+ run_script 'bar.rb'
90
+ end
91
+ end
92
+
93
+ it "raises an exception" do
94
+ expect { hook }.to raise_exception 'Missing required attribute app_type for RubyYacht::Hook::DSL'
95
+ end
96
+ end
97
+
98
+ context "with an invalid app type" do
99
+ before do
100
+ @config_block = Proc.new do
101
+ app_type :invalid
102
+ command 'whoami'
103
+ end
104
+ end
105
+
106
+ it "raises an exception" do
107
+ expect { hook }.to raise_exception 'Hook has invalid app type `invalid`'
108
+ end
109
+ end
110
+ end
111
+ end