capistrano / capistrano/symfony
symfony_console ignores caller-supplied role/host scope, always uses symfony_deploy_roles
- Dominant language
- Ruby
- Stars
- 353
- Forks
- 61
- PR merge metrics
- No merged PRs in 30d
Description
## Bug
`symfony_console` in `lib/capistrano/dsl/symfony.rb` always wraps its `execute` call in its own `on` block:
```ruby
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):
```ruby
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
```ruby
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.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at symfony_console in lib/capistrano/dsl/symfony.rb, then inspect its callers in lib/capistrano/tasks/symfony.rake and the role defaults in lib/capistrano/symfony/defaults.rb. Verify the reproduction with a caller-selected role such as :db; done means symfony:console preserves that host scope instead of re-resolving symfony_deploy_roles.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- devops, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 85/100