Skip to content

Instantly share code, notes, and snippets.

@kofiasare-dev
Last active October 16, 2023 07:52
Show Gist options
  • Save kofiasare-dev/0708f9e39bfd5aac32e809a9eea5d3d2 to your computer and use it in GitHub Desktop.
Save kofiasare-dev/0708f9e39bfd5aac32e809a9eea5d3d2 to your computer and use it in GitHub Desktop.
Create docker compose rails app
#!/bin/bash
set -e
create_dir() {
local target="$1"
if [ -d "$target" ]; then
echo "❌ Directory '$target' already exists. Skipping."
else
mkdir -p "$target"
echo "✅ Created directory: $target"
fi
}
create_file() {
local target="$1"
local content="$2"
if [ -f "$target" ]; then
echo "❌ File '$target' already exists. Skipping."
else
echo "$content" >"$target"
echo "✅ Created file: $target"
fi
}
write_file() {
local filename="$1"
local content="$2"
echo "$content" >"$filename"
}
create_rails_api() {
local app="$1"
RUBY_VERSION=3.2.2
RAILS_VERSION='7.1.0.rc1'
DB_DOCKERFILE=db/Dockerfile
DB_DOCKERFILE_CONTENT="FROM postgres:15.1-alpine"
CREATE_DB_SQL=db/initdb.d/01_create_db.sql
CREATE_DB_SQL_CONTENT=$(
cat <<EOL
CREATE DATABASE $app;
CREATE DATABASE ${app}_testd;
EOL
)
DOCKER_COMPOSE_FILE=docker-compose.yml
DOCKER_COMPOSE_FILE_CONTENT=$(
cat <<EOL
version: "3"
x-rails: &rails-config
build: .
volumes:
- ./:/app
- api_gem_path:/bundle
environment:
- RUBY_YJIT_ENABLE=1
- BUNDLE_GEMFILE=/app/Gemfile
- BUNDLE_PATH=/bundle/vendor
- RAILS_ENV=\$RAILS_ENV
- DB_HOST=\$DB_HOST
- DB_PASSWORD=\$DB_PASSWORD
- HOST_PORT=\$HOST_PORT
- CONTAINER_PORT=\$CONTAINER_PORT
services:
db:
build:
context: db
environment:
- POSTGRES_PASSWORD=\$DB_PASSWORD
volumes:
- ./db/initdb.d:/docker-entrypoint-initdb.d
- db_data:/var/lib/postgresql/data
ports:
- 5432:5432
api:
<<: *rails-config
tty: true
stdin_open: true
ports:
- \$HOST_PORT:\$CONTAINER_PORT
command: |
sh -c "rm -f /app/tmp/pids/server.pid &&
bin/rails db:migrate
bin/rails db:seed
bin/rails s -b 0.0.0.0 -p \$CONTAINER_PORT"
depends_on:
- db
volumes:
db_data:
api_gem_path:
external: true
EOL
)
DOCKERFILE=Dockerfile
DOCKERFILE_CONTENT=$(
cat <<EOL
FROM ruby:${RUBY_VERSION}
RUN apt-get update -qq && apt-get install -y postgresql-client vim
WORKDIR /app
ADD Gemfile /app/Gemfile
EOL
)
DOCKER_IGNORE_FILE=.dockerignore
DOCKER_IGNORE_FILE_CONTENT=$(
cat <<EOL
crapi.sh
.env
.git
EOL
)
GEMFILE=Gemfile
GEMFILE_CONTENT=$(
cat <<EOL
# frozen_string_literal: true
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '~> ${RUBY_VERSION}'
gem 'rails', '${RAILS_VERSION}'
EOL
)
MAKEFILE=Makefile
MAKEFILE_CONTENT=$(
cat <<EOL
.PHONY: build install up debug down shell test
build:
@docker compose build
install:
@docker compose run --rm --no-deps --entrypoint bundle api install --jobs=3 --retry=5
up:
@docker compose up -d
debug:
@docker compose up -d
@docker attach \$\$(docker compose ps -q api)
down:
@docker compose down
start:
@docker compose start
stop:
@docker compose stop
sh:
@docker compose exec api bash
EOL
)
DOTENV_FILE=.env
DOTENV_FILE_CONTENT=$(
cat <<EOL
RAILS_ENV=development
DB_HOST=db
DB_PASSWORD=postgres
HOST_PORT=4000
CONTAINER_PORT=3000
EOL
)
RUBOCOP_FILE=.rubocop.yml
RUBOCOP_FILE_CONTENT=$(
cat <<EOL
---
require:
- rubocop-performance
- rubocop-rails
Style/FrozenStringLiteralComment:
SafeAutoCorrect: true
Style/ClassAndModuleChildren:
SafeAutoCorrect: true
EOL
)
create_dir "$app" && cd "$app"
create_dir "db/initdb.d"
create_file "$DB_DOCKERFILE" "$DB_DOCKERFILE_CONTENT"
create_file "$CREATE_DB_SQL" "$CREATE_DB_SQL_CONTENT"
create_file "$DOCKER_COMPOSE_FILE" "$DOCKER_COMPOSE_FILE_CONTENT"
create_file "$DOCKERFILE" "$DOCKERFILE_CONTENT"
create_file "$DOCKER_IGNORE_FILE" "$DOCKER_IGNORE_FILE_CONTENT"
create_file "$GEMFILE" "$GEMFILE_CONTENT"
create_file "$MAKEFILE" "$MAKEFILE_CONTENT"
create_file "$DOTENV_FILE" "$DOTENV_FILE_CONTENT"
create_file "$RUBOCOP_FILE" "$RUBOCOP_FILE_CONTENT"
echo "🔔 Files and directories created successfully!"
echo "🥁 Building docker containers for rails app $app..."
make build
echo "⏳ Preparing to generate your rails app $app..."
make install
echo "🚀 Generating your rails app $app..."
docker compose run --rm --no-deps --entrypoint bundle api exec rails new "$app" . -JTABf -d=postgresql --api --skip-docker --skip-active-storage
rsync -a "$app"/ . && rm -rf "$app"
DB_CONFIG=config/database.yml
DB_CONFIG_CONTENT=$(
cat <<EOL
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: <%= ENV.fetch("DB_HOST") { "localhost" } %>
username: postgres
password: <%= ENV['DB_PASSWORD'] %>
development:
<<: *default
database: ${app}
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: ${app}_testd
production:
<<: *default
database: ${app}_prod
EOL
)
write_file "$DB_CONFIG" "$DB_CONFIG_CONTENT"
GEMFILE=Gemfile
GEMFILE_CONTENT=$(
cat <<EOL
# frozen_string_literal: true
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '~> ${RUBY_VERSION}'
gem 'rails', '${RAILS_VERSION}'
gem 'bootsnap', require: false
gem 'pg', '~> 1.1'
gem 'puma', '6.0'
gem 'rack-cors'
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
group :github do
gem 'plutonium_generators', git: 'https://github.com/plutonium-rails/plutonium-generators'
end
group :development do
gem 'awesome_print'
gem 'rubocop', require: false
gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false
gem 'prosopite'
end
group :development, :test do
gem 'pry-byebug'
gem 'pry-rails'
gem 'spring'
end
EOL
)
write_file "$GEMFILE" "$GEMFILE_CONTENT"
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo "| Post-installation instructions completed.|"
echo "| |"
echo "| cd $app && crapi -i |"
echo "| |"
echo "| springify your app |"
echo "| crapi -sh |"
echo "| bundle exec spring binstub --all |"
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo '🔥🔥 Done !!!'
}
help() {
echo "Usage: crapi [APP_NAME] | [options]"
echo "Options (must be called in a valid 'crapi' directory):"
echo " -b build/rebuild the app"
echo " -i Install dependencies in Gemfile"
echo " -u Start/Up the app"
echo " -dbg Start the app in debug mode"
echo " -s Stop the app"
echo " -u Start/Up the app"
echo " -u Start/Up the app"
}
# Check if there are no arguments
if [ $# -eq 0 ]; then
help
exit 1
fi
# Variable for the app name
APP_NAME="$1"
# Check if the first argument is a valid option
if [ "${APP_NAME:0:1}" = "-" ]; then
if [ -f Makefile ] && [ -f docker-compose.yml ]; then
case "$APP_NAME" in
-b)
make build
;;
-i)
echo "Installing dependencies for app..."
make install
;;
-u)
echo "Starting app..."
make up
;;
-dbg)
echo "Starting app in debug mode..."
make debug
;;
-s)
make stop
;;
-d)
echo "Stopping the app and removing all containers..."
make down
;;
-sh)
make sh
;;
*)
echo "Invalid option: $APP_NAME"
help
exit 1
;;
esac
else
help
exit 1
fi
else
echo "Creating the app '$APP_NAME'..."
create_rails_api "$APP_NAME"
fi
gist_url="https://gist.github.com/kofiasare-dev/0708f9e39bfd5aac32e809a9eea5d3d2"
wget $gist_url/raw -O crapi
chmod +x crapi
mkdir -p ~/bin
mv crapi ~/bin/
add to your .bashrc or .zshrc
export PATH="$PATH:$HOME/bin"
source ~/.bashrc or ~/.zshrc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment