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
@@ -7,6 +7,8 @@ module RubyYacht
7
7
  #
8
8
  # A project is a family of apps that communicate with each other and
9
9
  # share a database.
10
+ #
11
+ # You can configure this with RubyYacht::Project::DSL
10
12
  class Project
11
13
  # The name of the project.
12
14
  attr_accessor :name
@@ -21,12 +23,6 @@ module RubyYacht
21
23
  # The hostname for the repository that contains the code for the apps.
22
24
  attr_accessor :repository
23
25
 
24
- # The secret key that the apps should use for signing cookies.
25
- attr_accessor :secret_key_base
26
-
27
- # The environment that the apps should run in.
28
- attr_accessor :rails_environment
29
-
30
26
  # Whether we should check out the code on the host machine, rather than
31
27
  # keeping it entirely inside the container.
32
28
  attr_accessor :check_out_locally
@@ -59,6 +55,8 @@ module RubyYacht
59
55
  # * *name: String* The name of the project
60
56
  def initialize(name)
61
57
  @name = name.to_sym
58
+ load_custom_attributes
59
+ load_app_initializers
62
60
  end
63
61
 
64
62
  add_attribute :name
@@ -75,27 +73,12 @@ module RubyYacht
75
73
  # test.com
76
74
  add_attribute :domain
77
75
 
78
- ##
79
- # :method: secret_key_base
80
- # You can call `secret_key_base '1234kj1234k;lj1234jklh'` to set the
81
- # project's `secret_key_base` to `1234kj1234k;lj1234jklh`.
82
- add_attribute :secret_key_base
83
-
84
76
  ##
85
77
  # :method: repository
86
78
  # You can call `repository 'github.com'` to set the project's `repository`
87
79
  # to `github.com`
88
80
  add_attribute :repository
89
81
 
90
- ##
91
- # :method: rails_environment
92
- #
93
- # You can call `rails_environment 'staging'` to set the project's
94
- # `rails_environment` to `staging`.
95
- #
96
- # The default is `development`.
97
- add_attribute :rails_environment, 'development'
98
-
99
82
  ##
100
83
  # :method: check_out_locally
101
84
  #
@@ -139,6 +122,19 @@ module RubyYacht
139
122
  add_object :dns_server, RubyYacht::DnsServer::DSL, required: false
140
123
 
141
124
  creates_object Project
125
+
126
+ # This method loads the special DSL methods for defining apps of a certain
127
+ # type.
128
+ #
129
+ # For the app type with the name `foo`, this will create a `foo_app`
130
+ # method on the DSL that builds an app with the type `foo`.
131
+ def load_app_initializers
132
+ RubyYacht.configuration.app_types.each do |app_type|
133
+ define_singleton_method "#{app_type.name}_app" do |name, &block|
134
+ app name, app_type.name, &block
135
+ end
136
+ end
137
+ end
142
138
  end
143
139
  end
144
140
  end
@@ -4,3 +4,5 @@ require 'ruby_yacht/dsl/project'
4
4
  require 'ruby_yacht/dsl/app'
5
5
  require 'ruby_yacht/dsl/database'
6
6
  require 'ruby_yacht/dsl/dns_server'
7
+ require 'ruby_yacht/dsl/hook'
8
+ require 'ruby_yacht/dsl/app_type'
@@ -1,32 +1,39 @@
1
- FROM <%= @project.system_prefix %>-app-dependencies
1
+ FROM <%= @project.system_prefix %>-<%= @app.app_type %>-app-dependencies
2
2
 
3
3
  ENV DATABASE_HOST <%= @project.database.host %>
4
4
  ENV DATABASE_NAME <%= @project.database.name %>
5
5
  ENV DATABASE_PASSWORD <%= @project.database.password %>
6
6
  ENV DATABASE_USERNAME <%= @project.database.username %>
7
- ENV RAILS_ENV <%= @project.rails_environment %>
8
- ENV RAILS_PORT <%= @app.port %>
7
+ ENV APP_PORT <%= @app.port %>
9
8
  ENV REPOSITORY_HOST <%= @project.repository %>
10
- ENV SECRET_KEY_BASE <%= @project.secret_key_base %>
11
9
  ENV SYSTEM_PREFIX <%= @project.system_prefix %>
10
+ <% app_type = RubyYacht.configuration.find_app_type(@app.app_type) %>
11
+ <% app_type.environment_variables.select { |variable| variable[:image] == :app }.each do |variable| %>
12
+ ENV <%= variable[:name] %> <%= instance_eval(&variable[:block]) %>
13
+ <% end %>
12
14
 
13
15
  RUN rm -r /var/code
14
16
  RUN mkdir -p /var/code
15
17
 
16
- COPY startup.rb /var/docker/startup.rb
17
- COPY checkout.rb /var/docker/checkout.rb
18
- COPY update_database_config.rb /var/docker/update_database_config.rb
19
-
20
- RUN chmod u+x /var/docker/*.rb
21
-
22
18
  ENV REPOSITORY_NAME <%= @app.repository_name %>
19
+ COPY checkout.bash /var/docker/checkout.bash
20
+ RUN bash /var/docker/checkout.bash
21
+
22
+ COPY before_startup.bash /var/docker/before_startup.bash
23
+ COPY startup.bash /var/docker/startup.bash
24
+ <% RubyYacht.configuration.fetch_hooks(app_type: @app.app_type).select { |hook| hook.script_name != '' }.each do |hook| %>
25
+ <% next unless [:startup, :build_checkout].include?(hook.event_type) %>
26
+ COPY <%= hook.script_name %> /var/docker/<%= hook.script_name %>
27
+ <% end %>
23
28
 
24
- RUN /var/docker/checkout.rb
29
+ RUN chmod u+x /var/docker/*
25
30
 
26
31
  WORKDIR /var/code
27
32
 
28
- RUN bundle install && bundle clean --force
33
+ <% RubyYacht.configuration.fetch_hooks(app_type: @app.app_type, event_time: :after, event_type: :build_checkout).each do |hook| %>
34
+ RUN <%= hook.command %>
35
+ <% end %>
29
36
 
30
37
  EXPOSE <%= @app.port %>
31
38
 
32
- CMD /var/docker/startup.rb
39
+ CMD /var/docker/startup.bash
@@ -0,0 +1,8 @@
1
+ #! /bin/bash
2
+
3
+ cd /var/code;
4
+ /var/docker/checkout.bash;
5
+
6
+ <% RubyYacht.configuration.fetch_hooks(app_type: @app.app_type, event_time: :before, event_type: :startup).each do |hook| %>
7
+ <%= hook.command %>;
8
+ <% end %>
@@ -0,0 +1,6 @@
1
+ #! /bin/bash
2
+
3
+ if [ ! -d /var/code/.git ]
4
+ then
5
+ git clone git@$REPOSITORY_HOST:$REPOSITORY_NAME /var/code
6
+ fi
@@ -0,0 +1,5 @@
1
+ #! /bin/bash
2
+ /var/docker/before_startup.bash;
3
+ <% RubyYacht.configuration.fetch_hooks(app_type: @app.app_type, event_time: :during, event_type: :startup).each do |hook| %>
4
+ <%= hook.command %>;
5
+ <% end %>
@@ -1,23 +1,41 @@
1
- # This Dockerfile creates an image for installing all of the gem dependencies
1
+ # This Dockerfile creates an image for installing all of the dependencies
2
2
  # for all of the apps.
3
3
  #
4
4
  # This is a slow process, so this should be kept as simple as possible so that
5
5
  # it can remain unchanged.
6
6
 
7
- FROM ruby:2.3
7
+ FROM <%= @app_type.baseline_image %>
8
8
 
9
9
  RUN mkdir -p /root/.ssh
10
10
  COPY id_rsa /root/.ssh
11
11
  RUN ssh-keyscan <%= @project.repository %> >> /root/.ssh/known_hosts
12
12
 
13
13
  RUN mkdir -p /var/docker/
14
- COPY install_gems.rb /var/docker/install_gems.rb
14
+
15
+ <% library_scripts = RubyYacht.configuration.fetch_hooks(app_type: @app_type.name, event_time: :during, event_type: :install_libraries).select { |hook| hook.script_name != '' } %>
16
+ <% library_scripts.each do |hook |%>
17
+ COPY <%= hook.script_name %> /var/docker/<%= hook.script_name %>
18
+ <% end %>
19
+
20
+ <% if library_scripts.any? %>
21
+ RUN chmod u+x /var/docker/*
22
+ <% end %>
15
23
 
16
24
  <% @project.apps.each do |app| %>
17
- RUN ruby /var/docker/install_gems.rb <%= app.name %> <%= @project.repository %> <%= app.repository_name %>
25
+ <% next unless app.app_type == @app_type.name %>
26
+
27
+ RUN git clone git@<%= @project.repository %>:<%= app.repository_name %> /var/code/<%= app.name %>
28
+ WORKDIR /var/code/<%= app.name %>
29
+ <% RubyYacht.configuration.fetch_hooks(app_type: @app_type.name, event_time: :during, event_type: :install_libraries).each do |hook |%>
30
+ RUN <%= hook.command %>
31
+ <% end %>
32
+ <% end %>
33
+
34
+ <% if library_scripts.any? %>
35
+ RUN rm /var/docker/*
18
36
  <% end %>
19
37
 
20
- RUN rm /var/docker/install_gems.rb
38
+ WORKDIR /
21
39
 
22
40
  RUN apt-get update && apt-get upgrade -y
23
41
  RUN apt-get install -y mysql-client
@@ -1,26 +1,40 @@
1
- FROM <%= @project.system_prefix %>-app-dependencies
2
-
1
+ FROM <%= @project.system_prefix %>-<%= @app_type.name %>-app-dependencies
3
2
  <% database = @project.database %>
4
3
 
5
4
  ENV DEBIAN_FRONTEND noninteractive
6
5
  RUN apt-get install -y mysql-server
7
6
 
8
- COPY setup.rb /var/docker/setup.rb
9
- COPY setup_database.sql.erb /var/docker/setup_database.sql.erb
10
- COPY load_seeds.rb /var/docker/load_seeds.rb
7
+ ENV DATABASE_USERNAME <%= @project.database.username %>
8
+ ENV DATABASE_PASSWORD <%= @project.database.password %>
9
+ ENV DATABASE_NAME <%= @project.database.name %>
10
+
11
+ COPY setup.bash /var/docker/setup.bash
12
+ COPY checkout.bash /var/docker/checkout.bash
13
+ <% @project.apps.map(&:app_type).uniq.each do |app_type| %>
14
+ <% RubyYacht.configuration.fetch_hooks(app_type: app_type, event_type: :load_database_seeds).each do |hook| %>
15
+ COPY <%= hook.script_name %> /var/docker/<%= hook.script_name %>
16
+ <% end %>
17
+ <% end %>
18
+
19
+ RUN chmod u+x /var/docker/*
11
20
 
12
- RUN ruby /var/docker/setup.rb <%= database.name %> <%= database.username %> <%= database.password %> <%= @project.rails_environment %>
21
+ RUN /var/docker/setup.bash <%= database.name %> <%= database.username %> <%= database.password %>
13
22
 
14
- <% initialized = false %>
15
23
  <% @project.apps.each do |app| %>
16
- <% database_name = database.name %>
17
- <% database_name += '_development' if @project.rails_environment == 'development' %>
18
- RUN ruby /var/docker/load_seeds.rb <%= app.name %> <%= database_name %> <%= database.username %> <%= database.password %> <%= initialized %>
19
- <% initialized = true %>
24
+
25
+ RUN /var/docker/checkout.bash <%= @project.repository %> <%= app.name %> <%= app.repository_name %>
26
+ WORKDIR /var/code/<%= app.name %>
27
+ <% @app_type = RubyYacht.configuration.find_app_type(app.app_type) %>
28
+ <%= include_event :load_database_seeds %>
20
29
  <% end %>
30
+
21
31
  RUN rm -r /var/docker
22
32
  RUN rm -r /var/code
23
33
 
34
+ ENV DATABASE_USERNAME ''
35
+ ENV DATABASE_PASSWORD ''
36
+ ENV DATABASE_NAME ''
37
+
24
38
  EXPOSE 3306
25
39
 
26
40
  CMD mysqld_safe --bind-address=0.0.0.0
@@ -0,0 +1,10 @@
1
+ #! /bin/bash
2
+
3
+ REPOSITORY_HOST=$1
4
+ APP_NAME=$2
5
+ REPOSITORY_NAME=$3
6
+
7
+ if [ ! -d /var/code/$APP_NAME/.git ]
8
+ then
9
+ git clone git@$REPOSITORY_HOST:$REPOSITORY_NAME /var/code/$APP_NAME
10
+ fi
@@ -0,0 +1,15 @@
1
+ #! /bin/bash
2
+
3
+ DATABASE_NAME=$1
4
+ DATABASE_USER=$2
5
+ DATABASE_PASSWORD=$3
6
+
7
+ service mysql start;
8
+ COMMAND="CREATE USER '$DATABASE_USER'@'localhost' IDENTIFIED BY '$DATABASE_PASSWORD';";
9
+ COMMAND="$COMMAND CREATE USER '$DATABASE_USER'@'%' IDENTIFIED BY '$DATABASE_PASSWORD';";
10
+
11
+ COMMAND="$COMMAND GRANT ALL ON $DATABASE_NAME.* to '$DATABASE_USER'@'localhost';";
12
+ COMMAND="$COMMAND GRANT ALL ON $DATABASE_NAME.* to '$DATABASE_USER'@'%';";
13
+ COMMAND="$COMMAND CREATE DATABASE $DATABASE_NAME;";
14
+
15
+ mysql -uroot -e "$COMMAND";
@@ -13,11 +13,12 @@ COPY index_config.erb /var/docker/index_config.erb
13
13
  COPY app_config.erb /var/docker/app_config.erb
14
14
 
15
15
  <% @projects.each do |project| %>
16
- <% app_list = project.apps.map(&:name).join(',') %>
16
+
17
+ <% app_list = project.apps.map(&:name).join(',') %>
17
18
  RUN ruby /var/docker/add_project.rb <%= project.system_prefix %> <%= project.domain %> <%= app_list %>
18
- <% project.apps.each do |app| %>
19
+ <% project.apps.each do |app| %>
19
20
  RUN ruby /var/docker/add_app.rb <%= project.system_prefix %> <%= project.domain %> <%= app.name %> <%= app.port %>
20
- <% end %>
21
+ <% end %>
21
22
  <% end %>
22
23
 
23
24
  RUN rm -r /var/docker
@@ -0,0 +1,3 @@
1
+ #! /usr/local/bin/ruby
2
+
3
+ system "bundle install"
@@ -0,0 +1,34 @@
1
+ #! /usr/local/bin/ruby
2
+
3
+ require 'yaml'
4
+ require 'fileutils'
5
+
6
+ puts "Loading seeds"
7
+
8
+ system "service mysql start"
9
+
10
+ config_path = "./config/database.yml"
11
+
12
+ database_config = {
13
+ 'development' => {
14
+ 'adapter' => 'mysql2',
15
+ 'encoding' => 'utf8',
16
+ 'reconnect' => true,
17
+ 'username' => ENV['DATABASE_USERNAME'],
18
+ 'password' => ENV['DATABASE_PASSWORD'],
19
+ 'host' => 'localhost',
20
+ 'database' => ENV['DATABASE_NAME']
21
+ }
22
+ }
23
+
24
+ File.open(config_path, "w") do |file|
25
+ file.write(database_config.to_yaml)
26
+ end
27
+
28
+ system "bundle install"
29
+ tables = `mysql -uroot -e "SHOW TABLES" #{ENV['DATABASE_NAME']}`
30
+ if tables == ''
31
+ system "bundle exec rake db:reset"
32
+ else
33
+ system "bundle exec rake db:migrate; bundle exec rake db:seed"
34
+ end
@@ -1,17 +1,11 @@
1
1
  #! /usr/local/bin/ruby
2
2
 
3
3
  require 'fileutils'
4
- require_relative 'checkout'
5
- require_relative 'update_database_config'
6
-
7
- FileUtils.cd '/var/code'
8
4
 
9
5
  system "bundle install"
10
6
  system "rake db:migrate"
11
-
12
7
  system "rails r Rails.cache.clear"
8
+
13
9
  if ENV['RAILS_ENV'] != 'development'
14
10
  system "rake assets:precompile"
15
- end
16
-
17
- exec "rails s -b 0.0.0.0 -p $RAILS_PORT -e $RAILS_ENV"
11
+ end
@@ -23,7 +23,6 @@ database_config = {
23
23
  if ENV['RAILS_ENV'] == 'development' && local_database
24
24
  database_config['test'] = common_config.dup
25
25
  database_config['test']['database'] += '_test'
26
- database_config['development']['database'] += '_development'
27
26
  end
28
27
 
29
28
  File.open('/var/code/config/database.yml', 'w') do |file|
@@ -0,0 +1,40 @@
1
+ module RubyYacht::Plugins
2
+ # This module provides the plugin for managing Ruby on Rails apps.
3
+ module Rails
4
+ # This method loads the configuration for the Rails plugin.
5
+ def self.load
6
+ RubyYacht.configure do
7
+ app_type :rails do
8
+ baseline_image 'ruby:2.3'
9
+ project_attribute name: :environment, default: 'development'
10
+ project_attribute name: :secret_key_base
11
+
12
+ environment_variable :app, 'RAILS_ENV' do
13
+ @project.rails_environment
14
+ end
15
+
16
+ environment_variable :app, 'SECRET_KEY_BASE' do
17
+ @project.rails_secret_key_base
18
+ end
19
+ end
20
+ end
21
+
22
+ RubyYacht.configure do
23
+ add_hooks(app_type: :rails, folder: File.join(File.dirname(__FILE__), 'rails', 'scripts')) do
24
+ during(:install_libraries) { run_script 'install_gems.rb' }
25
+
26
+ after(:build_checkout) { command 'bundle install && bundle clean --force' }
27
+
28
+ during(:load_database_seeds) { run_script 'load_seeds.rb' }
29
+
30
+ before(:startup) { run_script 'update_rails_config.rb' }
31
+ before(:startup) { run_script 'prepare_rails_for_launch.rb' }
32
+
33
+ during(:startup) { command 'rails s -b 0.0.0.0 -p $APP_PORT -e $RAILS_ENV' }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ RubyYacht::Plugins::Rails.load
@@ -0,0 +1,6 @@
1
+ module RubyYacht
2
+ # This module groups plugins that can customize the build behavior.
3
+ module Plugins
4
+ end
5
+ end
6
+ require 'ruby_yacht/plugins/rails'
@@ -28,13 +28,19 @@ module RubyYacht::Runner
28
28
  FileUtils.cp(id_path, tmp_id_path)
29
29
  end
30
30
 
31
- build_image 'app-dependencies'
31
+ project.apps.map(&:app_type).uniq.each do |type_name|
32
+ @app_type = RubyYacht.configuration.find_app_type(type_name)
33
+ build_image 'app-dependencies', "#{@project.system_prefix}-#{@app_type.name}-app-dependencies"
34
+ end
35
+
32
36
  build_image 'database' if project.database.local?
33
37
 
34
38
  @project.apps.each do |app|
35
39
  @app = app
40
+ @app_type = RubyYacht.configuration.find_app_type(@app.app_type)
36
41
  build_image 'app', "#{@project.system_prefix}-#{app.name}"
37
42
  end
43
+ @app = nil
38
44
 
39
45
  if @project.create_deploy_container
40
46
  build_image 'deploy'
@@ -55,6 +61,10 @@ module RubyYacht::Runner
55
61
  # current context, and write it to the Dockerfile in the tmp folder. It will
56
62
  # then build the image, and clear out the tmp folder.
57
63
  #
64
+ # Depending on the image type, it may also copy and interpret other template
65
+ # files. For instance, for app containers we also have erb files for the
66
+ # `startup.bash` and `before_startup.bash` scripts.
67
+ #
58
68
  # ### Parameters
59
69
  #
60
70
  # * **folder_name: String** The name of the folder containing the
@@ -65,12 +75,46 @@ module RubyYacht::Runner
65
75
  # dash, followed by the folder name.
66
76
  def build_image(folder_name, image_name = nil)
67
77
  Dir[File.join(File.dirname(File.dirname(__FILE__)), 'images', folder_name, '*')].each do |path|
68
- FileUtils.cp(path, 'tmp')
78
+ FileUtils.cp(path, File.join('tmp', File.basename(path)))
69
79
  end
80
+
81
+ templates =
82
+ case folder_name
83
+ when 'app' then ['Dockerfile', 'before_startup.bash', 'startup.bash']
84
+ else ['Dockerfile']
85
+ end
86
+
87
+ hook_events =
88
+ case folder_name
89
+ when 'app' then [:startup, :build_checkout]
90
+ when 'app-dependencies' then [:install_libraries]
91
+ when 'database' then [:load_database_seeds]
92
+ else []
93
+ end
94
+
95
+ app_types =
96
+ case folder_name
97
+ when 'database' then @project.apps.map(&:app_type).uniq
98
+ else [@app_type.name]
99
+ end
70
100
 
71
- File.open(File.join('tmp', 'Dockerfile'), 'w') do |file|
72
- contents = ERB.new(File.read(File.join('tmp', 'Dockerfile.erb'))).result(binding)
73
- file.write(contents)
101
+ hook_events.each do |event|
102
+ app_types.each do |app_type|
103
+ RubyYacht.configuration.fetch_hooks(app_type: app_type, event_type: event).each do |hook|
104
+ next unless hook.script_path
105
+ FileUtils.cp hook.script_path, "tmp"
106
+ end
107
+ end
108
+ end
109
+
110
+ templates.each do |template_name|
111
+ File.open(File.join('tmp', template_name), 'w') do |file|
112
+ template_contents = File.read(File.join('tmp', template_name + '.erb'))
113
+ file_contents = ERB.new(template_contents, nil, '<>').result(binding)
114
+ file_contents.gsub!(/\n\n\n+/, "\n\n")
115
+ file_contents.gsub!(/\n*\Z/, "")
116
+ file.write(file_contents)
117
+ end
74
118
  end
75
119
 
76
120
  image_name ||= "#{@project.system_prefix}-#{folder_name}"
@@ -78,5 +122,28 @@ module RubyYacht::Runner
78
122
 
79
123
  FileUtils.rm(Dir[File.join("tmp", "*")])
80
124
  end
125
+
126
+ # This method includes the hooks for an event in a Dockerfile.
127
+ #
128
+ # It will run the commands for the before hooks, then the during hooks, then
129
+ # the after hooks.
130
+ #
131
+ # ### Parameters
132
+ #
133
+ # * **event_type: Symbol** The event whose hooks we are running.
134
+ #
135
+ # ### Returns
136
+ #
137
+ # A String with the contents of the Dockerfile for running the hooks.
138
+ def include_event(event_type)
139
+ result = ""
140
+ [:before, :during, :after].each do |time|
141
+ before_hooks = RubyYacht.configuration.fetch_hooks(app_type: @app_type.name, event_type: event_type, event_time: time).each do |hook|
142
+ result += "RUN #{hook.command}\n"
143
+ end
144
+ end
145
+
146
+ result
147
+ end
81
148
  end
82
149
  end
@@ -59,7 +59,7 @@ module RubyYacht::Runner
59
59
  container_name = "#{project.system_prefix}-#{app}"
60
60
 
61
61
  docker "exec #{container_name} bash -c 'cd /var/code; git fetch; git checkout .; git checkout #{branch}; git pull'"
62
- docker "exec #{container_name} bash -c '/var/docker/update_database_config.rb; rake db:migrate'"
62
+ docker "exec #{container_name} /var/docker/before_startup.bash"
63
63
  docker "restart #{container_name}"
64
64
 
65
65
  true
data/lib/ruby_yacht.rb CHANGED
@@ -3,4 +3,5 @@ module RubyYacht
3
3
  end
4
4
 
5
5
  require 'ruby_yacht/dsl'
6
- require 'ruby_yacht/runner'
6
+ require 'ruby_yacht/runner'
7
+ require 'ruby_yacht/plugins'
data/ruby_yacht.gemspec CHANGED
@@ -1,7 +1,8 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = 'ruby_yacht'
3
- spec.version = '0.1.1'
3
+ spec.version = '0.2.0'
4
4
  spec.date = '2016-04-17'
5
+ spec.description = "A DSL for building docker containers for a family of Rails apps"
5
6
  spec.summary = "A DSL for building docker containers for a family of Rails apps"
6
7
  spec.authors = ["John Brownlee"]
7
8
  spec.email = 'apps@mail.johnbrownlee.com'
@@ -2,4 +2,4 @@ FROM ruby:2.3
2
2
 
3
3
  VOLUME /var/code
4
4
  WORKDIR /var/code
5
- CMD bash
5
+ CMD bundle install; bash
data/spec/dsl/app_spec.rb CHANGED
@@ -5,28 +5,62 @@ RSpec.describe RubyYacht::App do
5
5
  let(:name) { :test_app }
6
6
  let(:app) { RubyYacht::App::DSL.new(name).run(@builder).create_object }
7
7
 
8
+ before do
9
+ RubyYacht.configuration.clear
10
+ RubyYacht.configure do
11
+ app_type :test do
12
+ baseline_image 'ubuntu'
13
+ end
14
+ end
15
+ end
16
+
8
17
  it "creates an app with all fields" do
9
18
  @builder = Proc.new do
10
19
  repository_name 'brownleej/test-app'
20
+ app_type :test
11
21
  port 3000
12
22
  end
13
23
  expect(app.name).to eq :test_app
14
24
  expect(app.repository_name).to eq 'brownleej/test-app'
25
+ expect(app.app_type).to eq :test
15
26
  expect(app.port).to eq 3000
16
27
  end
17
28
 
18
29
  it "requires the repository name" do
19
30
  @builder = Proc.new do
20
31
  port 3000
32
+ app_type :test
21
33
  end
22
34
  expect do
23
35
  self.app
24
36
  end.to raise_exception("Missing required attribute repository_name for RubyYacht::App::DSL")
25
37
  end
26
38
 
39
+ it "requires the app type" do
40
+ @builder = Proc.new do
41
+ repository_name 'brownleej/test-app'
42
+ port 3000
43
+ end
44
+ expect do
45
+ self.app
46
+ end.to raise_exception("Missing required attribute app_type for RubyYacht::App::DSL")
47
+ end
48
+
49
+ it "requires a defined app type" do
50
+ @builder = Proc.new do
51
+ app_type :invalid
52
+ repository_name 'brownleej/test-app'
53
+ port 3000
54
+ end
55
+ expect do
56
+ self.app
57
+ end.to raise_exception("App has invalid app type `invalid`")
58
+ end
59
+
27
60
  it "defaults the port to 8080" do
28
61
  @builder = Proc.new do
29
62
  repository_name 'brownleej/test-app'
63
+ app_type :test
30
64
  end
31
65
  expect(app.port).to eq 8080
32
66
  end