template/bin/setup
#!/usr/bin/env ruby
# frozen_string_literal: true
# This script is a way to set up or update your development environment automatically.
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
# Add necessary setup steps to this method.
def setup!
env ".env", from: ".env.sample"
run "bundle install" if bundle_needed?
run "overcommit --install" if overcommit_installable?
run "bin/rails db:prepare" if database_present?
run install_node_packages_command if node_present?
run "bin/rails tmp:create" if tmp_missing?
run "bin/rails restart" if pid_present?
if git_safe_needed?
say_status :notice,
"Remember to run #{colorize("mkdir -p .git/safe", :yellow)} to trust the binstubs in this project",
:magenta
end
say_status :Ready!,
"Use #{colorize("bin/dev", :yellow)} to start the app, " \
"or #{colorize("bin/rake", :yellow)} to run tests"
end
def run(command, echo: true, silent: false, exception: true)
say_status(:run, command, :blue) if echo
with_original_bundler_env do
options = silent ? {out: File::NULL, err: File::NULL} : {}
system(command, exception:, **options)
end
end
def run?(command)
run command, silent: true, echo: false, exception: false
end
def bundle_needed?
!run("bundle check", silent: true, exception: false)
end
def overcommit_installable?
File.exist?(".overcommit.yml") && !File.exist?(".git/hooks/overcommit-hook") && run?("overcommit -v")
end
def database_present?
File.exist?("config/database.yml")
end
def node_present?
File.exist?("package.json")
end
def install_node_packages_command
if File.exist?("yarn.lock")
"yarn install --check-files"
else
"npm install"
end
end
def tmp_missing?
!Dir.exist?("tmp/pids")
end
def pid_present?
Dir["tmp/pids/*.pid"].any?
end
def git_safe_needed?
ENV["PATH"].include?(".git/safe/../../bin") && !Dir.exist?(".git/safe")
end
def with_original_bundler_env(&)
return yield unless defined?(Bundler)
Bundler.with_original_env(&)
end
def env(env_file, from:)
return unless File.exist?(from)
unless File.exist?(env_file)
say_status(:copy, "#{from} → #{env_file}", :magenta)
require "fileutils"
FileUtils.cp(from, env_file)
end
keys = ->(f) { File.readlines(f).filter_map { |l| l[/^([^#\s][^=\s]*)/, 1] } }
missing = keys[from] - keys[env_file]
return if missing.empty?
say_status(:WARNING, "Your #{env_file} file is missing #{missing.join(", ")}. Refer to #{from} for details.", :red)
end
def say_status(label, message, color = :green)
label = label.to_s.rjust(12)
puts [colorize(label, color), message.gsub(/^/, " " * 13).strip].join(" ")
end
def colorize(str, color)
return str unless color_supported?
code = {red: 31, green: 32, yellow: 33, blue: 34, magenta: 35}.fetch(color)
"\e[0;#{code};49m#{str}\e[0m"
end
def color_supported?
if ENV["TERM"] == "dumb" || !ENV["NO_COLOR"].to_s.empty?
false
else
[$stdout, $stderr].all? { |io| io.respond_to?(:tty?) && io.tty? }
end
end
Dir.chdir(File.expand_path("..", __dir__)) do
setup!
end