spatie/scotty
Scotty is a beautiful SSH task runner for executing scripted tasks on remote servers. Define tasks in a Scotty.sh file (bash with annotations), run them with clear output, and use it as a drop-in, Envoy-compatible alternative for deploys and ops.
Installation:
composer require spatie/scotty
Publish the config (optional):
php artisan vendor:publish --provider="Spatie\Scotty\ScottyServiceProvider"
First Task File:
Create Scotty.sh in your project root with a basic task:
#!/usr/bin/env scotty
# @servers remote=deployer@your-server.com
# @task on:remote
hello() {
echo "Hello from remote server!"
}
Run It:
scotty run hello
git pull, composer install, and artisan migrate sequentially.Task Definition:
# @task on:remote for server-side execution.# @task on:local for local-only tasks (e.g., composer install).# @macro for reusable workflows:
# @macro deploy pullCode runMigrations
Server Management:
scotty.php config or inline:
# @servers remote=deployer@server1.com,backup=deployer@server2.com
# @servers remote=deployer@${SERVER_HOST}
Laravel Integration:
Scotty::run('deploy'); // Runs the 'deploy' macro
Artisan::call():
Artisan::call('scotty:run', ['task' => 'deploy']);
Parallel Execution:
# @servers remote=deployer@server1.com,deployer@server2.com
# @task on:remote
syncData() { ... }
Execute with:
scotty run --parallel syncData
Conditional Tasks:
Use if statements in tasks with SSH output checks:
# @task on:remote
backupDb() {
if [ -f "/backup/db.sql" ]; then
echo "Backup exists. Skipping."
else
mysqldump -u user -p db_name > /backup/db.sql
fi
}
File Transfers:
Use scp-like logic via scotty:
# @task on:local
uploadFile() {
scp local-file.txt deployer@server:/remote/path/
}
Environment-Specific Tasks:
Use .env variables to switch between staging/production:
# @servers remote=deployer@${APP_SERVER}
SSH Key Issues:
~/.ssh/id_rsa is properly set up or specify keys in scotty.php:
'ssh' => [
'key' => '/path/to/private_key',
],
scotty run --verbose.Task Ordering:
# @macro deploy pullCode installDeps migrate
Avoid relying on implicit ordering.Output Parsing:
grep in tasks).Local vs. Remote Confusion:
# @task on:local runs on your machine; on:remote runs on the server. Mixing them requires explicit file transfers.Verbose Mode:
scotty run --verbose deploy
Shows raw SSH commands and output.
Dry Runs:
Use --dry-run to preview commands without execution.
Logging:
Enable Laravel logging for Scotty events in config/scotty.php:
'log' => true,
Custom SSH Config: Override SSH options per server:
# @servers remote=deployer@server.com --port=2222 --timeout=30
Pre/Post Hooks: Use local tasks to wrap remote execution:
# @task on:local
preDeploy() {
echo "Starting deployment..."
}
# @task on:remote
deploy() { ... }
# @task on:local
postDeploy() {
echo "Deployment complete!";
}
Dynamic Servers: Fetch server lists from Laravel models or APIs:
# @servers remote=$(php artisan server:list)
Parallelism Limits:
Configure max parallel tasks in scotty.php:
'parallel' => [
'max_processes' => 4,
],
Template Tasks:
Store reusable tasks in separate files and source them:
#!/usr/bin/env scotty
source ./tasks/deploy.sh
source ./tasks/backup.sh
Git Hooks:
Integrate Scotty into post-receive hooks for zero-downtime deployments:
#!/bin/bash
cd /var/www/app && ./vendor/bin/scotty run deploy
CI/CD: Use Scotty in GitHub Actions/GitLab CI for remote deployments:
- name: Deploy
run: ./vendor/bin/scotty run deploy
How can I help you explore Laravel packages today?