ruby_yacht 0.6.1 → 0.7.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +7 -5
  4. data/doc/TODO.md +1 -5
  5. data/doc/configuration.md +51 -0
  6. data/doc/plugins.md +4 -0
  7. data/lib/ruby_yacht/dsl/configuration.rb +26 -1
  8. data/lib/ruby_yacht/dsl/dsl.rb +35 -3
  9. data/lib/ruby_yacht/dsl/hook.rb +4 -0
  10. data/lib/ruby_yacht/dsl/project.rb +11 -0
  11. data/lib/ruby_yacht/images/app/Dockerfile.erb +2 -1
  12. data/lib/ruby_yacht/images/app/checkout.bash +1 -1
  13. data/lib/ruby_yacht/images/app-dependencies/Dockerfile.erb +7 -1
  14. data/lib/ruby_yacht/images/database/Dockerfile.erb +3 -1
  15. data/lib/ruby_yacht/images/database/checkout.bash +3 -4
  16. data/lib/ruby_yacht/images/web/Dockerfile.erb +2 -0
  17. data/lib/ruby_yacht/plugins/nginx.rb +5 -0
  18. data/lib/ruby_yacht/plugins/rails/scripts/load_seeds.rb +10 -1
  19. data/lib/ruby_yacht/plugins/rails/scripts/prepare_rails_for_launch.rb +1 -1
  20. data/lib/ruby_yacht/plugins/rails/scripts/update_rails_config.rb +6 -4
  21. data/lib/ruby_yacht/plugins/rails.rb +30 -17
  22. data/lib/ruby_yacht/plugins.rb +1 -1
  23. data/lib/ruby_yacht/runner/build_images.rb +5 -7
  24. data/lib/ruby_yacht/runner/run_containers.rb +1 -2
  25. data/ruby_yacht.gemspec +2 -2
  26. data/spec/docker/run.bash +4 -0
  27. data/spec/dsl/configuration_spec.rb +29 -0
  28. data/spec/dsl/dsl_spec.rb +56 -0
  29. data/spec/dsl/hook_spec.rb +28 -5
  30. data/spec/dsl/project_spec.rb +46 -0
  31. data/spec/dsl/server_type_spec.rb +3 -0
  32. data/spec/fixtures/app-dependencies-dockerfile-generic +3 -1
  33. data/spec/fixtures/app-dependencies-dockerfile-generic-with-library-install +3 -1
  34. data/spec/fixtures/app-dependencies-dockerfile-rails +4 -3
  35. data/spec/fixtures/app-dependencies-dockerfile-rails-production +35 -0
  36. data/spec/fixtures/app-dependencies-dockerfile-with-https-repository +25 -0
  37. data/spec/fixtures/app-dependencies-dockerfile-with-no-repository +2 -0
  38. data/spec/fixtures/database-dockerfile +1 -1
  39. data/spec/fixtures/database-dockerfile-mysql +1 -1
  40. data/spec/fixtures/database-dockerfile-rails +2 -6
  41. data/spec/fixtures/database-dockerfile-rails-mysql +38 -0
  42. data/spec/fixtures/database-dockerfile-rails-with-no-repository +1 -3
  43. data/spec/fixtures/database-dockerfile-with-seed-hooks +1 -1
  44. data/spec/fixtures/local_config.yml +8 -0
  45. data/spec/fixtures/mars-dockerfile +0 -1
  46. data/spec/fixtures/mars-dockerfile-rails +0 -1
  47. data/spec/fixtures/mars-dockerfile-rails-with-no-repository +0 -1
  48. data/spec/fixtures/mars-dockerfile-with-after-checkout-hooks +0 -1
  49. data/spec/fixtures/mars-dockerfile-with-before-startup-hooks +0 -1
  50. data/spec/fixtures/mars-dockerfile-with-custom-file-copy +0 -1
  51. data/spec/fixtures/mars-dockerfile-with-local-database +0 -1
  52. data/spec/fixtures/mars-dockerfile-with-no-repository +0 -1
  53. data/spec/fixtures/mars-dockerfile-with-remote-database +0 -1
  54. data/spec/fixtures/mars-startup-rails +1 -1
  55. data/spec/fixtures/mars-startup-rails-with-no-repository +1 -1
  56. data/spec/fixtures/web-dockerfile-nginx +3 -0
  57. data/spec/integration/01_normal_config_spec.rb +352 -0
  58. data/spec/integration/{create_new_project_spec.rb → 02_creating_new_project_spec.rb} +2 -2
  59. data/spec/integration/03_no_repository_spec.rb +56 -0
  60. data/spec/integration/04_no_database_spec.rb +58 -0
  61. data/spec/integration/05_https_repository_spec.rb +52 -0
  62. data/spec/integration/06_production_environment_spec.rb +72 -0
  63. data/spec/integration/07_local_checkout_spec.rb +52 -0
  64. data/spec/integration/08_multiple_projects_spec.rb +46 -0
  65. data/spec/integration/09_titular_app_spec.rb +53 -0
  66. data/spec/integration/10_misc_scenarios_spec.rb +97 -0
  67. data/spec/integration/run.rb +18 -2
  68. data/spec/plugins/rails_spec.rb +73 -16
  69. data/spec/runner/build_images_spec.rb +17 -1
  70. data/spec/runner/run_containers_spec.rb +3 -3
  71. data/spec/support/integration_helpers.rb +18 -4
  72. metadata +30 -20
  73. data/spec/integration/build_images_spec.rb +0 -210
  74. data/spec/integration/build_spec.rb +0 -23
  75. data/spec/integration/checkout_spec.rb +0 -94
  76. data/spec/integration/implode_spec.rb +0 -20
  77. data/spec/integration/run_containers_spec.rb +0 -279
  78. data/spec/integration/services_spec.rb +0 -99
  79. data/spec/integration/shell_spec.rb +0 -31
  80. data/spec/integration/update_hosts_spec.rb +0 -35
@@ -17,11 +17,13 @@ common_config = {
17
17
  'port' => ENV['DATABASE_PORT']
18
18
  }
19
19
 
20
+ rails_env = ENV['RAILS_ENV'] || 'development'
21
+
20
22
  database_config = {
21
- ENV['RAILS_ENV'] => common_config
23
+ rails_env => common_config
22
24
  }
23
25
 
24
- if ENV['RAILS_ENV'] == 'development'
26
+ if rails_env == 'development'
25
27
  database_config['test'] = common_config.dup
26
28
  database_config['test']['database'] += '_test'
27
29
  end
@@ -31,12 +33,12 @@ File.open('/var/code/config/database.yml', 'w') do |file|
31
33
  end
32
34
 
33
35
  secret_key_config = {
34
- ENV['RAILS_ENV'] => {
36
+ rails_env => {
35
37
  'secret_key_base' => ENV['SECRET_KEY_BASE']
36
38
  }
37
39
  }
38
40
 
39
- if ENV['RAILS_ENV'] == 'development'
41
+ if rails_env == 'development'
40
42
  secret_key_config['test'] = secret_key_config['development'].dup
41
43
  end
42
44
 
@@ -5,6 +5,7 @@ module RubyYacht::Plugins
5
5
  def self.load
6
6
  load_server_type
7
7
  load_hooks
8
+ load_environment_variables
8
9
  end
9
10
 
10
11
  # This method loads the configuration for the Rails server type.
@@ -24,26 +25,16 @@ module RubyYacht::Plugins
24
25
  def self.load_hooks
25
26
  RubyYacht.configure do
26
27
  add_hooks(app_server_type: :rails, container_type: :app, script_folder: File.join(File.dirname(__FILE__), 'rails', 'scripts')) do
27
- during :initialize_app_environment do
28
- set_environment_variable 'RAILS_ENV' do
29
- @project.rails_environment
30
- end
31
- set_environment_variable 'SECRET_KEY_BASE' do
32
- @project.rails_secret_key_base
33
- end
34
- set_environment_variable 'EXCLUDED_GEM_GROUPS' do
35
- groups = @project.rails_excluded_gem_groups.join(' ')
36
- groups = '""' if groups == ''
37
- groups
38
- end
39
- end
40
28
  during(:install_libraries) { run_script :ruby, 'install_gems.rb' }
41
29
 
42
30
  after(:build_checkout) { command 'bundle install --clean' }
43
31
 
44
- during :load_database_seeds do
45
- container_type :database
46
- run_script :ruby, 'load_seeds.rb'
32
+ if RubyYacht.configuration.find_server_type(:mysql)
33
+ during :load_database_seeds do
34
+ container_type :database
35
+ database_server_type :mysql
36
+ run_script :ruby, 'load_seeds.rb'
37
+ end
47
38
  end
48
39
 
49
40
  during :build_new_app do
@@ -53,7 +44,29 @@ module RubyYacht::Plugins
53
44
  before(:startup) { run_script :ruby, 'update_rails_config.rb' }
54
45
  before(:startup) { run_script :ruby, 'prepare_rails_for_launch.rb' }
55
46
 
56
- during(:startup) { command 'rails s -b 0.0.0.0 -p $APP_PORT -e $RAILS_ENV' }
47
+ during(:startup) { command 'rails s -b 0.0.0.0 -p $APP_PORT' }
48
+ end
49
+ end
50
+ end
51
+
52
+ # This method loads the hooks for setting environment variables for the
53
+ # Rails apps.
54
+ def self.load_environment_variables
55
+ RubyYacht.configure do
56
+ add_hooks app_server_type: :rails, container_type: :app do
57
+ during :initialize_app_environment do
58
+ set_environment_variable 'RAILS_ENV' do
59
+ @project.rails_environment == 'development' ? nil : @project.rails_environment
60
+ end
61
+ set_environment_variable 'SECRET_KEY_BASE' do
62
+ @project.rails_secret_key_base
63
+ end
64
+ set_environment_variable 'EXCLUDED_GEM_GROUPS' do
65
+ groups = @project.rails_excluded_gem_groups.join(' ')
66
+ groups = '""' if groups == ''
67
+ groups
68
+ end
69
+ end
57
70
  end
58
71
  end
59
72
  end
@@ -3,6 +3,6 @@ module RubyYacht
3
3
  module Plugins
4
4
  end
5
5
  end
6
- require 'ruby_yacht/plugins/rails'
7
6
  require 'ruby_yacht/plugins/mysql'
7
+ require 'ruby_yacht/plugins/rails'
8
8
  require 'ruby_yacht/plugins/nginx'
@@ -15,12 +15,10 @@ module RubyYacht::Runner
15
15
  def run
16
16
  FileUtils.mkdir_p 'tmp'
17
17
 
18
- default_system_prefix = projects.first.system_prefix
19
- docker "network create #{default_system_prefix} 2> /dev/null"
20
-
21
18
  projects.each do |project|
22
19
  log "Building images for #{project.name}"
23
20
 
21
+ docker "network create #{project.system_prefix} 2> /dev/null"
24
22
  id_path = File.join(ENV['HOME'], '.ssh', 'id_rsa')
25
23
  tmp_id_path = File.join('tmp', 'id_rsa')
26
24
  FileUtils.cp(id_path, tmp_id_path) if File.exist?(id_path)
@@ -133,10 +131,10 @@ module RubyYacht::Runner
133
131
 
134
132
  @hook_events =
135
133
  case folder_name
136
- when 'app' then [:startup, :build_checkout, :build_new_app]
137
- when 'app-dependencies' then [:initialize_app_environment, :install_libraries]
138
- when 'database' then [:create_databases, :install_libraries, :load_database_seeds]
139
- when 'web' then [:install_libraries, :add_project_landing, :add_app_config]
134
+ when 'app' then [:startup, :build_checkout, :build_new_app, :cleanup]
135
+ when 'app-dependencies' then [:initialize_app_environment, :install_libraries, :cleanup]
136
+ when 'database' then [:create_databases, :install_libraries, :load_database_seeds, :cleanup]
137
+ when 'web' then [:install_libraries, :add_project_landing, :add_app_config, :cleanup]
140
138
  else []
141
139
  end
142
140
 
@@ -11,10 +11,9 @@ module RubyYacht::Runner
11
11
 
12
12
  # This method runs the logic of the command.
13
13
  def run
14
- @network = projects.first.system_prefix
15
-
16
14
  projects.each do |project|
17
15
  @project = project
16
+ @network = project.system_prefix
18
17
 
19
18
  project.databases.select(&:local?).each do |database|
20
19
  run_container database
data/ruby_yacht.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = 'ruby_yacht'
3
- spec.version = '0.6.1'
4
- spec.date = '2016-05-16'
3
+ spec.version = '0.7.0'
4
+ spec.date = '2016-05-20'
5
5
  spec.description = "A DSL for building docker containers for a family of Rails apps"
6
6
  spec.summary = "A DSL for building docker containers for a family of Rails apps"
7
7
  spec.authors = ["John Brownlee"]
data/spec/docker/run.bash CHANGED
@@ -31,6 +31,10 @@ else
31
31
  EXISTING_CONTAINER=""
32
32
  fi
33
33
 
34
+ if [[ -n $VERBOSE_DOCKER && $VERBOSE_DOCKER -eq 1 ]]; then
35
+ EXTRA_FLAGS="$EXTRA_FLAGS -e VERBOSE_DOCKER=1"
36
+ fi
37
+
34
38
  if [ -z "$EXISTING_CONTAINER" ]; then
35
39
  docker run -it $EXTRA_FLAGS --privileged --name=ruby-yacht-tests -v $PWD:/var/code/ruby-yacht ruby-yacht-tests /var/docker/startup.bash $*
36
40
  RESULT=$?
@@ -339,6 +339,24 @@ describe RubyYacht::Configuration do
339
339
  expect(configuration.server_types[0].server_attributes.count).to eq 1
340
340
  end
341
341
 
342
+ it 'can add local config' do
343
+ configuration = RubyYacht::Configuration::DSL.new.run(Proc.new do
344
+ add_local_config File.join(File.dirname(__FILE__), '..', 'fixtures', 'local_config.yml')
345
+ end)
346
+
347
+ expect(configuration.local_config).to eq(
348
+ system_prefix: 'jupiter',
349
+ check_out_locally: true,
350
+ rails_environment: 'production',
351
+ database: {
352
+ host: 'localhost',
353
+ name: 'jupiter_testing',
354
+ username: 'jupiter',
355
+ password: 'jupiterpass'
356
+ }
357
+ )
358
+ end
359
+
342
360
  it "can add `during` hooks" do
343
361
  configuration = RubyYacht::Configuration::DSL.new.run(Proc.new do
344
362
  add_hooks container_type: :app, app_server_type: :configuration_test, script_folder: './scripts' do
@@ -408,6 +426,17 @@ describe RubyYacht::Configuration do
408
426
  expect(configuration.server_types[2].name).to eq :second_configuration_test
409
427
  end
410
428
 
429
+ it "adds to the local config" do
430
+ RubyYacht.configuration.local_config = {system_prefix: 'apollo', rails_secret_key_base: 'ABC1234'}
431
+ RubyYacht.configure do
432
+ add_local_config File.join(File.dirname(__FILE__), '..', 'fixtures', 'local_config.yml')
433
+ end
434
+
435
+ configuration = RubyYacht.configuration
436
+ expect(configuration.local_config[:system_prefix]).to eq 'jupiter'
437
+ expect(configuration.local_config[:rails_secret_key_base]).to eq 'ABC1234'
438
+ end
439
+
411
440
  context "with a server type that is already registered" do
412
441
  before do
413
442
  type = RubyYacht::ServerType.new
data/spec/dsl/dsl_spec.rb CHANGED
@@ -298,6 +298,62 @@ describe RubyYacht::DSL::Base do
298
298
  end
299
299
  end
300
300
 
301
+ describe 'copy_local_config' do
302
+ before do
303
+ DSLTestHelpers::DSL.add_attribute :name
304
+ DSLTestHelpers::DSL.add_attribute :height
305
+ DSLTestHelpers::DSL.add_attribute :gender
306
+ DSLTestHelpers::DSL.add_boolean :vegan
307
+
308
+ @dsl = DSLTestHelpers::DSL.new
309
+ RubyYacht.configuration.local_config = {name: 'John', height: 120, vegan: false, last_name: 'Smith'}
310
+ end
311
+
312
+ context 'with a valid attribute' do
313
+ it 'copies the value from the local config' do
314
+ @dsl.copy_local_config(:name)
315
+ expect(@dsl.instance_eval { @name }).to eq 'John'
316
+ end
317
+ end
318
+
319
+ context 'with a path to the dictionary' do
320
+ it 'copies the value from the local config' do
321
+ RubyYacht.configuration.local_config = {people: {john: {height: 150}}}
322
+ @dsl.copy_local_config :height, from: 'people.john'
323
+ expect(@dsl.instance_eval { @height }).to eq 150
324
+ end
325
+ end
326
+
327
+ context 'with a false boolean attribute' do
328
+ it 'leaves the value false' do
329
+ @dsl.copy_local_config :vegan
330
+ expect(@dsl.instance_eval { @vegan }).to be_falsey
331
+ end
332
+ end
333
+
334
+ context 'with a true boolean attribute' do
335
+ it 'sets the value to true' do
336
+ RubyYacht.configuration.local_config[:vegan] = true
337
+ @dsl.copy_local_config :vegan
338
+ expect(@dsl.instance_eval { @vegan }).to be_truthy
339
+ end
340
+ end
341
+
342
+ context 'with an attribute that is not defined on the DSL' do
343
+ it 'raises an exception' do
344
+ expect { @dsl.copy_local_config :last_name }.to raise_exception 'Undefined field in DSLTestHelpers::DSL: last_name'
345
+ end
346
+ end
347
+
348
+ context 'with an attribute with no value in the config file' do
349
+ it 'leaves the value nil' do
350
+ @dsl.copy_local_config :gender
351
+ expect(@dsl.instance_eval { @gender }).to be_nil
352
+ end
353
+ end
354
+ end
355
+
356
+
301
357
  describe "check_required_attributes" do
302
358
  before do
303
359
  DSLTestHelpers::DSL.add_attribute :name
@@ -335,14 +335,37 @@ describe RubyYacht::Hook do
335
335
  end
336
336
 
337
337
  describe "environment variable behavior" do
338
- let(:behavior) { RubyYacht::Hook::EnvironmentVariableBehavior.new('SECRET_KEY_BASE', Proc.new { 'abc'}) }
338
+ context 'with a normal value' do
339
+ let(:behavior) { RubyYacht::Hook::EnvironmentVariableBehavior.new('SECRET_KEY_BASE', Proc.new { 'abc'}) }
339
340
 
340
- it 'sets the environment variable as its docker command' do
341
- expect(behavior.dockerfile_command).to eq 'ENV SECRET_KEY_BASE abc'
341
+ it 'sets the environment variable as its docker command' do
342
+ expect(behavior.dockerfile_command).to eq 'ENV SECRET_KEY_BASE abc'
343
+ end
344
+
345
+ it 'sets the environment variable as its shell command' do
346
+ expect(behavior.shell_command).to eq 'export SECRET_KEY_BASE="abc"'
347
+ end
342
348
  end
343
349
 
344
- it 'sets the environment variable as its shell command' do
345
- expect(behavior.shell_command).to eq 'export SECRET_KEY_BASE="abc"'
350
+ context 'with a blank value' do
351
+ let(:behavior) { RubyYacht::Hook::EnvironmentVariableBehavior.new('SECRET_KEY_BASE', Proc.new { '' }) }
352
+
353
+ it 'sets the environment variable as its docker command' do
354
+ expect(behavior.dockerfile_command).to eq 'ENV SECRET_KEY_BASE '
355
+ end
356
+
357
+ it 'sets the environment variable as its shell command' do
358
+ expect(behavior.shell_command).to eq 'export SECRET_KEY_BASE=""'
359
+ end
360
+ end
361
+
362
+ context 'with a nil value' do
363
+ let(:behavior) { RubyYacht::Hook::EnvironmentVariableBehavior.new('SECRET_KEY_BASE', Proc.new { nil }) }
364
+
365
+ it 'has a nil command' do
366
+ expect(behavior.dockerfile_command).to be_nil
367
+ expect(behavior.shell_command).to be_nil
368
+ end
346
369
  end
347
370
  end
348
371
  end
@@ -26,6 +26,7 @@ describe RubyYacht::Project do
26
26
  @builder = Proc.new do
27
27
  system_prefix :a
28
28
  repository "github.com"
29
+ repository_protocol :https
29
30
 
30
31
  app :generic, :app1 do
31
32
  repository_name 'brownleej/test1'
@@ -57,6 +58,7 @@ describe RubyYacht::Project do
57
58
  expect(project.name).to eq :test_project
58
59
  expect(project.system_prefix).to eq :a
59
60
  expect(project.repository).to eq "github.com"
61
+ expect(project.repository_protocol).to eq :https
60
62
  expect(project.primary_app).to eq :app1
61
63
 
62
64
  expect(project.apps.map(&:name)).to eq [:app1, :app2]
@@ -68,6 +70,9 @@ describe RubyYacht::Project do
68
70
 
69
71
  it "requires the system prefix" do
70
72
  @builder = Proc.new do
73
+ repository 'github.com'
74
+ repository_protocol :https
75
+
71
76
  app :generic, :app1 do
72
77
  repository_name 'brownleej/test1'
73
78
  end
@@ -101,6 +106,7 @@ describe RubyYacht::Project do
101
106
  it "requires the repository" do
102
107
  @builder = Proc.new do
103
108
  system_prefix :a
109
+ repository_protocol :https
104
110
 
105
111
  app :generic, :app1 do
106
112
  repository_name 'brownleej/test1'
@@ -132,10 +138,46 @@ describe RubyYacht::Project do
132
138
  expect { project }.to raise_exception "Missing required attribute repository for RubyYacht::Project::DSL"
133
139
  end
134
140
 
141
+ it 'defaults the repository protocol to ssh' do
142
+ @builder = Proc.new do
143
+ system_prefix :a
144
+ repository 'github.com'
145
+
146
+ app :generic, :app1 do
147
+ repository_name 'brownleej/test1'
148
+ end
149
+
150
+ app :generic, :app2 do
151
+ repository_name 'brownleej/test2'
152
+ end
153
+
154
+ database :sqlite, :project1 do
155
+ host "localhost"
156
+ username "test"
157
+ password "test"
158
+ port 1234
159
+ container_label :sqlite
160
+ end
161
+
162
+ web_server :apache, :web do
163
+ domain 'test.com'
164
+ end
165
+
166
+ dns_server do
167
+ server '8.10.1.1'
168
+ end
169
+
170
+ primary_app :app1
171
+ end
172
+
173
+ expect(project.repository_protocol).to eq :ssh
174
+ end
175
+
135
176
  it "does not require any apps" do
136
177
  @builder = Proc.new do
137
178
  system_prefix :a
138
179
  repository "github.com"
180
+ repository_protocol :https
139
181
 
140
182
  database :sqlite, :project1 do
141
183
  host "localhost"
@@ -163,6 +205,7 @@ describe RubyYacht::Project do
163
205
  @builder = Proc.new do
164
206
  system_prefix :a
165
207
  repository "github.com"
208
+ repository_protocol :https
166
209
 
167
210
  app :generic, :app1 do
168
211
  repository_name 'brownleej/test1'
@@ -194,6 +237,7 @@ describe RubyYacht::Project do
194
237
  @builder = Proc.new do
195
238
  system_prefix :a
196
239
  repository "github.com"
240
+ repository_protocol :https
197
241
 
198
242
  app :generic, :app1 do
199
243
  repository_name 'brownleej/test1'
@@ -221,6 +265,7 @@ describe RubyYacht::Project do
221
265
  @builder = Proc.new do
222
266
  system_prefix :a
223
267
  repository "github.com"
268
+ repository_protocol :https
224
269
 
225
270
  app :generic, :app1 do
226
271
  repository_name 'brownleej/test1'
@@ -252,6 +297,7 @@ describe RubyYacht::Project do
252
297
  @builder = Proc.new do
253
298
  system_prefix :a
254
299
  repository "github.com"
300
+ repository_protocol :https
255
301
 
256
302
  app :generic, :app1 do
257
303
  repository_name 'brownleej/test1'
@@ -82,6 +82,7 @@ describe RubyYacht::ServerType do
82
82
  end
83
83
 
84
84
  project = RubyYacht.configuration.projects.last
85
+ expect(RubyYacht::Project::DSL.new(:test).singleton_class.all_attributes).to include :app_type_test_foo
85
86
  expect(project.app_type_test_environment).to eq 'staging'
86
87
  expect(project.app_type_test_foo).to eq 'test value'
87
88
  end
@@ -99,6 +100,8 @@ describe RubyYacht::ServerType do
99
100
  end
100
101
  end
101
102
  end
103
+
104
+ expect(RubyYacht::App::DSL.new(:app_type_test, :test1).singleton_class.all_attributes).to include :app_type_test_bar
102
105
 
103
106
  project = RubyYacht.configuration.projects.last
104
107
  app = project.apps.last