﻿# 如何有條件的控制 Azure Pipelines 的執行流程

由於我在 Azure Pipelines 設定的 CI 有整合 [Telegram Notification](https://marketplace.visualstudio.com/items?itemName=EvgenyChernyi.telegram-notification-extension)，但我希望依據前一個建置步驟 (Task) 的執行狀態，動態決定要不要執行這個 Telegram 訊息推播步驟，嘗試了好些時間，終於可以理解正確設定的方法。

### 早期錯誤的設定

早期我是從 StackOverflow 查到[一則解答](https://stackoverflow.com/a/55891479/910074)，原本的想法很簡單，就是直接設定 Azure Pipelines [預先定義好的 Agent 變數](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#agent-variables) `agent.jobstatus`，將其值設定為 `canceled`，試圖中斷 Agent 的執行，讓 Agent 不再繼續執行接下來的 Tasks。

```bash
echo "##vso[task.setvariable variable=agent.jobstatus;]canceled"
echo "##vso[task.complete result=Canceled;]DONE"
```

這個方法雖然還有效果，但是在 Azure DevOps Services 上面，執行 Pipelines 的過程中已經開始看到明顯的錯誤訊息，日後某天肯定會發生錯誤，必須趁早改掉。

```bash
##[warning]Overwriting readonly task variable 'agent.jobstatus'. This behavior will be disabled in the future. See https://github.com/microsoft/azure-pipelines-yaml/blob/master/design/readonly-variables.md for details.
```

![](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/5a7b08cdab80577e628e-77219450-dc044d00-6b70-11ea-98b9-d264128c2af9.png)

> 因為 `agent.jobstatus` 屬於 [Read-only variables](https://github.com/microsoft/azure-pipelines-yaml/blob/master/design/readonly-variables.md) (唯讀變數)，不能在 Task 執行的過程中被修改。

### 正確的設定步驟

1.  先理解 [如何從 Azure Pipelines 的 Task 設定一個變數給下一個 Task 使用](/post/2020/02/08/Set-variables-in-scripts-in-Azure-Pipelines)
    
2.  想辦法在主要的建置步驟動態設定一個變數，該變數可以讓下一個 Task 判斷是否需要執行
    
    ```bash
    echo "##vso[task.setvariable variable=NGCLIVersions]canceled"
    echo "##vso[task.complete result=Canceled;]DONE"
    ```
    
    > 這裡的 `echo "##vso[task.complete result=Canceled;]DONE"` 主要用來設定目前工作的狀態是否要標示為 `Canceled` 狀態。即便 `Canceled` 狀態出現，由於並非 `Failed` 失敗狀態，所以接下來的 Tasks 還是會正常執行，因此還需要將接下來的每個 Tasks 設定 [Conditions](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/conditions?view=azure-devops&tabs=classic) 自訂執行條件，才能讓需要跳過的 Task 產生 `Skipped` 狀態。
    
3.  設定後面要接續執行的 Tasks，展開 **Control Options**，將 **Run this task** 下拉選單調整為 **Custom conditions**，然後設定 **Custom condition** 自訂條件。
    
    ```bash
    and(succeeded(), ne(variables['NGCLIVersions'], 'canceled'))
    ```
    
    ![2020-03-21\_15-14-51](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/034d5ac711c7d9c01703-77221686-d580d000-6b86-11ea-943e-87563959ff36.jpg)
    
    > 注意：如果你想取消後面所有 Tasks 執行，每個 Tasks 都需要做一樣的設定！
    

以下是 Pipelines 執行完後的結果畫面：

![2020-03-21\_15-36-45](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/15e174b081086e7df99b-77221968-d5360400-6b89-11ea-9cde-8ce5e56db54a.jpg)

### 相關連結

-   Azure Pipelines | Microsoft Docs
    -   [Conditions](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/conditions?view=azure-devops&tabs=classic)
    -   [Expressions](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops)
    -   [Logging commands](https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash)
-   [azure-pipelines-yaml/readonly-variables.md at master · microsoft/azure-pipelines-yaml](https://github.com/microsoft/azure-pipelines-yaml/blob/master/design/readonly-variables.md)
