capistrano / capistrano/symfony

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

Open Beginner friendly
#126 0 comments 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.