> ## 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

> 說明如何以 Blade 語法運用 Laravel Envoy 定義並在遠端伺服器上執行部署任務或 Artisan 指令。

## 簡介

[Laravel Envoy](https://github.com/laravel/envoy) 是一個在遠端伺服器執行常見任務的工具。你可以使用與 [Blade](/zh-TW/blade) 相同的語法，簡潔地定義部署或執行 Artisan 指令等任務。

<Info>
  Envoy 目前僅支援 macOS 與 Linux。若要在 Windows 使用，需透過 [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。
</Info>

## 安裝

使用 Composer 套件管理員將 Envoy 安裝到專案中：

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

安裝完成後，Envoy 的執行檔會出現在 `vendor/bin` 目錄。

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

## 建立任務

### 定義任務

Task 是 Envoy 的基本組成單位。Task 定義了執行時要在遠端伺服器上執行的 shell 指令。例如，可以定義在所有佇列 worker 伺服器上執行 `php artisan queue:restart` 的任務。

所有 Envoy task 都定義在應用程式根目錄下的 `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` 陣列，並在各 task 宣告的 `on` 選項中引用這些伺服器。`@servers` 宣告必須寫在單一行。`@task` 宣告內是 task 執行時要在伺服器上執行的 shell 指令。

#### 本機任務

將伺服器 IP 指定為 `127.0.0.1`，就可以強制在本機執行腳本。

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

#### 引入 Envoy 任務

使用 `@import` 指令可以引入其他 Envoy 檔案，將其中的故事（story）或任務（task）加入自己的檔案中。引入後，就能像自己定義的一樣執行這些任務。

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

#### 並行執行

預設情況下，任務會在各伺服器上依序執行。也就是說，會在第一台伺服器完成後，才在下一台執行。若想在多台伺服器上並行執行任務，可在任務宣告中加上 `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
```

### 設定（Setup）

在執行 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
```

### 故事（Stories）

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 後，其呼叫方式與 task 相同。

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

### 完成時的 Hook

執行 task 或 story 時會觸發多個 hook。Envoy 支援的 hook 種類有 `@before`、`@after`、`@error`、`@success`、`@finished`。這些 hook 中的程式碼皆會被解讀為 PHP，並在 **本機** 執行，而非在遠端伺服器。

每種 hook 都可以定義任意多個，並依照 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` hook 會收到已執行任務的狀態碼。狀態碼為 `null` 或 `0` 以上的整數。

## 執行任務

要執行 `Envoy.blade.php` 中定義的 task 或 story，請執行 Envoy 的 `run` 指令並傳入要執行的名稱。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
```

預設會在通知頻道發送描述已執行任務的訊息。傳入第 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。可透過 [BotFather](https://t.me/botfather) 建立新機器人取得 Bot ID；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://en.wikipedia.org/wiki/Secure_Shell) 連線至遠端伺服器。依照執行環境不同，可能需要預先設定金鑰認證與伺服器存取控制。若需要更進階的部署自動化，也可以參考[部署](/zh-TW/deployment)指南或與 [GitHub Actions](/zh-TW/advanced/github-actions-pinning) 結合使用。
</Warning>
