> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Envoy

> 介绍如何使用 Laravel Envoy 通过 Blade 语法在远程服务器上定义并执行部署任务与 Artisan 命令。

## 前言

[Laravel Envoy](https://github.com/laravel/envoy) 是一个用于在远程服务器上执行常用任务的工具。它使用与 [Blade](/zh-CN/blade) 相同的语法，可以轻松定义部署、Artisan 命令执行等任务。

<Info>
  Envoy 目前仅支持 macOS 和 Linux。若在 Windows 中使用，需要通过 [WSL2](https://docs.microsoft.com/zh-cn/windows/wsl/install-win10)。
</Info>

## 安装

使用 Composer 包管理器将 Envoy 安装到项目中。

```shell theme={null}
composer require laravel/envoy --dev
```

安装完成后，`vendor/bin` 目录下即可使用 Envoy 可执行文件。

```shell theme={null}
php vendor/bin/envoy
```

## 任务的创建

### 任务的定义

任务是 Envoy 的基本构成要素。任务用于定义在任务执行时应在远程服务器上运行的 shell 命令。例如，可以定义一个在所有队列 Worker 服务器上执行 `php artisan queue:restart` 命令的任务。

所有 Envoy 任务都定义在应用根目录下的 `Envoy.blade.php` 文件中。

```blade theme={null}
@servers(['web' => ['user@192.168.1.1'], 'workers' => ['user@192.168.1.2']])

@task('restart-queues', ['on' => 'workers'])
    cd /home/user/example.com
    php artisan queue:restart
@endtask
```

如上所示，在文件顶部定义 `@servers` 数组，然后在每个任务声明的 `on` 选项中引用这些服务器。`@servers` 声明必须写在一行内。`@task` 声明中写入的是在任务执行时于服务器上运行的 shell 命令。

#### 本地任务

将服务器的 IP 地址指定为 `127.0.0.1`，可以强制在本地计算机上运行脚本。

```blade theme={null}
@servers(['localhost' => '127.0.0.1'])
```

#### Envoy 任务的导入

使用 `@import` 指令可以导入其他 Envoy 文件，将其 story 或 task 加入到自己的文件中。导入后，可以像在自己的 Envoy 文件中定义一样执行这些任务。

```blade theme={null}
@import('vendor/package/Envoy.blade.php')
```

### 多台服务器

Envoy 可以轻松地在多台服务器上执行同一个任务。首先在 `@servers` 声明中追加服务器，并为每台服务器分配一个唯一名称。添加完毕后，在任务的 `on` 数组中列出各服务器。

```blade theme={null}
@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
```

#### 并行执行

默认情况下，任务在各服务器上是串行执行的。也就是说，任务在第 1 台服务器完成后，才会开始在第 2 台服务器执行。如果希望在多台服务器上并行执行，可以在任务声明中添加 `parallel` 选项。

```blade theme={null}
@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
```

### 初始化设置

如果在执行 Envoy 任务之前需要执行任意 PHP 代码，可以使用 `@setup` 指令。

```php theme={null}
@setup
    $now = new DateTime;
@endsetup
```

如果需要在任务执行之前加载其他 PHP 文件，可在 `Envoy.blade.php` 文件顶部使用 `@include` 指令。

```blade theme={null}
@include('vendor/autoload.php')

@task('restart-queues')
    # ...
@endtask
```

### 变量

调用 Envoy 任务时，可以在命令行中指定参数传递给任务。

```shell theme={null}
php vendor/bin/envoy run deploy --branch=master
```

在任务内部可以通过 Blade 的"echo"语法访问选项，也可以使用 Blade 的 `if` 语句和循环。例如，若希望在执行 `git pull` 命令前确认 `$branch` 变量存在，可以这样写。

```blade theme={null}
@servers(['web' => ['user@192.168.1.1']])

@task('deploy', ['on' => 'web'])
    cd /home/user/example.com

    @if ($branch)
        git pull origin {{ $branch }}
    @endif

    php artisan migrate --force
@endtask
```

### 故事（Story）

Story 用一个方便的名字将一系列任务分组。例如，可以在 `deploy` story 中一起执行 `update-code` 和 `install-dependencies` 任务。

```blade theme={null}
@servers(['web' => ['user@192.168.1.1']])

@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
```

编写完 story 后，可以像调用任务一样调用它。

```shell theme={null}
php vendor/bin/envoy run deploy
```

### 完成钩子

在任务和 story 执行时会触发多个钩子。Envoy 支持的钩子类型有 `@before`、`@after`、`@error`、`@success`、`@finished`。这些钩子内的代码都会作为 PHP 解释，并**在本地**执行，而不是在任务操作的远程服务器上。

每种钩子可以定义任意多个，会按其在 Envoy 脚本中书写的顺序执行。

```blade theme={null}
@before
    if ($task === 'deploy') {
        // ...
    }
@endbefore

@after
    if ($task === 'deploy') {
        // ...
    }
@endafter

@error
    if ($task === 'deploy') {
        // ...
    }
@enderror

@success
    // ...
@endsuccess

@finished
    if ($exitCode > 0) {
        // 某个任务发生了错误...
    }
@endfinished
```

`@finished` 钩子会接收已执行完的任务的状态码。状态码为 `null` 或大于等于 `0` 的整数。

## 执行任务

要执行应用 `Envoy.blade.php` 文件中定义的任务或 story，可运行 Envoy 的 `run` 命令并传入要执行的任务或 story 名称。Envoy 会执行任务，并在过程中显示来自远程服务器的输出。

```shell theme={null}
php vendor/bin/envoy run deploy
```

### 任务执行的确认

如果希望在服务器上执行特定任务前要求确认，可在任务声明中添加 `confirm` 指令。此功能在执行破坏性操作时尤其有用。

```blade theme={null}
@task('deploy', ['on' => 'web', 'confirm' => true])
    cd /home/user/example.com
    git pull origin {{ $branch }}
    php artisan migrate
@endtask
```

## 通知

### Slack

Envoy 可以在每个任务执行后向 [Slack](https://slack.com) 发送通知。`@slack` 指令接收 Slack 的 Webhook URL 与频道名（或用户名）。Webhook URL 可以通过在 Slack 控制面板中创建"Incoming WebHooks"集成来获取。

`@slack` 指令的第 1 个参数为整个 Webhook URL。第 2 个参数为频道名（`#channel`）或用户名（`@user`）。

```blade theme={null}
@finished
    @slack('webhook-url', '#bots')
@endfinished
```

默认情况下会向通知频道发送描述所执行任务的消息。通过向 `@slack` 指令传入第 3 个参数，可以自定义消息。

```blade theme={null}
@finished
    @slack('webhook-url', '#bots', 'Hello, Slack.')
@endfinished
```

### Discord

Envoy 也支持在每个任务执行后向 [Discord](https://discord.com) 发送通知。`@discord` 指令接收 Discord 的 Webhook URL 与消息。Webhook URL 可以在服务器设置中创建"Webhook"并选择发送目标频道获得。

```blade theme={null}
@finished
    @discord('discord-webhook-url')
@endfinished
```

### Telegram

Envoy 也支持在每个任务执行后向 [Telegram](https://telegram.org) 发送通知。`@telegram` 指令接收 Telegram Bot ID 与 Chat ID。Bot ID 可以通过在 [BotFather](https://t.me/botfather) 创建新 bot 得到。Chat ID 可以使用 [@username\_to\_id\_bot](https://t.me/username_to_id_bot) 获取。

```blade theme={null}
@finished
    @telegram('bot-id','chat-id')
@endfinished
```

### Microsoft Teams

Envoy 也支持在每个任务执行后向 [Microsoft Teams](https://www.microsoft.com/microsoft-teams) 发送通知。`@teams` 指令接收 Teams 的 webhook（必需）、消息、主题颜色（success, info, warning, error）以及可选的配置数组。Teams 的 webhook 可通过创建 [Incoming Webhook](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook) 获得。Teams API 还有许多其他配置项，可以自由创建自定义消息卡片。详情请参阅 [Microsoft Teams 的文档](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using)。

```blade theme={null}
@finished
    @teams('webhook-url')
@endfinished
```

<Warning>
  Envoy 前提是通过 [SSH](https://zh.wikipedia.org/wiki/Secure_Shell) 连接到远程服务器。根据运行环境，可能需要事先完成密钥认证配置及对服务器的访问控制。若需要更高级的部署自动化，也可以考虑与[部署](/zh-CN/deployment)指南或 [GitHub Actions](/zh-CN/advanced/github-actions-pinning) 结合使用。
</Warning>
