如何使用 GitHub Actions 为 CI 创建工作流?

已完成

回想一下,你的目标是自动执行代码生成和发布过程,以便每次开发人员向代码库添加更改时更新功能。

若要实现此过程,请了解如何:

  • 从模板创建工作流。
  • 使用可重用工作流避免重复。
  • 标识触发工作流的事件。
  • 使用 GitHub Actions 工作流日志。
  • 针对多个目标进行测试。
  • 单独的构建和测试作业。
  • 保存和访问构建工件。
  • 在审阅后,自动向拉取请求添加标签。

从模板创建工作流

若要创建工作流,通常首先使用模板。 模板具有为要实现的特定类型的自动化预先配置的常见作业和步骤。 如果不熟悉工作流、作业和步骤,请使用 GitHub Actions 模块查看“自动执行开发任务 ”。

在 GitHub 存储库的主页上,选择 操作,然后选择 新建工作流

“选择工作流 ”页上,可以从许多类型的模板中进行选择。 一个示例是 Node.js 模板。 Node.js 模板安装 Node.js 和所有依赖项,生成源代码,并针对不同版本的 Node.js运行测试。 另一个示例是 Python 包 模板,它安装 Python 及其依赖项,然后在多个 Python 版本中运行测试(包括 lint)。

若要从 Node.js 工作流模板开始,请在搜索框中输入 Node.js

显示“GitHub Actions”选项卡的屏幕截图,其中突出显示了搜索框,文本 Node.js。

在搜索结果中,在 “Node.js ”窗格中,选择“ 配置”。

显示“GitHub Actions”选项卡的屏幕截图,其中突出显示了“Node.js”窗格,并选择了“配置”按钮。

项目的 node.js.yml 文件是根据模板创建的:

name: Node.js CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [14.x, 16.x, 18.x]

    steps:
    - uses: actions/checkout@v3
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - run: npm ci
    - run: npm run build --if-present
    - run: npm test

如属性 on 所示,此示例工作流在响应推送到存储库时或针对主分支创建拉取请求时运行。

此工作流运行一个作业,该作业由 job 属性指示。

runs-on 属性指定,对于操作系统,工作流在 ubuntu-latest 上运行。 该 node-version 属性指定有三个版本,每个版本分别用于 Node.js 版本 14.x、16.x 和 18.x。 该 matrix 属性将在模块的后面部分进行深入描述。

jobs 属性中,这些步骤使用 GitHub Actions actions/checkout@v3 动作将代码从存储库获取到虚拟机(VM),并使用 actions/setup-node@v3 来设置正确的 Node.js版本。 指定要使用属性 ${{ matrix.node-version }} 测试三个版本的 Node.js。 此属性引用前面定义的矩阵。 该 cache 属性指定用于在默认目录中缓存的包管理器。

此步骤的最后一部分执行 Node.js 项目使用的命令。 命令 npm cipackage-lock.json 文件中安装依赖。 npm run build --if-present 运行生成脚本(如果存在)。 npm test 运行测试框架。 此模板包括同一作业中的生成和测试步骤。

若要了解有关 npm 的详细信息,请查看 npm 文档:

开发人员团队可以从使用可重用工作流来简化和标准化重复的自动化步骤中获益。 通过使用可重用工作流,可以减少冗余,提高可维护性,并确保持续集成/持续部署(CI/CD)管道之间的一致性。

使用可重用工作流避免重复

随着团队的规模和项目的增长,在多个工作流文件中重复相同的步骤很常见。 这些步骤可能包括代码签出、依赖项安装、测试和部署。 此类重复不仅使代码库混乱,还增加了需要更改代码时的维护时间。 可重用工作流通过允许定义自动化逻辑一次,然后从其他工作流调用逻辑来解决此问题。

可重用工作流是其他工作流可以调用的特殊 GitHub Actions 工作流,类似于编程中的函数。 创建它们以共享重复的逻辑,例如生成步骤、测试过程或部署策略。 创建可重用工作流后,可以从同一存储库中的其他任何工作流,甚至在不同的存储库中引用它。

显示 GitHub Actions 中可重用工作流的概念的关系图。多个存储库或工作流可以引用中央工作流。

为何使用可重用工作流?

以下是使用可重用工作流的好处:

  • 一致性。 团队可以在所有项目中遵循相同的自动化标准。
  • 效率。 只需指向可重用的工作流,而不是复制和粘贴步骤。
  • 简化的更新。 当进程发生更改(例如通过添加测试步骤)时,可以在一个位置更新它。 然后,使用该工作流的所有工作流会自动获益。
  • 可伸缩性。 可重用工作流非常适合管理多个服务的平台或 DevOps 团队。

