Bug
symfony_console in lib/capistrano/dsl/symfony.rb always wraps its execute call in its own on block:
def symfony_console(command, params = '')
on release_roles(fetch(:symfony_deploy_roles)) do
execute fetch(:php), symfony_console_path, command, params, fetch(:symfony_console_flags)
end
end
Every caller of symfony_console in lib/capistrano/tasks/symfony.rake already invokes it from inside its own on block, using a role the caller chose (e.g. symfony:console's :role argument, or a project's own custom role variable):
task :console, :command, :params, :role do |t, args|
role = args[:role] || fetch(:symfony_roles)
on release_roles(role) do
within release_path do
symfony_console(command, params) # <- nested `on` happens here
end
end
end
SSHKit's on just instantiates a new Coordinator per call; there is no shared "current backend" that a nested on inherits or is constrained by. So the inner on release_roles(fetch(:symfony_deploy_roles)) inside symfony_console silently ignores whatever host scope the outer on was already running under, and re-resolves hosts from symfony_deploy_roles (default :all) instead.
Concretely: a project cannot scope a symfony:console-based command (e.g. a Doctrine migration that should run once, only on a primary/db host) to a subset of hosts by passing a role to symfony:console's :role arg, or by wrapping the call in on roles(:db) do ... end. It will always run on every host in symfony_deploy_roles, regardless.
This looks related to the symfony_deploy_roles vs symfony_roles inconsistency reported in #90 — same root cause (two separate, unsynchronized role variables), different symptom.
Reproduction
set :symfony_deploy_roles, :all # gem default, from lib/capistrano/symfony/defaults.rb
# server "web1", roles: [:app, :web, :db]
# server "web2", roles: [:app, :web]
namespace :ocab do
task :migrate do
on roles(:db) do # intent: web1 only
invoke "symfony:console", "doctrine:migrations:migrate", "", :db
end
end
end
Expected: migration runs once, on web1 only.
Actual: migration runs on both web1 and web2, because symfony_console's inner on release_roles(:all) overrides the intended scope.
Fix
See linked PR: remove the inner on/release_roles call from symfony_console and let it run in whatever host context the caller already established, since every existing caller in this gem already calls it from inside an on block.
Bug
symfony_consoleinlib/capistrano/dsl/symfony.rbalways wraps itsexecutecall in its ownonblock:Every caller of
symfony_consoleinlib/capistrano/tasks/symfony.rakealready invokes it from inside its ownonblock, using a role the caller chose (e.g.symfony:console's:roleargument, or a project's own custom role variable):SSHKit's
onjust instantiates a newCoordinatorper call; there is no shared "current backend" that a nestedoninherits or is constrained by. So the inneron release_roles(fetch(:symfony_deploy_roles))insidesymfony_consolesilently ignores whatever host scope the outeronwas already running under, and re-resolves hosts fromsymfony_deploy_roles(default:all) instead.Concretely: a project cannot scope a symfony:console-based command (e.g. a Doctrine migration that should run once, only on a primary/db host) to a subset of hosts by passing a role to
symfony:console's:rolearg, or by wrapping the call inon roles(:db) do ... end. It will always run on every host insymfony_deploy_roles, regardless.This looks related to the
symfony_deploy_rolesvssymfony_rolesinconsistency reported in #90 — same root cause (two separate, unsynchronized role variables), different symptom.Reproduction
Expected: migration runs once, on
web1only.Actual: migration runs on both
web1andweb2, becausesymfony_console's inneron release_roles(:all)overrides the intended scope.Fix
See linked PR: remove the inner
on/release_rolescall fromsymfony_consoleand let it run in whatever host context the caller already established, since every existing caller in this gem already calls it from inside anonblock.