# vim: filetype=ruby require 'capistrano/dsl/opscomplete'
namespace :opscomplete do
include Capistrano::DSL::Opscomplete # desc 'Validate opscomplete specific configuration' task :validate do invoke('opscomplete:ruby:check') end namespace :ruby do desc 'Check if Ruby version is set according to application\'s .ruby-version.' task :check do on roles fetch(:rbenv_roles, :all) do |host| warn("#{host}: Managed Ruby environment! Won't do any changes to ruby version.") if managed_ruby? unless capture(:ruby_get_current_version) == app_ruby_version validation_error!("#{host}: Ruby version is not set according to application\'s .ruby-version file. Use cap opscomplete:ruby:ensure.") end info("#{host}: Ruby #{app_ruby_version} is installed.") end end desc 'Install Ruby version management tool dependencies' task :install_ruby_build do on roles fetch(:rbenv_roles, :all) do execute(:ruby_update_management_tool, :install_build) end end desc 'Update Ruby version management tool' task :update_ruby_build do on roles fetch(:rbenv_roles, :all) do execute(:ruby_update_management_tool, :update_build) end end desc 'Rehash shims (run this after installing executables).' task :rehash do on roles fetch(:rbenv_roles, :all) do execute(:ruby_update_management_tool, :rehash) end end desc 'Install bundler gem' task :install_bundler do on roles fetch(:rbenv_roles, :all) do # manually specified version will take precedence specific_bundler_version = fetch(:bundler_version, app_gemfile_bundled_with_version) if specific_bundler_version # We have to set force = true to overwrite the binary gem_install('bundler', specific_bundler_version, true) unless gem_installed?('bundler', specific_bundler_version) else gem_install('bundler') unless gem_installed?('bundler') end end end desc 'Install geordi gem' task :install_geordi do on roles fetch(:rbenv_roles, :all) do gem_install('geordi') unless gem_installed?('geordi') end end desc 'Install RubyGems' task :install_rubygems do on roles fetch(:rbenv_roles, :all) do # if no rubygems_version was set, we use and don't check the installed rubygems version if fetch(:rubygems_version, false) current_rubygems_version = capture(:ruby_get_current_version, :rubygems).chomp info("Ensuring requested RubyGems version #{fetch(:rubygems_version)}") next if current_rubygems_version == fetch(:rubygems_version) info("Previously installed RubyGems version was #{current_rubygems_version}") execute(:ruby_install_version, :rubygems, "'#{fetch(:rubygems_version)}'") end end end desc 'Install and configure ruby according to applications .ruby-version.' task :ensure do invoke('opscomplete:ruby:update_ruby_build') on roles fetch(:rbenv_roles, :all) do |host| if managed_ruby? validation_error!("#{host}: Managed Ruby environment! Won't do any changes to Ruby version.") end if ruby_installed_versions.include?(app_ruby_version) info("#{host}: Ruby #{app_ruby_version} is installed.") elsif ruby_installable_versions.include?(app_ruby_version) info("#{host}: Configured Ruby version is not installed, but available for installation.") with tmpdir: fetch(:tmp_dir) do execute(:ruby_install_version, "'#{app_ruby_version}'") end else validation_error!("#{host}: Configured Ruby version is neither installed nor installable.") end unless capture(:ruby_get_current_version) == app_ruby_version set :ruby_modified, true execute(:ruby_set_version, "'#{app_ruby_version}'") end end invoke('opscomplete:ruby:install_rubygems') invoke('opscomplete:ruby:install_bundler') invoke('opscomplete:ruby:install_geordi') invoke('opscomplete:ruby:rehash') end desc 'resets the global ruby version and gems to Gemfile and .ruby-version in current_path.' task :reset do on roles fetch(:rbenv_roles, :all) do |host| within current_path do current_ruby_version_file_path = current_path.join('.ruby-version').to_s if test("[ -f #{current_ruby_version_file_path} ]") execute(:rbenv, :global, capture(:cat, current_ruby_version_file_path)) else validation_error!("#{host}: Missing .ruby-version in #{current_path}. Won't set a new global version.") end if test("[ -f '#{current_path}/.bundle/config' ]") debug("#{host}: Found #{current_path}/.bundle/config, running bundle pristine.") set :bundle_gemfile, -> { current_path.join('Gemfile') } execute(:bundle, :pristine) else validation_error!("Unable to find #{current_path}/.bundle/config, won't run bundle pristine.") end end end end desc 'Set the old ruby version before the change and invoke bundle pristine.' task :broken_gems_warning do on roles fetch(:rbenv_roles, :all) do |host| if fetch(:ruby_modified, false) warn('Deploy failed and the ruby version has been modified in this deploy.') warn('If this was a minor ruby version upgrade your running application may run into issues with native gem extensions.') warn("If your deploy failed before deploy:symlink:release you may run bundle exec 'cap #{fetch(:stage)} opscomplete:ruby:reset'.") warn('Please refer https://makandracards.com/makandra/477884-bundler-in-deploy-mode-shares-gems-between-patch-level-ruby-versions') else debug("#{host}: Ruby not modified in current deploy.") end end end end
end