接下来,了解如何使用可重用工作流改进项目。

实现可重用工作流

若要使用可重用工作流,请使用:

  1. 在存储库文件夹中,创建可重用的工作流。 该文件包括要共享的自动化步骤,例如测试、生成和部署所涉及的常见步骤。
  2. 通过使用 workflow_call 事件配置,使工作流显式可重用。
  3. 在主工作流(调用方工作流)中,引用此可重用文件并提供任何必需的输入或机密。

为了说明可重用工作流的优点,请考虑以下实际方案。

示例:

假设组织有 10 个微服务。 所有 10 个微服务都需要相同的步骤才能:

  • 运行测试
  • Lint 代码
  • 部署到特定环境

如果没有可重用的工作流,每个存储库都包含重复的逻辑,这些逻辑列出了每个工作流中的重复步骤。

如果使用可重用工作流:

  • 在中心文件中定义一次进程(例如,在 ci-standard.yml 中)。
  • 从每个微服务自己的工作流调用此文件,传入环境变量或应用程序名称等变量。

如果添加了新的安全步骤或工具(例如扫描漏洞),则只需在可重用工作流中添加一次。 所有 10 个微服务立即开始使用更新的过程。 无需修改 10 个微服务。

通过了解可重用工作流的功能及其优势,可以采用最佳做法来最大程度地提高其有效性,并确保与 CI/CD 管道无缝集成。

最佳做法

  • 如果计划跨团队共享可重用工作流,请将可重用工作流集中到一个存储库中。
  • 使用分支或标记对工作流进行版本控制(例如,使用 @v1),以便在需要时可以轻松回滚更改。
  • 清楚地记录输入和机密。 可重用工作流通常依赖于输入和机密。 团队需要知道应该使用哪些信息。
  • 如果只需要重复使用几个步骤,请结合可重用工作流和复合操作,而不是创建完整的工作流。

可重用工作流是在任何工程团队中强制实施一致性、减少重复和缩放 DevOps 实践的强大方法。 无论是管理单个存储库、微服务还是开源库,可重用工作流都可以简化自动化,因此 CI/CD 更快、更简洁、更易于管理。

标识触发工作流的事件

了解触发的 GitHub Actions 工作流对于调试、审核和改进 CI/CD 管道至关重要。 触发器类型包括推送到分支、创建或更新的拉取请求、计划的作业或手动调度。 可以通过检查工作流运行、存储库更改以及相关的 GitHub 问题或拉取请求来标识触发事件。

图表显示 GitHub Actions 中的各种工作流触发器,比如推送、拉取请求、计划任务和手动触发。

什么是工作流触发器?

