soviann / deploy-tasks-bundle
One-time deploy task runner for Symfony applications
Package info
github.com/Soviann/deploy-tasks-bundle
Type:symfony-bundle
pkg:composer/soviann/deploy-tasks-bundle
Requires
- php: >=8.2
- psr/clock: ^1.0
- psr/log: ^3.0
- symfony/config: ^6.4 || ^7.0 || ^8.0
- symfony/console: ^6.4 || ^7.0 || ^8.0
- symfony/dependency-injection: ^6.4 || ^7.0 || ^8.0
- symfony/event-dispatcher-contracts: ^2.5 || ^3.0
- symfony/filesystem: ^6.4 || ^7.0 || ^8.0
- symfony/finder: ^6.4 || ^7.0 || ^8.0
- symfony/http-kernel: ^6.4 || ^7.0 || ^8.0
- symfony/string: ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- doctrine/dbal: ^4.3
- friendsofphp/php-cs-fixer: ^3.0
- infection/infection: ^0.32
- phpstan/phpstan: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^10.5 || ^11.0
- symfony/clock: ^6.4 || ^7.0 || ^8.0
- symfony/dotenv: ^6.4 || ^7.0 || ^8.0
- symfony/event-dispatcher: ^6.4 || ^7.0 || ^8.0
- symfony/framework-bundle: ^6.4 || ^7.0 || ^8.0
- symfony/lock: ^6.4 || ^7.0 || ^8.0
- symfony/phpunit-bridge: ^8.0.8
- symfony/process: ^6.4 || ^7.0 || ^8.0
Suggests
- doctrine/dbal: Required (^4.3) for the database storage backend
- symfony/event-dispatcher: Required for task lifecycle events
- symfony/lock: Required for concurrent execution protection
- symfony/process: Required by ProcessRunnerTrait for tasks that shell out to external commands
Conflicts
- doctrine/dbal: <4.3
- symfony/event-dispatcher: <6.4
- symfony/lock: <6.4
- symfony/process: <6.4
This package is auto-updated.
Last update: 2026-07-20 15:28:10 UTC
README
A Symfony bundle for running one-time deploy tasks — data migrations, cache warmups, seed scripts — via CLI. Each task is tracked so it executes exactly once across deployments.
Status: pre-1.0. Public API and configuration may change without a major-version bump until
v1.0.0. Breaking changes bump the minor version and are documented inUPGRADE.md.
Requirements
- PHP >= 8.2 (>= 8.4 for Symfony 8)
- Symfony 6.4 LTS, 7.x or 8.x
Installation
composer require soviann/deploy-tasks-bundle
With Symfony Flex, the bundle is registered automatically. Without Flex, register it manually in config/bundles.php:
return [ // ... Soviann\DeployTasksBundle\SoviannDeployTasksBundle::class => ['all' => true], ];
Flex recipe
The bundle's Flex recipe lives in symfony/recipes-contrib. When Contrib recipes are enabled, composer require soviann/deploy-tasks-bundle registers the bundle, publishes config/packages/soviann_deploy_tasks.yaml, installs the host runner (bin/deploy-tasks-host.sh), and adds the host-task .gitignore entries automatically. Flex asks once per project before running a Contrib recipe — answer yes, or enable them permanently:
composer config extra.symfony.allow-contrib true
The recipe is optional — without it, the bundle works with its default configuration, and deploytasks:host:install scaffolds the host runner on demand.
Alternative: dedicated recipe endpoint
Prefer not to enable Contrib recipes globally? The same recipe is also served from a dedicated endpoint:
composer config extra.symfony.endpoint --json '["https://api.github.com/repos/Soviann/flex-recipes/contents/index.json", "flex://defaults"]'
Quick Start
Creating a task
use Soviann\DeployTasksBundle\Attribute\AsDeployTask; use Soviann\DeployTasksBundle\DeployTaskInterface; use Soviann\DeployTasksBundle\TaskResult; use Symfony\Component\Console\Output\OutputInterface; #[AsDeployTask(id: 'task_20260412143000_seed_categories', priority: 10)] final class SeedCategoriesTask implements DeployTaskInterface { public function getDescription(): string { return 'Seeds the categories table with initial data.'; } public function run(OutputInterface $output): TaskResult { // Your task logic here $output->writeln('Categories seeded.'); return TaskResult::SUCCESS; } }
Running tasks
Execute all pending tasks:
bin/console deploytasks:run
Check the status of all tasks:
bin/console deploytasks:status
Configuration
# config/packages/soviann_deploy_tasks.yaml soviann_deploy_tasks: slow_task_threshold: 300 # seconds; warn when a task runs longer (nothing is killed) storage: type: filesystem # filesystem | database | custom filesystem: path: '%kernel.project_dir%/var/deploy-tasks' lock: enabled: true
Full reference: docs/storage.md and docs/installation.md.
Storage Backends
Filesystem (default): stores execution records as files in var/deploy-tasks/. No additional dependencies required.
Database: stores execution records in a database table. Requires doctrine/dbal.
Custom: plug in any TaskStorageInterface implementation via storage.type: custom. See docs/storage.md.
Task Groups
Tasks can be assigned to one or more groups (e.g. predeploy, postdeploy) to split a deploy into named stages. Without --group, every command operates on every slot — the default (ungrouped) slot and every declared group; --group=<name> (repeatable) narrows to the tasks declaring the listed group(s), and a multi-group task records one row per matching slot.
#[AsDeployTask(id: 'task_...', groups: 'predeploy')] #[AsDeployTask(id: 'task_...', groups: ['predeploy', 'postdeploy'])]
See docs/creating-tasks.md and docs/commands.md for details.
Host-scope tasks
Host tasks run outside the Symfony container — useful for operations that must execute on the host (Docker restarts, SSH-driven commands, infrastructure prep). The host runner (bin/deploy-tasks-host.sh) is installed automatically by the Flex recipe; without it, one command scaffolds everything:
bin/console deploytasks:host:install
This installs the runner script (executable), creates the configured host-task directory (default deploy/host-tasks/, with a .gitkeep), and adds a Flex-style .gitignore block for the runner's log, lock, and local-override files — each step idempotent. Re-run with --force to refresh the runner after a bundle update. See docs/host-tasks.md for generation, execution, .env cascade, and concurrency details.
Commands
| Command | Description | Options |
|---|---|---|
deploytasks:run |
Execute pending tasks | --dry-run, --rerun-all, --id=<id>, --group=<name> (repeatable), --require-some |
deploytasks:status |
List tasks with their execution state | --no-state, --group=<name> (repeatable), --filter-status=<comma-list> |
deploytasks:show <id> |
Show full metadata and every stored execution record for a single task | — |
deploytasks:skip <id> |
Mark a task as skipped (interactive confirm) | --group=<name> (repeatable) |
deploytasks:reset <id> |
Clear the execution record for a task (interactive confirm) | --no-interaction, --group=<name> (repeatable), --force |
deploytasks:rollup |
Clear history and mark all tasks as executed | --no-interaction, --group=<name> (repeatable), --force |
deploytasks:generate |
Generate a blank deploy task (PHP class, runs inside the Symfony container) | --dir, --namespace |
deploytasks:create-schema |
Create the storage schema (storages implementing SchemaManageableInterface) |
--dump-sql |
deploytasks:host:install |
Install the host runner, the configured host-task directory, and the .gitignore block (idempotent) |
--force |
deploytasks:host:generate |
Generate a blank deploy task (bash script, runs on the host outside the container) | --dir |
deploytasks:host:skip <id> |
Mark a host-scope task as done in the completion log (interactive confirm) | — |
deploytasks:host:reset <id> |
Remove a host-scope task's completion-log entry | --no-interaction, --force |
deploytasks:host:rollup |
Mark every pending host-scope task as done | --no-interaction, --force |
deploytasks:host:config |
Render (or write) the host runner env config matching soviann_deploy_tasks.host.* |
--write |
Running shell commands
Tasks that shell out to external binaries can opt into the ProcessRunnerTrait, which wraps symfony/process to stream output and enforce a per-call timeout. See docs/creating-tasks.md for setup and behavior notes.
Documentation
Full index: docs/index.md.
| Topic | File |
|---|---|
| Installation, requirements, optional packages | docs/installation.md |
| Creating tasks (attributes, env/group filtering, IDs) | docs/creating-tasks.md |
| Console commands reference | docs/commands.md |
| Storage backends (filesystem, database, custom) | docs/storage.md |
Host-scope tasks (host runner, .env cascade, concurrency) |
docs/host-tasks.md |
| Lifecycle events | docs/events.md |
| Logging (PSR-3, Monolog channel) | docs/logging.md |
| Testing (unit, functional, command tester) | docs/testing.md |
| Security model, host runner hardening | docs/security.md |
| Advanced (custom sorter, locking, slow-task threshold, transactions) | docs/advanced.md |
| Troubleshooting / FAQ | docs/troubleshooting.md |
Project meta: CHANGELOG.md (release notes, Keep-a-Changelog format), UPGRADE.md (breaking-change migration notes), SECURITY.md (vulnerability disclosure), CONTRIBUTING.md (local dev setup and PR conventions).
Security
Failure logs from DBAL-backed storage are scrubbed of full exception objects to avoid leaking connection credentials into shared log sinks. See docs/logging.md and docs/security.md for the full trust model and hardening notes.
Contributing
See CONTRIBUTING.md for guidelines.
License
MIT. See LICENSE for details.