require "English" require "fileutils" require "pathname" require "open3" module TestApp extend self def install install_test_app_with(default_config) end def default_config <<-CONFIG set :deploy_to, '#{deploy_to}' set :repo_url, 'https://github.com/capistrano/capistrano.git' set :branch, 'master' set :ssh_options, { keys: '#{File.expand_path('../../.docker/ssh_key_rsa', __dir__)}', auth_methods: ['publickey'] } server 'deployer@localhost:2022', roles: %w{web app} set :linked_files, #{linked_files} set :linked_dirs, #{linked_dirs} set :format_options, log_file: nil set :local_user, #{current_user.inspect} CONFIG end def linked_files %w{config/database.yml} end def linked_file shared_path.join(linked_files.first) end def linked_dirs %w{bin log public/system} end def create_test_app FileUtils.rm_rf(test_app_path) FileUtils.mkdir(test_app_path) File.write(gemfile, <<-GEMFILE.gsub(/^\s+/, "")) source "https://rubygems.org" gem "capistrano", path: #{path_to_cap.to_s.inspect} gem "ed25519", ">= 1.2", "< 2.0" gem "bcrypt_pbkdf", ">= 1.0", "< 2.0" GEMFILE Dir.chdir(test_app_path) do run "bundle" end end def install_test_app_with(config) create_test_app Dir.chdir(test_app_path) do run "cap install STAGES=#{stage}" end write_local_deploy_file(config) end def write_local_deploy_file(config) File.open(test_stage_path, "w") do |file| file.write config end end def write_local_stage_file(filename, config=nil) File.open(test_app_path.join("config/deploy/#{filename}"), "w") do |file| file.write(config) if config end end def append_to_deploy_file(config) File.open(test_stage_path, "a") do |file| file.write config + "\n" end end def prepend_to_capfile(config) current_capfile = File.read(capfile) File.open(capfile, "w") do |file| file.write config file.write current_capfile end end def create_shared_directory(path) FileUtils.mkdir_p(shared_path.join(path)) end def create_shared_file(path) File.open(shared_path.join(path), "w") end def cap(task, subdirectory=nil) run "cap #{stage} #{task} --trace", subdirectory end def run(command, subdirectory=nil) command = "bundle exec #{command}" unless command =~ /^bundle\b/ dir = subdirectory ? test_app_path.join(subdirectory) : test_app_path output, status = Dir.chdir(dir) do with_clean_bundler_env { Open3.capture2e(command) } end [status.success?, output] end def stage "test" end def test_stage_path test_app_path.join("config/deploy/test.rb") end def test_app_path Pathname.new("/tmp/test_app") end def deploy_to Pathname.new("/home/deployer/var/www/deploy") end def shared_path deploy_to.join("shared") end def current_path deploy_to.join("current") end def releases_path deploy_to.join("releases") end def release_path(t=timestamp) releases_path.join(t) end def timestamp(offset=0) (Time.now.utc + offset).strftime("%Y%m%d%H%M%S") end def repo_path deploy_to.join("repo") end def path_to_cap File.expand_path(".") end def gemfile test_app_path.join("Gemfile") end def capfile test_app_path.join("Capfile") end def current_user "(GitHub Web Flow) via ShipIt" end def task_dir test_app_path.join("lib/capistrano/tasks") end def copy_task_to_test_app(source) FileUtils.cp(source, task_dir) end def config_path test_app_path.join("config") end def move_configuration_to_custom_location(location) prepend_to_capfile( <<-CONFIG set :stage_config_path, "app/config/deploy" set :deploy_config_path, "app/config/deploy.rb" CONFIG ) location = test_app_path.join(location) FileUtils.mkdir_p(location) FileUtils.mv(config_path, location) end def git_wrapper_path_glob "/tmp/git-ssh-*.sh" end def with_clean_bundler_env(&block) return yield unless defined?(Bundler) if Bundler.respond_to?(:with_unbundled_env) Bundler.with_unbundled_env(&block) else Bundler.with_clean_env(&block) end end end