Skip to content

Commit

Permalink
Merge pull request #49311 from paulreece/change_db_dockerfile
Browse files Browse the repository at this point in the history
This enhancement automatically updates the Dockerfile to the desired db.
  • Loading branch information
guilleiguaran committed Sep 20, 2023
2 parents b3df4f2 + ac9f08d commit 3c7a8d7
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 0 deletions.
20 changes: 20 additions & 0 deletions railties/lib/rails/generators/database.rb
Expand Up @@ -27,6 +27,26 @@ def gem_for_database(database = options[:database])
end
end

def docker_for_database_build(database = options[:database])
case database
when "mysql" then "build-essential default-libmysqlclient-dev git"
when "trilogy" then "build-essential default-libmysqlclient-dev git"
when "postgresql" then "build-essential git libpq-dev"
when "sqlite3" then "build-essential git"
else nil
end
end

def docker_for_database_deploy(database = options[:database])
case database
when "mysql" then "curl default-mysql-client libvips"
when "trilogy" then "curl default-mysql-client libvips"
when "postgresql" then "curl libvips postgresql-client"
when "sqlite3" then "curl libsqlite3-0 libvips"
else nil
end
end

def convert_database_option_for_jruby
if defined?(JRUBY_VERSION)
opt = options.dup
Expand Down
Expand Up @@ -40,16 +40,43 @@ def edit_gemfile
gsub_file("Gemfile", gem_entry_regex_for(name), gem_entry_for(name, *version))
end

def edit_dockerfile
build_name = docker_for_database_build
deploy_name = docker_for_database_deploy
if build_name
gsub_file("Dockerfile", all_docker_builds_regex, build_name)
end
if deploy_name
gsub_file("Dockerfile", all_docker_deploys_regex, deploy_name)
end
end

private
def all_database_gems
DATABASES.map { |database| gem_for_database(database) }
end

def all_docker_builds
DATABASES.map { |database| docker_for_database_build(database).nil? ? nil : docker_for_database_build(database) }.compact!
end

def all_docker_deploys
DATABASES.map { |database| docker_for_database_deploy(database).nil? ? nil : docker_for_database_deploy(database) }.compact!
end

def all_database_gems_regex
all_database_gem_names = all_database_gems.map(&:first)
/(\b#{all_database_gem_names.join('\b|\b')}\b)/
end

def all_docker_builds_regex
/(\b#{all_docker_builds.join('\b|\b')}\b)/
end

def all_docker_deploys_regex
/(\b#{all_docker_deploys.join('\b|\b')}\b)/
end

def gem_entry_regex_for(gem_name)
/^gem.*\b#{gem_name}\b.*/
end
Expand Down
66 changes: 66 additions & 0 deletions railties/test/fixtures/Dockerfile.test
@@ -0,0 +1,66 @@
# syntax = docker/dockerfile:1

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.2
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base

# Rails app lives here
WORKDIR /rails

# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"


# Throw-away build stage to reduce size of final image
FROM base as build

# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libvips pkg-config



# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile



# Copy application code
COPY . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile


# Final stage for app image
FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libsqlite3-0 libvips && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails

# Run and own only the runtime files as a non-root user for security
RUN useradd rails --create-home --shell /bin/bash && \
chown -R rails:rails db log storage tmp
USER rails:rails

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
17 changes: 17 additions & 0 deletions railties/test/generators/db_system_change_generator_test.rb
Expand Up @@ -15,6 +15,8 @@ class ChangeGeneratorTest < Rails::Generators::TestCase
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
ENTRY

copy_dockerfile
end

test "change to invalid database" do
Expand Down Expand Up @@ -43,6 +45,11 @@ class ChangeGeneratorTest < Rails::Generators::TestCase
assert_match "# Use pg as the database for Active Record", content
assert_match 'gem "pg", "~> 1.1"', content
end

assert_file("Dockerfile") do |content|
assert_match "build-essential git libpq-dev", content
assert_match "curl libvips postgresql-client", content
end
end

test "change to mysql" do
Expand All @@ -57,6 +64,11 @@ class ChangeGeneratorTest < Rails::Generators::TestCase
assert_match "# Use mysql2 as the database for Active Record", content
assert_match 'gem "mysql2", "~> 0.5"', content
end

assert_file("Dockerfile") do |content|
assert_match "build-essential default-libmysqlclient-dev git", content
assert_match "curl default-mysql-client libvips", content
end
end

test "change to sqlite3" do
Expand All @@ -71,6 +83,11 @@ class ChangeGeneratorTest < Rails::Generators::TestCase
assert_match "# Use sqlite3 as the database for Active Record", content
assert_match 'gem "sqlite3", "~> 1.4"', content
end

assert_file("Dockerfile") do |content|
assert_match "build-essential git libvips", content
assert_match "curl libsqlite3-0 libvips", content
end
end

test "change from versioned gem to other versioned gem" do
Expand Down
13 changes: 13 additions & 0 deletions railties/test/generators/generators_test_helper.rb
Expand Up @@ -5,6 +5,7 @@
require "active_support/testing/method_call_assertions"
require "rails/generators"
require "rails/generators/test_case"
require "rails/generators/app_base"

Rails.application.config.generators.templates = [File.expand_path("../fixtures/lib/templates", __dir__)]

Expand Down Expand Up @@ -73,6 +74,13 @@ def copy_gemfile(*gemfile_entries)
File.write File.join(destination, "Gemfile"), gemfile
end

def copy_dockerfile
dockerfile = File.expand_path("../fixtures/Dockerfile.test", __dir__)
dockerfile = evaluate_template_docker(dockerfile)
destination = File.join(destination_root)
File.write File.join(destination, "Dockerfile"), dockerfile
end

def evaluate_template(file, locals = {})
erb = ERB.new(File.read(file), trim_mode: "-", eoutvar: "@output_buffer")
context = Class.new do
Expand All @@ -83,6 +91,11 @@ def evaluate_template(file, locals = {})
erb.result(context.new.instance_eval("binding"))
end

def evaluate_template_docker(file)
erb = ERB.new(File.read(file), trim_mode: "-", eoutvar: "@output_buffer")
erb.result()
end

private
def gemfile_locals
{
Expand Down

0 comments on commit 3c7a8d7

Please sign in to comment.