lib/capistrano/dsl.rb
require "capistrano/dsl/task_enhancements"
require "capistrano/dsl/paths"
require "capistrano/dsl/stages"
require "capistrano/dsl/env"
require "capistrano/configuration/filter"
module Capistrano
module DSL
include TaskEnhancements
include Env
include Paths
include Stages
def invoke(task_name, *args)
task = Rake::Task[task_name]
# NOTE: We access instance variable since the accessor was only added recently. Once Capistrano depends on rake 11+, we can revert the following line
if task && task.instance_variable_get(:@already_invoked)
file, line, = caller.first.split(":")
colors = SSHKit::Color.new($stderr)
$stderr.puts colors.colorize("Skipping task `#{task_name}'.", :yellow)
$stderr.puts "Capistrano tasks may only be invoked once. Since task `#{task}' was previously invoked, invoke(\"#{task_name}\") at #{file}:#{line} will be skipped."
$stderr.puts "If you really meant to run this task again, use invoke!(\"#{task_name}\")"
$stderr.puts colors.colorize("THIS BEHAVIOR MAY CHANGE IN A FUTURE VERSION OF CAPISTRANO. Please join the conversation here if this affects you.", :red)
$stderr.puts colors.colorize("https://github.com/capistrano/capistrano/issues/1686", :red)
end
task.invoke(*args)
end
def invoke!(task_name, *args)
task = Rake::Task[task_name]
task.reenable
task.invoke(*args)
end
def t(key, options={})
I18n.t(key, **options.merge(scope: :capistrano))
end
def scm
fetch(:scm)
end
def sudo(*args)
execute :sudo, *args
end
def revision_log_message
fetch(:revision_log_message,
t(:revision_log_message,
branch: fetch(:branch),
user: local_user,
sha: fetch(:current_revision),
release: fetch(:release_timestamp)))
end
def rollback_log_message
t(:rollback_log_message, user: local_user, release: fetch(:rollback_timestamp))
end
def local_user
fetch(:local_user)
end
def lock(locked_version)
VersionValidator.new(locked_version).verify
end
# rubocop:disable Security/MarshalLoad
def on(hosts, options={}, &block)
subset_copy = Marshal.dump(Configuration.env.filter(hosts))
SSHKit::Coordinator.new(Marshal.load(subset_copy)).each(options, &block)
end
# rubocop:enable Security/MarshalLoad
def run_locally(&block)
SSHKit::Backend::Local.new(&block).run
end
# Catch common beginner mistake and give a helpful error message on stderr
def execute(*)
file, line, = caller.first.split(":")
colors = SSHKit::Color.new($stderr)
$stderr.puts colors.colorize("Warning: `execute' should be wrapped in an `on' scope in #{file}:#{line}.", :red)
$stderr.puts
$stderr.puts " task :example do"
$stderr.puts colors.colorize(" on roles(:app) do", :yellow)
$stderr.puts " execute 'whoami'"
$stderr.puts colors.colorize(" end", :yellow)
$stderr.puts " end"
$stderr.puts
raise NoMethodError, "undefined method `execute' for main:Object"
end
end
end
extend Capistrano::DSL