lib/capistrano/configuration/scm_resolver.rb
module Capistrano
class Configuration
# In earlier versions of Capistrano, users would specify the desired SCM
# implementation using `set :scm, :git`, for example. Capistrano would then
# load the matching .rb file based on this variable.
#
# Now we expect users to explicitly `require` and call `new` on the desired
# SCM implementation in their Capfile. The `set` technique is deprecated.
#
# This SCMResolver class takes care of managing the transition from the old
# to new system. It maintains the legacy behavior, but prints deprecation
# warnings when it is used.
#
# To maintain backwards compatibility, the resolver will load the Git SCM by
# if default it determines that no SCM has been explicitly specified or
# loaded. To force no SCM to be used at all, use `set :scm, nil`. This hack
# won't be necessary once backwards compatibility is removed in a future
# version.
#
# TODO: Remove this class entirely in Capistrano 4.0.
#
class SCMResolver
DEFAULT_GIT = :"default-git"
include Capistrano::DSL
def resolve
return if scm_name.nil?
set(:scm, :git) if using_default_scm?
print_deprecation_warnings_if_applicable
# Note that `scm_plugin_installed?` comes from Capistrano::DSL
if scm_plugin_installed?
delete(:scm)
return
end
if built_in_scm_name?
load_built_in_scm
else
# Compatibility with existing 3.x third-party SCMs
register_legacy_scm_hooks
load_legacy_scm_by_name
end
end
private
def using_default_scm?
return @using_default_scm if defined? @using_default_scm
@using_default_scm = (fetch(:scm) == DEFAULT_GIT)
end
def scm_name
fetch(:scm)
end
def load_built_in_scm
require "capistrano/scm/#{scm_name}"
scm_class = Object.const_get(built_in_scm_plugin_class_name)
# We use :load_immediately because we are initializing the SCM plugin
# late in the load process and therefore can't use the standard
# load:defaults technique.
install_plugin(scm_class, load_immediately: true)
end
def load_legacy_scm_by_name
load("capistrano/#{scm_name}.rb")
end
def third_party_scm_name?
!built_in_scm_name?
end
def built_in_scm_name?
%w(git hg svn).include?(scm_name.to_s.downcase)
end
def built_in_scm_plugin_class_name
"Capistrano::SCM::#{scm_name.to_s.capitalize}"
end
# rubocop:disable Style/GuardClause
def register_legacy_scm_hooks
if Rake::Task.task_defined?("deploy:new_release_path")
after "deploy:new_release_path", "#{scm_name}:create_release"
end
if Rake::Task.task_defined?("deploy:check")
before "deploy:check", "#{scm_name}:check"
end
if Rake::Task.task_defined?("deploy:set_current_revision")
before "deploy:set_current_revision",
"#{scm_name}:set_current_revision"
end
end
# rubocop:enable Style/GuardClause
def print_deprecation_warnings_if_applicable
if using_default_scm?
warn_add_git_to_capfile unless scm_plugin_installed?
elsif built_in_scm_name?
warn_set_scm_is_deprecated
elsif third_party_scm_name?
warn_third_party_scm_must_be_upgraded
end
end
def warn_set_scm_is_deprecated
$stderr.puts(<<-MESSAGE)
[Deprecation Notice] `set :scm, #{scm_name.inspect}` is deprecated.
To ensure your project is compatible with future versions of Capistrano,
remove the :scm setting and instead add these lines to your Capfile after
`require "capistrano/deploy"`:
require "capistrano/scm/#{scm_name}"
install_plugin #{built_in_scm_plugin_class_name}
MESSAGE
end
def warn_add_git_to_capfile
$stderr.puts(<<-MESSAGE)
[Deprecation Notice] Future versions of Capistrano will not load the Git SCM
plugin by default. To silence this deprecation warning, add the following to
your Capfile after `require "capistrano/deploy"`:
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
MESSAGE
end
def warn_third_party_scm_must_be_upgraded
$stderr.puts(<<-MESSAGE)
[Deprecation Notice] `set :scm, #{scm_name.inspect}` is deprecated.
To ensure this custom SCM will work with future versions of Capistrano,
please upgrade it to a version that uses the new SCM plugin mechanism
documented here:
http://capistranorb.com/documentation/advanced-features/custom-scm
MESSAGE
end
end
end
end