工作流触发器是导致工作流运行的事件。 GitHub 支持各种类型的触发器,包括:

  • pushpull_request (基于代码更改)
  • workflow_dispatch (手动触发器)
  • schedule(cron 作业)
  • repository_dispatch (外部系统)
  • 问题、讨论和拉取请求事件(例如,issues.openedpull_request.closed

标识触发器事件

可以通过多种方式标识工作流触发器事件:

  • 使用 GitHub Actions UI:

    1. 在存储库中,选择操作选项卡。
    2. 选择工作流运行。

    事件类型(例如 pushpull_requestworkflow_dispatch)显示在工作流运行摘要的顶部。

  • 在日志或工作流中使用github.event_name

    • GitHub 在工作流运行期间公开上下文数据。 该 github.event_name 变量告诉你哪个事件触发了工作流。

    • 可以在调试过程中打印信息:

      -name: Show event trigger
        run: echo "Triggered by ${{ github.event_name }}"
      
  • 使用工作流运行详细信息:

    • 如果以编程方式检查工作流运行(例如使用 API),则运行对象包括一个 event 指定触发器的属性。
    • 可以找到提交记录的安全哈希算法(SHA)、操作者和时间戳,以跟踪导致触发的原因。

从存储库效果推断触发器

你可能无权直接访问工作流运行,但仍希望根据存储库活动推断触发工作流运行的内容:

观察到的行为 触发事件
新提交已推送到 main,并且工作流已运行。 push 事件
拉取请求已打开或更新。 pull_request 事件
贡献者手动运行工作流。 workflow_dispatch
工作流每天在特定时间运行。 schedule (cron)
工作流在外部服务调用完成后运行。 repository_dispatch
将标签或注释添加到问题时,工作流运行。 issues.* 事件

通过查看时间戳、拉取请求活动和提交历史记录,通常可以确定是哪个操作导致了工作流的运行。

总结如何识别触发工作流的内容:

  • “操作”选项卡上检查工作流运行摘要。
  • 在工作流中打印或记录 github.event_name 以确保其可见。
  • 比较时间戳和存储库活动(提交、拉取请求、问题)来推断触发器。
  • 使用完整 event 上下文进行更深入的调查。

这些做法可帮助你在开发和部署管道中调试、审核和提高工作流可靠性。

通过读取其配置文件描述工作流效果

要描述工作流通过读取其配置文件所产生的效果,请分析存储在.yml中的.github/workflows/文件的结构和内容。

工作流配置文件标识有关工作流的以下信息:

  • 当它运行时(在 on 分区中)。
  • 它执行的操作(在 jobssteps 中)。
  • 它的运行位置(runs-on 分区)。
  • 它运行的原因(其用途,例如测试、部署或 Lint 分析)。
  • 它在特定条件下的行为方式(环境、筛选器、逻辑)。

解释工作流效果

  1. 标识触发器。

    若要确定启动工作流的操作,请参阅工作流的on部分。

    例如:

    on:
      push:
        branches: [main]
      pull_request:
        types: [opened, synchronize]
      workflow_dispatch:
    

    此示例工作流:

    • 将代码推送到主分支时自动运行(push)。
    • 创建或更新拉取请求时运行(pull_request)。
    • 可由用户手动触发(workflow_dispatch)。
  2. 确定工作流作业和步骤。

    若要确定工作流的作用,请参阅工作流中的 jobssteps 部分。

    例如:

    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout code
            uses: actions/checkout@v3
          - name: Install dependencies
            run: npm install
          - name: Run tests
            run: npm test
    

    此示例工作流:

    • 使用 Linux 虚拟环境(runs-on)。
    • 查看存储库的代码 (steps>name)。
    • 安装项目依赖项(steps>name)。
    • 运行自动测试(steps>name)。
  3. 评估工作流的目的和结果。

    通过读取配置文件,可以描述工作流的预期结果:

    “此工作流是持续集成(CI)管道。 它可确保自动测试推送到存储库或通过拉取请求提交的任何新代码。 如果测试失败,GitHub 工作流 UI 会显示此结果,以帮助维护代码质量。

  4. 确定或设置影响工作流运行方式的可选功能:

    • env 设置环境变量。
    • if 仅当满足条件时,才添加条件逻辑以运行特定步骤。
    • timeout-minutescontinue-on-error 设置工作流执行和错误处理。

诊断失败的工作流运行

  1. 在存储库中,转到“操作”选项卡。

  2. 查找失败的运行(通常由红色 X 指示)。

  3. 选择失败的工作流以打开运行概览。

  4. 在工作流日志中,查看错误。

    1. 在运行摘要中,展开每个作业和步骤,直到找到指示失败的作业和步骤。

    2. 选择作业或步骤以查看其日志。

    3. 查找:

      • 错误消息
      • 堆栈跟踪
      • 退出代码

    例如,失败的测试可能会显示 npm ERR! Test failedexit code 1

  5. 检查工作流配置文件。

    使用 .yml 文件来确定:

    • 每个步骤都试图做什么?
    • 如果有影响执行的环境变量(env)或条件(if)。
    • 如果失败是由于缺少依赖项、语法错误或配置错误步骤导致的。

    如果步骤失败,请检查以下原因:

    • 依赖项是否已在上一步中成功安装?
    • 测试文件是否存在并在本地传递?

常见故障方案

下表描述了常见的工作流失败方案:

症状 可能的原因
步骤失败并返回 command not found 缺少依赖项或错误的设置
npm install 失败。 文件损坏 package-lock.json 或网络问题
测试步骤失败。 单元测试问题、缺少配置文件或无效的测试语法
Permission denied 出现。 文件权限不正确或机密缺失

确定如何在 GitHub 中访问工作流日志

  1. 在存储库中,转到“操作”选项卡。

  2. 在工作流列表中,选择相关的工作流。

    例如,如果 .yml 文件具有以下代码,列表中会显示标题为 CI 工作流 的链接:

    name: CI Workflow
    
  3. 选择特定的运行。

    在显示状态的运行列表中,选择要检查的特定运行的时间戳或提交消息。

  4. 展开每个作业和步骤。

    运行摘要页面显示在工作流文件中定义的作业,例如构建或测试:

    1. 选择作业以展开。
    2. 在作业中,展开各个步骤,例如“安装依赖项”或“运行测试”。
  5. 查看日志输出。

    若要查看完整的日志输出,包括控制台日志、错误消息和调试信息,请选择工作流步骤。 可以复制、搜索和下载日志。

下表总结了访问工作流日志所要执行的步骤:

行动 目的
动作选项卡 查看所有工作流记录。
选择工作流名称 按工作流筛选运行。
选择运行 请查看特定任务和步骤的结果。
展开步骤 查看详细日志。
下载日志 下载用于脱机或团队故障排除的日志。

生成的操作日志

工作流运行时,它会生成一个日志,其中包含所发生事件的详细信息以及任何错误或测试失败。

如果发生错误或测试失败,则会在日志中显示红色 X 而不是绿色复选标记。 可以检查错误或失败的详细信息来调查发生了什么情况。

GitHub Actions 日志的屏幕截图,其中包含有关失败的测试的详细信息。

自定义工作流模板

在本模块的开头,你已考虑了需要为开发人员团队设置 CI 的方案。 Node.js 模板是一个很好的开端,但你想要对其进行自定义,以便更好地满足团队的要求。 你需要面向 Node.js 的不同版本和不同的操作系统。 你还希望生成和测试步骤是单独的作业。

下面是自定义工作流的示例:

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    node-version: [16.x, 18.x]

在此示例中,你将配置一个 生成矩阵 ,用于跨多个作系统和语言版本进行测试。 此矩阵会产生四个版本,每个操作系统的版本搭配每个 Node.js 版本。

四个构建及其测试会产生大量的日志数据。 可能很难整理所有问题。 在以下示例中,将测试步骤移动到专用测试作业。 此作业针对多个目标进行测试。 分离生成和测试步骤可以更轻松地处理日志数据。

test:
  runs-on: ${{ matrix.os }}
  strategy:
    matrix:
      os: [ubuntu-latest, windows-latest]
      node-version: [16.x, 18.x]
  steps:
  - uses: actions/checkout@v3
  - name: Use Node.js ${{ matrix.node-version }}
    uses: actions/setup-node@v3
    with:
      node-version: ${{ matrix.node-version }}
  - name: npm install, and test
    run: |
      npm install
      npm test
    env:
      CI: true

处理工件

当工作流生成日志条目以外的内容时,产品称为 项目。 例如,Node.js 构建产生一个可以部署的 Docker 容器。 容器是一个工件,可以通过使用 动作/上传工件 动作将其上传到存储。 稍后可以使用 actions/download-artifact 从存储下载工件。

存储工件会在作业之间保留工件。 每个作业都使用 VM 的新实例,因此不能通过在 VM 上保存项目来重复使用该项目。 如果需要在其他作业中使用工件,可以在一个作业中将工件上传到存储,并将其下载到另一个作业中。

工件存储

工件存储在 GitHub 的存储空间中。 公共存储库的空间是免费的,某些存储空间对于私有存储库是免费的,这具体取决于帐户。 GitHub 可将工件存储 90 天。

在以下工作流代码片段中,actions/upload-artifact@main 操作中有一个 path 属性。 此属性的值是存储项目的路径。 在此示例中,指定 公共/ 将所有内容上传到目录。 如果只想上传单个文件,请使用 公共/mytext.txt等内容。

  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: npm install and build webpack
        run: |
          npm install
          npm run build
      - uses: actions/upload-artifact@main
        with:
          name: webpack artifacts
          path: public/

若要下载用于测试的工件,构建必须成功完成并上传工件。 在以下代码中,指定测试作业依赖于生成作业。

test:
    needs: build
    runs-on: ubuntu-latest

在以下工作流代码片段中,你将下载该工件。 现在,测试作业可以使用产物进行测试。

steps:
    - uses: actions/checkout@v3
    - uses: actions/download-artifact@main
      with:
        name: webpack artifacts
        path: public

有关在工作流中使用项目的详细信息,请参阅 将工作流数据存储为项目

使用工作流在 GitHub 上自动化代码审查

除了通过 GitHub 事件pushpull-request启动工作流,还可以按计划或在 GitHub 外部的某些事件之后运行工作流。

你可能希望工作流仅在用户完成特定操作后运行,例如拉取请求获审阅者批准之后。 对于此方案,可以在 pull-request-review 上触发。

可以采取的另一项操作是向拉取请求添加标签。 在这种情况下,请使用 pullreminders/label-when-approved-action 操作。

例如:

    steps:
     - name: Label when approved
       uses: pullreminders/label-when-approved-action@main
       env:
         APPROVALS: "1"
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         ADD_LABEL: "approved"

env 块中,为该操作设置环境变量。 例如,可以设置运行工作流所需的审批者数。 在此示例中,它是一。 身份验证 secrets.GITHUB_TOKEN 变量是必需的,因为该作必须通过添加标签对存储库进行更改。 最后,输入要添加的标签的名称。

添加标签可能是启动另一个工作流的事件,例如合并。 我们将在下一个模块中介绍此事件,该模块介绍如何在 GitHub Actions 中使用持续交付。