Skip to content

symfony_console ignores caller-supplied role/host scope, always uses symfony_deploy_roles #126

Description

@ahmed-bhs

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions