ruby_yacht 0.1.1 → 0.2.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.
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