627 lines
15 KiB
Markdown
627 lines
15 KiB
Markdown
# Laravel Envoy
|
||
|
||
* Introduction
|
||
* Installation
|
||
* Writing Tasks
|
||
* Defining Tasks
|
||
* Multiple Servers
|
||
* Setup
|
||
* Variables
|
||
* Stories
|
||
* Hooks
|
||
* Running Tasks
|
||
* Confirming Task Execution
|
||
* Notifications
|
||
* Slack
|
||
* Discord
|
||
* Telegram
|
||
* Microsoft Teams
|
||
|
||
## Introduction
|
||
|
||
[Laravel Envoy](https://github.com/laravel/envoy) is a tool for executing
|
||
common tasks you run on your remote servers. Using [Blade](/docs/12.x/blade)
|
||
style syntax, you can easily setup tasks for deployment, Artisan commands, and
|
||
more. Currently, Envoy only supports the Mac and Linux operating systems.
|
||
However, Windows support is achievable using
|
||
[WSL2](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
|
||
|
||
## Installation
|
||
|
||
First, install Envoy into your project using the Composer package manager:
|
||
|
||
|
||
|
||
1composer require laravel/envoy --dev
|
||
|
||
|
||
composer require laravel/envoy --dev
|
||
|
||
Once Envoy has been installed, the Envoy binary will be available in your
|
||
application's `vendor/bin` directory:
|
||
|
||
|
||
|
||
1php vendor/bin/envoy
|
||
|
||
|
||
php vendor/bin/envoy
|
||
|
||
## Writing Tasks
|
||
|
||
### Defining Tasks
|
||
|
||
Tasks are the basic building block of Envoy. Tasks define the shell commands
|
||
that should execute on your remote servers when the task is invoked. For
|
||
example, you might define a task that executes the `php artisan queue:restart`
|
||
command on all of your application's queue worker servers.
|
||
|
||
All of your Envoy tasks should be defined in an `Envoy.blade.php` file at the
|
||
root of your application. Here's an example to get you started:
|
||
|
||
|
||
|
||
1@servers(['web' => ['[[email protected]](/cdn-cgi/l/email-protection)'], 'workers' => ['[[email protected]](/cdn-cgi/l/email-protection)']])
|
||
|
||
2
|
||
|
||
3@task('restart-queues', ['on' => 'workers'])
|
||
|
||
4 cd /home/user/example.com
|
||
|
||
5 php artisan queue:restart
|
||
|
||
6@endtask
|
||
|
||
|
||
@servers(['web' => ['[[email protected]](/cdn-cgi/l/email-protection)'], 'workers' => ['[[email protected]](/cdn-cgi/l/email-protection)']])
|
||
|
||
@task('restart-queues', ['on' => 'workers'])
|
||
cd /home/user/example.com
|
||
php artisan queue:restart
|
||
@endtask
|
||
|
||
As you can see, an array of `@servers` is defined at the top of the file,
|
||
allowing you to reference these servers via the `on` option of your task
|
||
declarations. The `@servers` declaration should always be placed on a single
|
||
line. Within your `@task` declarations, you should place the shell commands
|
||
that should execute on your servers when the task is invoked.
|
||
|
||
#### Local Tasks
|
||
|
||
You can force a script to run on your local computer by specifying the
|
||
server's IP address as `127.0.0.1`:
|
||
|
||
|
||
|
||
1@servers(['localhost' => '127.0.0.1'])
|
||
|
||
|
||
@servers(['localhost' => '127.0.0.1'])
|
||
|
||
#### Importing Envoy Tasks
|
||
|
||
Using the `@import` directive, you may import other Envoy files so their
|
||
stories and tasks are added to yours. After the files have been imported, you
|
||
may execute the tasks they contain as if they were defined in your own Envoy
|
||
file:
|
||
|
||
|
||
|
||
1@import('vendor/package/Envoy.blade.php')
|
||
|
||
|
||
@import('vendor/package/Envoy.blade.php')
|
||
|
||
### Multiple Servers
|
||
|
||
Envoy allows you to easily run a task across multiple servers. First, add
|
||
additional servers to your `@servers` declaration. Each server should be
|
||
assigned a unique name. Once you have defined your additional servers you may
|
||
list each of the servers in the task's `on` array:
|
||
|
||
|
||
|
||
1@servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])
|
||
|
||
2
|
||
|
||
3@task('deploy', ['on' => ['web-1', 'web-2']])
|
||
|
||
4 cd /home/user/example.com
|
||
|
||
5 git pull origin {{ $branch }}
|
||
|
||
6 php artisan migrate --force
|
||
|
||
7@endtask
|
||
|
||
|
||
@servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])
|
||
|
||
@task('deploy', ['on' => ['web-1', 'web-2']])
|
||
cd /home/user/example.com
|
||
git pull origin {{ $branch }}
|
||
php artisan migrate --force
|
||
@endtask
|
||
|
||
#### Parallel Execution
|
||
|
||
By default, tasks will be executed on each server serially. In other words, a
|
||
task will finish running on the first server before proceeding to execute on
|
||
the second server. If you would like to run a task across multiple servers in
|
||
parallel, add the `parallel` option to your task declaration:
|
||
|
||
|
||
|
||
1@servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])
|
||
|
||
2
|
||
|
||
3@task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true])
|
||
|
||
4 cd /home/user/example.com
|
||
|
||
5 git pull origin {{ $branch }}
|
||
|
||
6 php artisan migrate --force
|
||
|
||
7@endtask
|
||
|
||
|
||
@servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])
|
||
|
||
@task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true])
|
||
cd /home/user/example.com
|
||
git pull origin {{ $branch }}
|
||
php artisan migrate --force
|
||
@endtask
|
||
|
||
### Setup
|
||
|
||
Sometimes, you may need to execute arbitrary PHP code before running your
|
||
Envoy tasks. You may use the `@setup` directive to define a block of PHP code
|
||
that should execute before your tasks:
|
||
|
||
|
||
|
||
1@setup
|
||
|
||
2 $now = new DateTime;
|
||
|
||
3@endsetup
|
||
|
||
|
||
@setup
|
||
$now = new DateTime;
|
||
@endsetup
|
||
|
||
If you need to require other PHP files before your task is executed, you may
|
||
use the `@include` directive at the top of your `Envoy.blade.php` file:
|
||
|
||
|
||
|
||
1@include('vendor/autoload.php')
|
||
|
||
2
|
||
|
||
3@task('restart-queues')
|
||
|
||
4 # ...
|
||
|
||
5@endtask
|
||
|
||
|
||
@include('vendor/autoload.php')
|
||
|
||
@task('restart-queues')
|
||
# ...
|
||
@endtask
|
||
|
||
### Variables
|
||
|
||
If needed, you may pass arguments to Envoy tasks by specifying them on the
|
||
command line when invoking Envoy:
|
||
|
||
|
||
|
||
1php vendor/bin/envoy run deploy --branch=master
|
||
|
||
|
||
php vendor/bin/envoy run deploy --branch=master
|
||
|
||
You may access the options within your tasks using Blade's "echo" syntax. You
|
||
may also define Blade `if` statements and loops within your tasks. For
|
||
example, let's verify the presence of the `$branch` variable before executing
|
||
the `git pull` command:
|
||
|
||
|
||
|
||
1@servers(['web' => ['[[email protected]](/cdn-cgi/l/email-protection)']])
|
||
|
||
2
|
||
|
||
3@task('deploy', ['on' => 'web'])
|
||
|
||
4 cd /home/user/example.com
|
||
|
||
5
|
||
|
||
6 @if ($branch)
|
||
|
||
7 git pull origin {{ $branch }}
|
||
|
||
8 @endif
|
||
|
||
9
|
||
|
||
10 php artisan migrate --force
|
||
|
||
11@endtask
|
||
|
||
|
||
@servers(['web' => ['[[email protected]](/cdn-cgi/l/email-protection)']])
|
||
|
||
@task('deploy', ['on' => 'web'])
|
||
cd /home/user/example.com
|
||
|
||
@if ($branch)
|
||
git pull origin {{ $branch }}
|
||
@endif
|
||
|
||
php artisan migrate --force
|
||
@endtask
|
||
|
||
### Stories
|
||
|
||
Stories group a set of tasks under a single, convenient name. For instance, a
|
||
`deploy` story may run the `update-code` and `install-dependencies` tasks by
|
||
listing the task names within its definition:
|
||
|
||
|
||
|
||
1@servers(['web' => ['[[email protected]](/cdn-cgi/l/email-protection)']])
|
||
|
||
2
|
||
|
||
3@story('deploy')
|
||
|
||
4 update-code
|
||
|
||
5 install-dependencies
|
||
|
||
6@endstory
|
||
|
||
7
|
||
|
||
8@task('update-code')
|
||
|
||
9 cd /home/user/example.com
|
||
|
||
10 git pull origin master
|
||
|
||
11@endtask
|
||
|
||
12
|
||
|
||
13@task('install-dependencies')
|
||
|
||
14 cd /home/user/example.com
|
||
|
||
15 composer install
|
||
|
||
16@endtask
|
||
|
||
|
||
@servers(['web' => ['[[email protected]](/cdn-cgi/l/email-protection)']])
|
||
|
||
@story('deploy')
|
||
update-code
|
||
install-dependencies
|
||
@endstory
|
||
|
||
@task('update-code')
|
||
cd /home/user/example.com
|
||
git pull origin master
|
||
@endtask
|
||
|
||
@task('install-dependencies')
|
||
cd /home/user/example.com
|
||
composer install
|
||
@endtask
|
||
|
||
Once the story has been written, you may invoke it in the same way you would
|
||
invoke a task:
|
||
|
||
|
||
|
||
1php vendor/bin/envoy run deploy
|
||
|
||
|
||
php vendor/bin/envoy run deploy
|
||
|
||
### Hooks
|
||
|
||
When tasks and stories run, a number of hooks are executed. The hook types
|
||
supported by Envoy are `@before`, `@after`, `@error`, `@success`, and
|
||
`@finished`. All of the code in these hooks is interpreted as PHP and executed
|
||
locally, not on the remote servers that your tasks interact with.
|
||
|
||
You may define as many of each of these hooks as you like. They will be
|
||
executed in the order that they appear in your Envoy script.
|
||
|
||
#### `@before`
|
||
|
||
Before each task execution, all of the `@before` hooks registered in your
|
||
Envoy script will execute. The `@before` hooks receive the name of the task
|
||
that will be executed:
|
||
|
||
|
||
|
||
1@before
|
||
|
||
2 if ($task === 'deploy') {
|
||
|
||
3 // ...
|
||
|
||
4 }
|
||
|
||
5@endbefore
|
||
|
||
|
||
@before
|
||
if ($task === 'deploy') {
|
||
// ...
|
||
}
|
||
@endbefore
|
||
|
||
#### `@after`
|
||
|
||
After each task execution, all of the `@after` hooks registered in your Envoy
|
||
script will execute. The `@after` hooks receive the name of the task that was
|
||
executed:
|
||
|
||
|
||
|
||
1@after
|
||
|
||
2 if ($task === 'deploy') {
|
||
|
||
3 // ...
|
||
|
||
4 }
|
||
|
||
5@endafter
|
||
|
||
|
||
@after
|
||
if ($task === 'deploy') {
|
||
// ...
|
||
}
|
||
@endafter
|
||
|
||
#### `@error`
|
||
|
||
After every task failure (exits with a status code greater than `0`), all of
|
||
the `@error` hooks registered in your Envoy script will execute. The `@error`
|
||
hooks receive the name of the task that was executed:
|
||
|
||
|
||
|
||
1@error
|
||
|
||
2 if ($task === 'deploy') {
|
||
|
||
3 // ...
|
||
|
||
4 }
|
||
|
||
5@enderror
|
||
|
||
|
||
@error
|
||
if ($task === 'deploy') {
|
||
// ...
|
||
}
|
||
@enderror
|
||
|
||
#### `@success`
|
||
|
||
If all tasks have executed without errors, all of the `@success` hooks
|
||
registered in your Envoy script will execute:
|
||
|
||
|
||
|
||
1@success
|
||
|
||
2 // ...
|
||
|
||
3@endsuccess
|
||
|
||
|
||
@success
|
||
// ...
|
||
@endsuccess
|
||
|
||
#### `@finished`
|
||
|
||
After all tasks have been executed (regardless of exit status), all of the
|
||
`@finished` hooks will be executed. The `@finished` hooks receive the status
|
||
code of the completed task, which may be `null` or an `integer` greater than
|
||
or equal to `0`:
|
||
|
||
|
||
|
||
1@finished
|
||
|
||
2 if ($exitCode > 0) {
|
||
|
||
3 // There were errors in one of the tasks...
|
||
|
||
4 }
|
||
|
||
5@endfinished
|
||
|
||
|
||
@finished
|
||
if ($exitCode > 0) {
|
||
// There were errors in one of the tasks...
|
||
}
|
||
@endfinished
|
||
|
||
## Running Tasks
|
||
|
||
To run a task or story that is defined in your application's `Envoy.blade.php`
|
||
file, execute Envoy's `run` command, passing the name of the task or story you
|
||
would like to execute. Envoy will execute the task and display the output from
|
||
your remote servers as the task is running:
|
||
|
||
|
||
|
||
1php vendor/bin/envoy run deploy
|
||
|
||
|
||
php vendor/bin/envoy run deploy
|
||
|
||
### Confirming Task Execution
|
||
|
||
If you would like to be prompted for confirmation before running a given task
|
||
on your servers, you should add the `confirm` directive to your task
|
||
declaration. This option is particularly useful for destructive operations:
|
||
|
||
|
||
|
||
1@task('deploy', ['on' => 'web', 'confirm' => true])
|
||
|
||
2 cd /home/user/example.com
|
||
|
||
3 git pull origin {{ $branch }}
|
||
|
||
4 php artisan migrate
|
||
|
||
5@endtask
|
||
|
||
|
||
@task('deploy', ['on' => 'web', 'confirm' => true])
|
||
cd /home/user/example.com
|
||
git pull origin {{ $branch }}
|
||
php artisan migrate
|
||
@endtask
|
||
|
||
## Notifications
|
||
|
||
### Slack
|
||
|
||
Envoy supports sending notifications to [Slack](https://slack.com) after each
|
||
task is executed. The `@slack` directive accepts a Slack hook URL and a
|
||
channel / user name. You may retrieve your webhook URL by creating an
|
||
"Incoming WebHooks" integration in your Slack control panel.
|
||
|
||
You should pass the entire webhook URL as the first argument given to the
|
||
`@slack` directive. The second argument given to the `@slack` directive should
|
||
be a channel name (`#channel`) or a user name (`@user`):
|
||
|
||
|
||
|
||
1@finished
|
||
|
||
2 @slack('webhook-url', '#bots')
|
||
|
||
3@endfinished
|
||
|
||
|
||
@finished
|
||
@slack('webhook-url', '#bots')
|
||
@endfinished
|
||
|
||
By default, Envoy notifications will send a message to the notification
|
||
channel describing the task that was executed. However, you may overwrite this
|
||
message with your own custom message by passing a third argument to the
|
||
`@slack` directive:
|
||
|
||
|
||
|
||
1@finished
|
||
|
||
2 @slack('webhook-url', '#bots', 'Hello, Slack.')
|
||
|
||
3@endfinished
|
||
|
||
|
||
@finished
|
||
@slack('webhook-url', '#bots', 'Hello, Slack.')
|
||
@endfinished
|
||
|
||
### Discord
|
||
|
||
Envoy also supports sending notifications to [Discord](https://discord.com)
|
||
after each task is executed. The `@discord` directive accepts a Discord hook
|
||
URL and a message. You may retrieve your webhook URL by creating a "Webhook"
|
||
in your Server Settings and choosing which channel the webhook should post to.
|
||
You should pass the entire Webhook URL into the `@discord` directive:
|
||
|
||
|
||
|
||
1@finished
|
||
|
||
2 @discord('discord-webhook-url')
|
||
|
||
3@endfinished
|
||
|
||
|
||
@finished
|
||
@discord('discord-webhook-url')
|
||
@endfinished
|
||
|
||
### Telegram
|
||
|
||
Envoy also supports sending notifications to [Telegram](https://telegram.org)
|
||
after each task is executed. The `@telegram` directive accepts a Telegram Bot
|
||
ID and a Chat ID. You may retrieve your Bot ID by creating a new bot using
|
||
[BotFather](https://t.me/botfather). You can retrieve a valid Chat ID using
|
||
[@username_to_id_bot](https://t.me/username_to_id_bot). You should pass the
|
||
entire Bot ID and Chat ID into the `@telegram` directive:
|
||
|
||
|
||
|
||
1@finished
|
||
|
||
2 @telegram('bot-id','chat-id')
|
||
|
||
3@endfinished
|
||
|
||
|
||
@finished
|
||
@telegram('bot-id','chat-id')
|
||
@endfinished
|
||
|
||
### Microsoft Teams
|
||
|
||
Envoy also supports sending notifications to [Microsoft
|
||
Teams](https://www.microsoft.com/en-us/microsoft-teams) after each task is
|
||
executed. The `@microsoftTeams` directive accepts a Teams Webhook (required),
|
||
a message, theme color (success, info, warning, error), and an array of
|
||
options. You may retrieve your Teams Webhook by creating a new [incoming
|
||
webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-
|
||
and-connectors/how-to/add-incoming-webhook). The Teams API has many other
|
||
attributes to customize your message box like title, summary, and sections.
|
||
You can find more information on the [Microsoft Teams
|
||
documentation](https://docs.microsoft.com/en-
|
||
us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-
|
||
using?tabs=cURL#example-of-connector-message). You should pass the entire
|
||
Webhook URL into the `@microsoftTeams` directive:
|
||
|
||
|
||
|
||
1@finished
|
||
|
||
2 @microsoftTeams('webhook-url')
|
||
|
||
3@endfinished
|
||
|
||
|
||
@finished
|
||
@microsoftTeams('webhook-url')
|
||
@endfinished
|
||
|