# 从Azure Pipelines迁移到GitHub Actions

GitHub Actions和Azure Pipelines共享多个配置相似之处，这使得迁移到GitHub Actions相对简单。

## 简介

Azure Pipelines和GitHub Actions两者都可以创建可自动生成、测试、发布、发布和部署代码的工作流。 在工作流配置方面，Azure Pipelines 与 GitHub Actions 有一些相似之处：

* 工作流程配置文件以 YAML 编写并存储在代码仓库中。
* 工作流程包括一项或多项作业。
* 作业包括一个或多个步骤或单个命令。
* 步骤或任务可以重复使用并与社区共享。

有关详细信息，请参阅“[了解GitHub Actions](/zh/actions/get-started/understand-github-actions)”。

## 主要差异

从Azure Pipelines迁移时，请考虑以下差异：

* Azure Pipelines支持旧的 *classic editor*，这使你可以在 GUI 编辑器中定义 CI 配置，而不是在 YAML 文件中创建管道定义。
  GitHub Actions 使用 YAML 文件定义工作流，不支持图形编辑器。
* Azure Pipelines允许在作业定义中省略某些结构。 例如，如果您只有一个作业，则无需定义作业，只需要定义其步骤。
  GitHub Actions 需要显式配置，并且无法省略 YAML 结构。
* Azure Pipelines支持 YAML 文件中定义的 *stages*，可用于创建部署工作流。
  GitHub Actions 要求将阶段分成单独的 YAML 工作流文件。
* 可以根据功能选择本地安装的 Azure Pipelines 构建代理。               通过标签可以选择 GitHub Actions 自托管的运行器。

## 迁移任务和步骤

Azure Pipelines 中的作业和步骤与 GitHub Actions 中的作业和步骤非常相似。 在这两个系统中，作业具有以下特征：

* 作业包含一系列按顺序运行的步骤。
* 作业在单独的虚拟机或单独的容器中运行。
* 默认情况下作业并行运行，但可以配置为按顺序运行。

## 迁移脚本步骤

可以将脚本或 shell 命令作为工作流程中的步骤运行。 在Azure Pipelines中，可以使用 `script` 键或 `bash`、`powershell` 或 `pwsh` 键指定脚本步骤。 也可以将脚本指定为 [Bash 任务](https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/bash?view=azure-devops)或 [PowerShell 任务](https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell?view=azure-devops)的输入。

在中 GitHub Actions，所有脚本都使用 `run` 密钥指定。 若要选择特定的 shell，可以在提供脚本时指定 `shell` 键。 有关详细信息，请参阅“[GitHub Actions 的工作流语法](/zh/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idstepsrun)”。

下面是每个系统的语法示例：

### Azure Pipelines 的脚本步骤语法

```yaml
jobs:
  - job: scripts
    pool:
      vmImage: 'windows-latest'
    steps:
      - script: echo "This step runs in the default shell"
      - bash: echo "This step runs in bash"
      - pwsh: Write-Host "This step runs in PowerShell Core"
      - task: PowerShell@2
        inputs:
          script: Write-Host "This step runs in PowerShell"
```

### GitHub Actions 脚本步骤的语法

```yaml
jobs:
  scripts:
    runs-on: windows-latest
    steps:
      - run: echo "This step runs in the default shell"
      - run: echo "This step runs in bash"
        shell: bash
      - run: Write-Host "This step runs in PowerShell Core"
        shell: pwsh
      - run: Write-Host "This step runs in PowerShell"
        shell: powershell
```

## 脚本错误处理中的差异

在Azure Pipelines中，如果将任何输出发送到 `stderr`，脚本可以配置为出错。
GitHub Actions 不支持此配置。

GitHub Actions 尽可能将 shell 配置为“快速失败”，如果脚本中的某个命令退出并出现错误代码，它将立即停止脚本。 相比之下，Azure Pipelines要求显式配置，当发生错误时立即退出。 有关详细信息，请参阅“[GitHub Actions 的工作流语法](/zh/actions/reference/workflows-and-actions/workflow-syntax#exit-codes-and-error-action-preference)”。

## Windows上默认 shell 的差异

在 Azure Pipelines 中，Windows 平台上脚本的默认 shell 是 Command shell（*cmd.exe*）。 在GitHub ActionsWindows平台上，脚本的默认 shell 是 PowerShell。 PowerShell 在内置命令、变量扩展和流控制方面存在若干差异。

如果您运行的是简单的命令，则可以在 PowerShell 中运行命令 shell 脚本，而无需进行任何更改。 但在大多数情况下，需要使用 PowerShell 语法更新脚本，或者指示 GitHub Actions 使用 Command shell 而不是 PowerShell 运行脚本。 为此，可以将 `shell` 指定为 `cmd`。

下面是每个系统的语法示例：

### Azure Pipelines语法默认使用CMD

```yaml
jobs:
  - job: run_command
    pool:
      vmImage: 'windows-latest'
    steps:
      - script: echo "This step runs in CMD on Windows by default"
```

### GitHub Actions 用于指定 CMD 的语法

```yaml
jobs:
  run_command:
    runs-on: windows-latest
    steps:
      - run: echo "This step runs in PowerShell on Windows by default"
      - run: echo "This step runs in CMD on Windows explicitly"
        shell: cmd
```

有关详细信息，请参阅“[GitHub Actions 的工作流语法](/zh/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idstepsshell)”。

## 迁移条件和表达式语法

Azure Pipelines 和 GitHub Actions 都可以有条件地运行步骤。 在 Azure Pipelines 中，使用 `condition` 键指定条件表达式。 其中 GitHub Actions，使用 `if` 键指定条件表达式。

Azure Pipelines使用表达式中的函数有条件地执行步骤。 相比之下， GitHub Actions 使用虚写表示法。 例如，必须将 Azure Pipelines 中的 `eq` 函数替换为 `==` 中的 GitHub Actions 运算符。

下面是每个系统的语法示例：

### Azure Pipelines条件表达式的语法

```yaml
jobs:
  - job: conditional
    pool:
      vmImage: 'ubuntu-latest'
    steps:
      - script: echo "This step runs with str equals 'ABC' and num equals 123"
        condition: and(eq(variables.str, 'ABC'), eq(variables.num, 123))
```

### GitHub Actions 条件表达式的语法

```yaml
jobs:
  conditional:
    runs-on: ubuntu-latest
    steps:
      - run: echo "This step runs with str equals 'ABC' and num equals 123"
        if: ${{ env.str == 'ABC' && env.num == 123 }}
```

有关详细信息，请参阅“[对工作流和操作中的表达式求值](/zh/actions/reference/workflows-and-actions/expressions)”。

## 作业之间的依赖关系

Azure Pipelines 和 GitHub Actions 都允许你为作业设置依赖项。 在这两个系统中，默认情况下作业并行运行，但可以明确指定作业依赖项。 在Azure Pipelines中，这是使用 `dependsOn` 键完成的。 在 GitHub Actions 中，这是通过 `needs` 键完成的。

下面是每个系统的语法示例： 工作流启动第一个名为 `initial` 的作业，当该作业完成时，两个分别名为 `fanout1` 和 `fanout2` 的作业将会运行。 最后，当这些作业完成后，作业 `fanin` 将会运行。

### Azure Pipelines 的作业之间依赖关系的语法

```yaml
jobs:
  - job: initial
    pool:
      vmImage: 'ubuntu-latest'
    steps:
      - script: echo "This job will be run first."
  - job: fanout1
    pool:
      vmImage: 'ubuntu-latest'
    dependsOn: initial
    steps:
      - script: echo "This job will run after the initial job, in parallel with fanout2."
  - job: fanout2
    pool:
      vmImage: 'ubuntu-latest'
    dependsOn: initial
    steps:
      - script: echo "This job will run after the initial job, in parallel with fanout1."
  - job: fanin
    pool:
      vmImage: 'ubuntu-latest'
    dependsOn: [fanout1, fanout2]
    steps:
      - script: echo "This job will run after fanout1 and fanout2 have finished."
```

### GitHub Actions 作业之间的依赖关系的语法

```yaml
jobs:
  initial:
    runs-on: ubuntu-latest
    steps:
      - run: echo "This job will be run first."
  fanout1:
    runs-on: ubuntu-latest
    needs: initial
    steps:
      - run: echo "This job will run after the initial job, in parallel with fanout2."
  fanout2:
    runs-on: ubuntu-latest
    needs: initial
    steps:
      - run: echo "This job will run after the initial job, in parallel with fanout1."
  fanin:
    runs-on: ubuntu-latest
    needs: [fanout1, fanout2]
    steps:
      - run: echo "This job will run after fanout1 and fanout2 have finished."
```

有关详细信息，请参阅“[GitHub Actions 的工作流语法](/zh/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idneeds)”。

## 将任务迁移到操作

Azure Pipelines使用 *tasks*，这是可在多个工作流中重用的应用程序组件。
GitHub Actions 使用 *操作*，可用于执行任务和自定义工作流。 在这两个系统中，您可以指定要运行的任务或操作的名称，以及任何必需的输入作为键/值对。

下面是每个系统的语法示例：

### Azure Pipelines任务语法

```yaml
jobs:
  - job: run_python
    pool:
      vmImage: 'ubuntu-latest'
    steps:
      - task: UsePythonVersion@0
        inputs:
          versionSpec: '3.7'
          architecture: 'x64'
      - script: python script.py
```

### GitHub Actions 操作的语法

```yaml
jobs:
  run_python:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-python@v5
        with:
          python-version: '3.7'
          architecture: 'x64'
      - run: python script.py
```

可以在工作流中找到可在工作流中使用的 [GitHub Marketplace](https://github.com/marketplace?type=actions)操作，也可以创建自己的操作。 有关详细信息，请参阅“[重用自动化](/zh/actions/how-tos/reuse-automations)”。