GitHub Actions使用学习最全文档

CI/CD 触发器

GitHub Actions是一个独立的系统:它提供了 CI/CD 构建功能──能够构建和测试 Pull Request 并合并到你的master分支中──但它不只限于构建系统。 它已经集成到GitHub中,并且 只要你的项目库中发生任何事件(例如正在创建发行版或正在评论问题),都可以触发并运行工作流。

我将在这个月更多地讨论那些项目库自动化方案,但是你要知道,这种灵活性将有助于理解如何进行 CI/CD 构建设置。 GitHub Actions 允许你定义一个 触发器 来控制工作流程的运行时间。每当你的项目库中发生与该触发器匹配的操作时,工作流运行都会进入排队队列中准备。

对于 CI/CD 工作流,我喜欢使用 push 和 pull_request 触发器,并将其范围限定在我感兴趣的分支上。例如:

on:
  push:
    branches:
    - master
  pull_request:
    branches:
    - master

这个触发器将在对master分支进行任何更改时运行你的工作流──(即使它的名字是 push 触发器,也将在你运行 git push 或将 pull request 合并到 master 分支时运行)。对于针对master分支打开的任何 pull request,工作流也将运行,并且将在 pull request 中向你显示验证。
在这里插入图片描述

如果你熟悉YAML语法,就可能会注意到分支采用数组。 因此,你可以轻松地设置工作流在多个分支中运行,这在你维护单独的发布轨道追踪时非常有用。 例如:

on:
  push:
    branches:
    - master
    - 'releases/**'
  pull_request:
    branches:
    - master
    - 'releases/**'

每当对 master 分支或名称 以 releases/ 开头的分支 打开 pull request 时,将运行你的工作流。

通过 push 和 pull_request 触发器,可以轻松设置 CI/CD 样式的工作流程来验证 pull request,并使用 GitHub Actions 合并到你的 master 分支中。

矩阵工作流

拥有 CI/CD 系统的最大优势之一是,它使你可以高效地构建和测试多种配置。在推送之前,你在机器上进行构建和测试当然是必要的,但这几乎是不够的。毕竟,你可能只安装了一个版本的节点。但是,在各种平台上构建将使你充满信心和洞察力,使你的更改可以在你支持的整个生态系统中发挥作用。

Mozilla Tinderbox 是最早引入跨多个配置构建概念的 CI 系统之一。这是革命性的──当我使用 AbiWord 时,我负责了 Tinderbox 的设置。我们有一个充满机器的实验室,以便我们可以测试 Motif 构建和 GTK 构建,并可以针对不同的依赖项进行测试(这是在从可怕的 libc5 到 libc6 迁移的时候),甚至是不同的 C ++ 编译器。

那时,我的工作很大一部分是维护这个装有昂贵计算机的实验室。因此,我最喜欢的 GitHub Actions 特性之一就是矩阵工作流功能也就不足为奇了,它使我能够快速运行多个构建以支持各种配置。

我仍然在编写代码,因此仍然需要使用不同的编译器和不同的依赖项进行构建。但是现在我不需要一个充满机器的实验室,我只需要在 GitHub Actions 中使用矩阵工作流设置即可。

矩阵工作流一开始可能看起来有些让人不知所措,但这实际上只是简单的变量替换。您定义了一组变量,以及应分配给每个变量的一组值。然后,GitHub Actions 将使用这些变量的所有不同扩展来执行工作流。

假设你要测试三个不同的变量,这很快变得非常强大。就我而言,我想用两个不同的 C 编译器(gcc和clang),三个不同的 SSL 后端(OpenSSL,GnuTLS和NSS)以及两个不同的 Kerberos 后端(MIT和Heimdal)进行测试。要测试所有这些不同的组合,那就是2 * 3 * 2 = 12种不同的配置。

但是,我不必定义十二个不同的工作(或更糟的是,必须像在糟糕的过去那样在实验室中设置十二个不同的机器),我只需指定一个包含三个变量的矩阵即可。如果在作业中指定矩阵,则实际上将获得十二个以不同排列运行的作业:

matrix:
  cc: [gcc, clang]
  curl: [openssl, gnutls, nss]
  kerberos: [libkrb5, heimdal]

现在在我的工作中,我可以使用矩阵上下文引用这些变量中的每一个。例如,$ 将扩展为 cc 变量的当前值。

以下是一个示例工作流,该工作流安装每个依赖项,并运行我的 autoconf 设置,然后运行 make:

当你运行此工作流程时,你可以快速查看它如何扩展到12个不同的作业。在工作流运行的左侧,你可以看到它们中的每一个。 这样,简单的工作流程就可以迅速扩展。

在其中一个运行中打开步骤时,你可以看到确实我们能够安装依赖项。 如果打开 build (clang, openssl, libkrb5) 任务,实际上正在运行 clang(由 ${CC} --version 显示),libcurl的OpenSSL版本(由 curl-config 显示)和 MIT krb5(由 krb5-config 显示)。
在这里插入图片描述

因此,你可以看到,你只需使用工作流中的几行矩阵定义就可以构建具有多种配置的强大工作流。

跨平台构建

GitHub Actions 的优点之一是它不仅支持在 Linux 主机上或在容器中运行构建。GitHub 当然提供了Linux虚拟机,但是它们也提供了运行 Windows 和 macOS 的虚拟机。

macOS 虚拟环境尤其重要,因为即使作为开发人员,也不能在虚拟机上运行 macOS,除非你在 Apple 硬件上运行它。因此,如果你要构建跨平台应用程序,则可能会限制你在本地构建和测试自己的应用程序的方式。

要指定主机类型,请使用作业的 runs-on 参数进行指示。 例如,runs-on: macos-latest 将在 macOS 上运行,runs-on: windows-latest 将毫不奇怪在 Windows 上运行。 因此,如果要通过在 Linux,macOS 和 Windows 三个平台上运行 make 来构建应用程序:,则可以将每个平台指定为一个单独的作业。 这是一个例子

但这重复了很多……如果你阅读了昨天有关 矩阵工作流 的文章,你可能还记得我说过矩阵扩展实际上只是简单的变量替换。好吧,即使在运行参数中也是如此。

这意味着你可以使用矩阵来建立跨平台构建,其中只需几行工作流定义即可:

因此,你可以选择:可以使用要在其上运行的虚拟环境指定每个单独的作业,或者,如果有共同的步骤,则可以使用矩阵来运行。

安装工具

昨天我提到 GitHub Actions 提供了 Linux,Windows 和 macOS 虚拟环境,你可以在其中运行工作流。

但是这些环境上实际安装了什么? 原来有很多安装

团队试图通过许多不同的平台使我们的运行器(runners)保持最新状态。 因此,你会发现许多不同版本的Python,Ruby,.NET Core等。 但是──仅仅依靠这些各种各样的开发工具──他们不可能绝对安装所有东西。

有时你需要自己安装。而且由于你拥有一台完整的虚拟机,因此对于每项作业执行,你都可以在其上安装任何所需的软件。

例如,你可能要安装非常好的“ninja”构建工具。

Linux

Linux虚拟环境运行Ubuntu,因此你可以使用 apt 安装可能需要的任何其他工具。 默认情况下,你以非 root 用户身份运行,但是可以使用无密码 sudo。这样你就可以:

run: sudo apt-get install ninja-build

Windows

Chocolatey 是 Windows 的首选软件包管理器,它已安装并可以在 GitHub Actions 虚拟环境中使用。

run: choco install ninja

macOS

在 macOS 上,Homebrew 是推荐的软件包管理器,可在 GitHub Actions 虚拟环境中使用。无需以 root 用户身份运行 Homebrew ──实际上,这是不合时宜的,因此您可以执行 brew install

run: brew install ninja

合在一起

综上所述,如果你想在所有三个平台上安装 ninja,你的工作流程将如下所示

name: CI

on: [push]

jobs:
  linux:
    runs-on: ubuntu-latest
    steps:
      - run: sudo apt-get install ninja-build
      - run: ninja --version

  windows:
    runs-on: windows-latest
    steps:
      - run: choco install ninja
      - run: ninja --version

  mac:
    runs-on: macos-latest
    steps:
      - run: brew install ninja 
      - run: ninja --version

在容器中构建

昨天我讨论了如何 在GitHub Actions虚拟环境上安装工具和依赖项。 但是,如果你需要更多控制权怎么办? 或者,如果你根本不想在 Ubuntu 上运行,该怎么办? 这是容器发光的地方。

通过创建一个包含所有需要的开发工具以及项目依赖项的容器,你不必操心在工作流运行开始时就对那些设置和安装步骤进行管理。

此外,你还将获得基于容器的开发的优势:你可以在用于CI构建的同一个容器中进行本地构建,因此你可以高度自信地确保 GitHub Actions 中的构建与构建时所看到的与本地匹配。

语法非常简单明了──我不需要自己运行任何 docker pulldocker run 命令。 GitHub Actions 为我解决了这个问题。要获取源代码并在 node:current 容器中运行测试,请执行以下操作:

name: CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    container: 'node:current'

    steps:
    - uses: actions/checkout@v1
    - run: |
        npm ci
        npm run build
        npm test

当我运行此工作流时,GitHub Actions 将从 DockerHub 下载我指定的容器,启动它,然后直接在该容器中执行我指定的运行步骤。

请注意,在容器内运行时,仍然需要指定运行对象。这是因为 Linux 和 Windows 都支持容器──因此,如果你要运行基于 Linux 的容器,则需要 runs-on: ubuntu-latest。 如果要使用基于Windows的容器,请确保设置 runs-on: windows-latest

容器还可以帮助扩展构建矩阵:如果要跨多个 Linux 发行版构建和测试工具,则甚至可以在矩阵中设置容器作业。(因为 矩阵工作流实际上只是可变的替代。)

例如,要在 Debian,Ubuntu 和 CentOS 的旧版和最新版本上构建:

name: CI

on: push

jobs:
  linux:
    strategy:
      matrix:
        container:
        - 'debian:7'
        - 'debian:testing'
        - 'ubuntu:14.04'
        - 'ubuntu:devel'
        - 'centos:6'
        - 'centos:latest'
    runs-on: ubuntu-latest
    container: ${{ matrix.container }}
    steps:
      - run: cat /etc/*release

因此,无论你是要直接在我们提供的虚拟环境中还是在你指定的容器中构建,你都可以灵活地选择工作流的运行位置。

快速失败的矩阵工作流

因此,关于 GitHub Actions 的这些帖子甚至还不到一周,我已经写了很多有关 矩阵工作流 的文章。如你还没猜到,我是忠实粉丝。 😍

但是,如果你开始设置第一个矩阵工作流程,那么你需要注意:默认情况下,矩阵工作流程会快速失败。这就是说:如果矩阵扩展中的一个作业失败,则其余作业将被取消。

这种行为通常非常有益:如果你正在运行 pull request 验证构建,而矩阵中的构建之一失败,则你可能根本不在乎其余的构建是否成功。任何失败都足以表明存在使你无法合并 PR 的问题。

但是,当你从头开始创建工作流时,可能需要迭代一下才能使其第一次正常工作。当作业失败是由于工作流设置中存在问题而不是代码本身存在问题时,关闭快速故障行为作为调试工具会很有帮助。

假设你有一个在 Linux 上运行良好的工作流程,并且希望使用矩阵将其扩展到可以在 macOS 和 Windows 上运行。对于简单的工作流程,这可能会正常工作。但是对于更复杂的事情,你可能需要先设置一些依赖项或安装一些工具,然后才能起作用。因此,很可能你的Linux上运行的工作流如果不做一些修改就无法在 macOS 或 Windows 上运行。

那么,当你第一次运行此新矩阵工作流时会发生什么?你的 Linux,macOS 和 Windows 作业将全部启动,并且 macOS 作业或 Windows 作业将失败,其余工作流程将被取消。

想象一下,首先失败的是 Windows 作业。你会看到的:
在这里插入图片描述

好的,因此你决定需要修复 Windows 工作流程。 因此,你可以查看出了什么问题,更新工作流程,然后推送更改以将新构建放入队列。 但是,由于排队和调度不是很确定,因此也许这次 macOS 构建首先完成──失败。 现在,你的 Windows 运行被取消,甚至无法找出它是否有效:
在这里插入图片描述

现在,在调试工作流时,可以通过设置 fail-fast: false 来关闭此行为:

strategy:
  matrix:
    os: [ubuntu-latest, macos-latest, windows-latest]
  fail-fast: false

现在,工作流不会在第一个失败的作业时被取消。它将允许 Windows 和 macOS 作业运行完成。
在这里插入图片描述

关闭 fail-fast 将帮助你更轻松地迭代工作流程。准备好在生产中运行时,请务必将其重新打开!这将帮助你节省CI运行时间(和金钱)。

入门工作流程

如果你仅创建了一个或两个GitHub Actions工作流,则可能对如何起步不太关注,但是GitHub Actions团队关注如何起步,他们努力工作,以使你能尽可能轻松地开始使用Actions。

在创建新工作流程时,GitHub首先要考虑的是存储库中的代码类型。GitHub Actions使用成熟的语言工具来了解你的存储库包含哪种代码。这是为GitHub许多其他部分提供支持的工具,其中包括存储库主页上的语言统计栏。
在这里插入图片描述

对于这个拥有大量JavaScript的存储库,GitHub Actions将选择两个可能的工作流程──运行 npm run buildnpm test 的Node.js CI/CD工作流程(这对应用程序有用),以及执行相同构建和测试运行的打包工作流程,然后将程序包发布到GitHub Packages中。
在这里插入图片描述

GitHub Actions不仅具有构建和测试项目的能力,还有工作流可以帮助你开始将应用程序部署到云中,无论是AWS,Azure还是Google Cloud。
在这里插入图片描述

而且,当然,尽管和语言学家一样好,它也不是完美的。许多人在同一存储库中混合了不同的项目,因此你还可以扩展整个启动程序工作流列表。

在这里插入图片描述

如果你想帮助改善入门工作流程──无论是对现有工作流程进行更改,还是添加全新的语言,都可以在GitHub上进行提交。

处理过时的 issue

存储库中存在过时的issue可能是一个很大的危害。如果你有数年不打算解决的issue,那么就很难找到要关注的重要问题。你永远不会合并的pull request使你看起来好像在忽略该项目。项目中的所有这些杂项都增加了无形的认知负担。

在服务行业工作的任何人都会理解此问题。这就像一个厨师的 场面调度连接 的地方──在他们与他们的配料厨房的设置。

如果让你的现场发生故障,变脏和混乱,你会很快发现自己旋转到位并需要备份。我和一位厨师一起工作,他曾经在匆忙中走到排队的肮脏厨师的工作台旁,解释为什么违规的厨师落后了。他将手掌压在切菜板上,切菜板上撒满了胡椒粒,飞溅的酱汁,一些香菜,面包屑以及通常会漂浮在工作台上的漂浮物和抛弃物,如果不时常用潮湿的侧毛巾将其擦掉。“你看到了吗?” 他打了个招呼,抬起他的手掌,这样厨师就可以看到灰尘和碎屑粘在厨师的手掌上。“那就是你现在的脑袋。”

Anthony Bourdain,厨房机密

当GitHub着手创建Actions平台时,他们希望构建一些对CI/CD工作流程非常有用的东西──构建项目,运行测试并部署它──但这也可以帮助你自动化项目中的常见任务。在这种情况下,请保持存储库的美观和整洁。

启动程序工作流程的底部是关闭陈旧issue和 pull request 的工作流程。

它会按计划触发运行,因此在每天UTC午夜:

on:
  schedule:
  - cron: "0 0 * * *"

当它运行时,它将运行过时的操作,该操作将查看存储库中的issue和pull request,并找到几个月没有执行任何操作的请求。然后它将在问题中发布一条消息,并添加一个标签,指示该问题是过时的。如果该问题再保持一周的陈旧状态,则将其关闭。
在这里插入图片描述

这样可以确保识别出每一个过时的issue,但同时也给人们足够的时间告诉过时的操作以使issue或pull request保持打开状态──许多这些旧issue和PR毕竟具有价值!

最终,处理过时issue的的工作流程是减少存储库中某些干扰并允许你“工作干净”的简便方法。

部署到GitHub Packages

本月到目前为止,我们已经研究了许多执行构建并运行一些测试的方案。这些都是很棒的工作流程──它们确保进入你的项目的pull request是高质量的,并且你的主分支是健康的。

但是,你通常想采取下一步并部署自己构建的内容。例如,你可能想构建一个容器,并在每次新的主分支合入新功能时将其上传到GitHub Packages。这将确保你有一个可以运行并验证每个更改的容器。

为此,我们要触发向master的推送。(无论是从 git push 还是从合并pull request,只要集成到master中,push 触发器都将运行。)

然后,我们将从docker登录到GitHub Packages。我们可以简单地使用GitHub Actions提供给我们的 GITHUB_TOKEN──令牌对我们存储库中的软件包具有发布权限。

然后,我们将构建容器,并使用包注册的名称对其进行标记(在本例中是 docker.pkg.github.com 其后为容器的名称 ethomson/myrepo/app),并为其指定版本号,即Unix时间。

最后,我们将容器推送到GitHub Packages

name: Docker

on:
  push:
    branches:
    - master

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js 12.x
      uses: actions/setup-node@v1
      with:
        node-version: 12.x
    - name: package docker
      run: |
        VERSION=$(date +%s)
        docker login docker.pkg.github.com --username ethomson --password ${{ secrets.GITHUB_TOKEN }}
        docker build . --file Dockerfile --tag docker.pkg.github.com/ethomson/myrepo/app:${VERSION}
        docker push docker.pkg.github.com/ethomson/myrepo/app:${VERSION}
      env:
        CI: true

现在,我有一个简单的连续部署系统,该系统将始终使用包含来自master分支的最新版本的容器来更新GitHub Packages。

路径触发器

前面我们看到可以限制基于分支过滤器的工作流运行。对于由 pushpull_request 触发的工作流,你可以对其进行限制,以使其仅在推送到特定分支或针对特定分支打开 pull request 时才触发。

你还可以限制这些工作流,以便仅在推送特定路径时才触发它们。

如果你在提交某些东西时会运行一些自动化功能,这将非常有用。例如:在我的一个开源项目中,每次将提交合并到master分支中时,我们都会将文档发布到我们的网站上。但是,我们只想在文档实际更改时运行该工作流程。

在这种情况下,我们希望docs在master分支中目录中的任何内容更改时运行。我们可以使用通配符作为路径过滤器的一部分:

name: Publish Documentation

on:
  push:
    branches:
    - master
    paths:
    - 'docs/**'

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - run: scripts/publish_docs.sh
        env:
          PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}

现在,我们有了一个工作流程,只要我们对文件docs夹中的文件进行新更改并将其合并到master分支中,就可以运行脚本 publish_docs.sh

密码(Secrets)

昨天我们建立了一个基于改变路径触发的工作流; 它的目标是发布文档。如果仔细看,在工作流程的底部,我们引用了一个变量。看起来有点像我们引用矩阵变量的方式 ,而这里引用了一个密码。

在部署场景中,你通常会需要令牌或密码之类的东西──GitHub Actions支持将这些作为密码保存在存储库中。

要设置密码,请转到“存储库设置”页面,然后选择“密码”。你的密码名称将在你的工作流中用于引用数据,你可以将密码本身放入值中。
在这里插入图片描述

要使用该密码,你可以在工作流中使用上下文 secrets 来引用它。如果你有一个密码的名字 SECRET_KEY,你可以将其称为 $

name: Publish Documentation

on:
  push:
    branches:
    - master

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - run: |
          VERSION=$(date +%s)
          docker login -u ethomson -p ${{ secrets.SECRET_KEY }}
          docker build . --file Dockerfile --tag ethomson/app:${VERSION}
          docker push ethomson/app:${VERSION}

GITHUB_TOKEN

GitHub Actions会为每次运行的工作流自动在存储库中设置一个密码 GITHUB_TOKEN。该令牌使你可以与存储库进行交互,而无需自己创建新令牌或设置密码。

该令牌为你提供了对存储库本身,issue和GitHub Packages进行读写的有限访问权限。但是它不能完全访问所有内容──你无法与组织中的其他存储库一起使用,也无法发布到GitHub Pages──因此,对于某些工作流,你可能仍需要设置令牌。

密码安全

GitHub试图防止你的密码被窥视。在输出日志中,你定义的所有密码都会被清除,并在输出日志之前用星号替换。
在这里插入图片描述

这有助于保护你的密码,防止他人窥视,尤其是利用那些导出值的工具。但这当然不是完美的,你应该谨慎保护密码。

Forks

如果你的项目使用fork来接受来自贡献者的pull request(例如,如果你正在开发一个开源项目),则可能对在工作流程中使用密码有所警惕。

GitHub明确 禁用 了对来自fork的工作流提供密码的功能。这意味着,当用户从fork打开对你的项目的pull request时,不会向此工作流提供任何密码。
在这里插入图片描述

这有助于防止用户修改工作流程本身──或工作流程调用的任何脚本──试图获取你的密码副本。这些密码根本无法获得。

GITHUB_TOKEN仍然为fork提供了特殊功能,以便它们可以克隆你的存储库(以便构建它),但已将其降级为只读令牌,以防止fork工作流在你的存储库中进行更改。)

有关工作流程的信息

昨天我们看到GitHub为GitHub Actions工作流运行提供了一些信息,即 GITHUB_TOKEN。但这还不是全部。GitHub Actions还为你提供什么其他信息?

其实很多!

GitHub Actions 设置了许多信息“上下文”,其中包含有关你的工作流程运行的数据。例如,github 上下文包含信息,例如你的工作流在其中运行的存储库的名称 github.repository,启动工作流的用户 github.actor。你可以使用与 处理矩阵 和 密码 相同的双弯括号扩展语法来引用它们。

name: Context Example

on: [push]

jobs:
  build:
    name: Inspect context
    runs-on: ubuntu-latest
    steps:
      - name: Inspect context
        run: |
          echo This workflow on github.repositorywasstartedby{{ github.actor }}

image

如果你想在上下文中查看GitHub Actions提供的所有信息,则可以实际使用方便的 toJson 函数来输出整个对象:

name: Inspect Contexts

on: [push]

jobs:
  build:
    name: Inspect contexts
    runs-on: ubuntu-latest
    steps:
      - name: Inspect contexts
        run: |
          echo "The github context is:"
          echo "${{ toJson(github) }}"
          echo ""
          echo "The job context is:"
          echo "${{ toJson(job) }}"
          echo ""
          echo "The steps context is:"
          echo "${{ toJson(steps) }}"
          echo ""
          echo "The runner context is:"
          echo "${{ toJson(runner) }}"
          echo ""
          echo "The strategy context is:"
          echo "${{ toJson(strategy) }}"
          echo ""
          echo "The matrix context is:"
          echo "${{ toJson(matrix) }}"

image

如果这样做,你会注意到GitHub上下文中有很多信息。特别是,github.event 对象本身就是一块巨大的json数据。它基本上包含与触发器相对应的 Webhook 信息

相同的事件信息已保存到磁盘上的 github.event_path。因此,你可以通过检查json blob来获取工作流程中的所有信息。幸运的是,非常方便的 jq 工具已安装在 runner 上。你可以使用它在命令行上分解json数据。

例如,如果我想获取存储库中的星标数量和fork数量,则可以 jq 用来解压缩保存在的json数据 github.event_path

name: Show Popularity

on: [push]

jobs:
  build:
    name: Show Popularity
    runs-on: ubuntu-latest
    steps:
      - name: Show Popularity
        run: |
          STARS=(jq−−raw−output.repository.stargazers"{{ github.event_path }}")
          FORKS=(jq−−raw−output.repository.forks"{{ github.event_path }}")
          echo "github.repositoryhasSTARS stars and $FORKS forks"

GitHub Actions提供了大量有关存储库,触发运行的操作以及环境的数据,所有这些使你能够创建工作流以构建应用程序,部署应用程序或自动执行存储库中的某些任务。

条件

昨天我们看到,当你运行工作流程时,有许多可用数据。你可以在run步骤中使用这些数据,并将其与构建脚本,部署步骤或存储库自动化一起使用。但是你也可以在工作流本身中使用它。

利用这些数据的一种有用方法是有条件地使用它来运行工作流步骤

例如,你可能想在执行步骤之前检查工作流在其中运行的存储库的名称。如果你正在开发一个开源项目,这将很有帮助──因为fork你的存储库的人拥有具有不同权限的令牌,因此你可以跳过fork的发布步骤。

这使fork的存储库仍可以执行连续的集成构建,并确保在运行构建和测试通过时工作流成功,并且不会由于发布步骤上的权限问题而失败。

你可以设置一个条件,以确保你位于正确的存储库上并在CI构建中运行(来自push事件)。

name: CI

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

jobs:
  build:
    name: Publish
    runs-on: ubuntu-latest
    steps:
      - name: Build
        run: |
          make && make test
      - name: Publish Documentation
        run: |
          scripts/publish.sh
        env:
          PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
        if: github.repository == 'ethomson/project' && github.event_name == 'push'

现在,当此工作流在fork中运行时,将跳过“发布文档”步骤。

在这里插入图片描述

使用条件语句使你可以构建可在分支或分支之间共享的高级工作流,但其中某些步骤是针对特定触发器或环境量身定制的。

矩阵条件

GitHub Actions 具有许多强大的组件,但是当你开始一起使用它们时,事情就开始变得真正强大。例如:矩阵工作流使你可以轻松地将简单的工作流扩展到多个不同的作业。通过条件执行,你可以限制作业中步骤的执行。

这两个功能很自然地结合在一起──当你跨不同的操作系统,平台或语言版本构建矩阵时,可能只需要在该矩阵的一个子集上运行一些步骤。例如:在Linux上运行时,可能需要安装其他编译器,或者对于不同的操作系统,可能需要安装稍有不同的依赖项。

我可以结合一些以前的概念来为我的一个项目(C语言中的系统库)构建工作流。它将使用跨平台工具安装矩阵工作流来执行CI的构建和测试步骤。

目标是安装Ninja构建系统,然后使用CMake创建构建脚本以利用这一优势──CMake和Ninja可以很好地协同工作,以生成快速,跨平台的本机构建。最后,我们将使用 cmake 进行构建,并使用 ctest 进行测试。

name: Build with CMake and Ninja

on: [push]

jobs:
  build:
    strategy:
      matrix:
        os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
    runs-on: ${{ matrix.os }}

    steps:
    - name: Install Dependencies (Linux)
      run: sudo apt-get install ninja-build
      if: matrix.os == 'ubuntu-latest'
    - name: Install Dependencies (Windows)
      run: choco install ninja
      if: matrix.os == 'windows-latest'
    - name: Install Dependencies (macOS)
      run: brew install ninja
      if: matrix.os == 'macos-latest'
    - name: Get Sources
      uses: actions/checkout@v1
    - name: Setup CMake
      run: |
        mkdir "${{ runner.workspace }}/build"
        cd "${{ runner.workspace }}/build"
        cmake $GITHUB_WORKSPACE -GNinja
      shell: bash
    - name: Build
      run: cmake --build .
      working-directory: ${{ runner.workspace }}/build      
    - name: Test
      run: ctest -V
      working-directory: ${{ runner.workspace }}/build

运行此命令时,条件将确保仅对特定平台运行适当的“安装依赖项”步骤。其他平台的其他步骤将被跳过。

在这里插入图片描述

现在,我们开始了解如何将GitHub Actions的简单片段组合到更复杂,功能更强大的工作流程中。

在步骤之间共享数据

在 GitHub Actions 的任务中,你可以有多个步骤 ,一个接一个地运行。每个步骤可能是调用一个操作(例如,检出存储库中的代码安装特定版本的Node.js),也可能是一个 run,仅运行你提供的脚本的步骤。

但是通常你希望与之前执行的步骤进行交互,例如,你可能希望运行一个步骤来更新软件的版本号,以使其准备好发布。然后,你可能需要在实际的发布步骤中使用该版本号。

但是,如何来回获取这些数据?GitHub Actions在其自己的流程中运行你的每个步骤。这意味着你不能只在一个步骤中设置环境变量,然后在另一步骤中引用它。换句话说,这将无法正常工作:

steps:
  # 这将 **无效**。这两个 `run` 步骤被编写为
  # 作为不同的脚本并由不同的shell运行,因此
  # `FOO` 变量将不会在它们之间持久存在。
  - run: export FOO=bar
  - run: echo $FOO

但是,GitHub Actions 确实为你提供了将数据持久保存在执行环境中的工具。你可以通过写入标准输出(即,仅使用echo)来向GitHub Actions编写命令──包括指示 GitHub Actions 在后续运行步骤中设置环境变量的命令

在当前shell中设置环境变量之后,可以对GitHub Actions 使用命令 set-env ,这将是环境变量被注入到以后的步骤中:

steps:
  # 这将会在第一个 `run` 脚本中设置 `FOO` 环境变量。
  # 然后指示 GitHub Actions 在随后的运行步骤中使其可用。
  - run: |
      export FOO=bar
      echo "::set-env name=FOO::$FOO"
  - run: echo $FOO

现在,实际上可以在后续步骤中获取环境变量 FOO 中的数据。

GitHub Actions将这些步骤作为单独的脚本运行──这意味着在单独的Shell调用中运行并每次都获得原始环境。但是,使用GitHub Actions平台内的开发工具,你可以在调用之间共享数据。

共享数据的条件

昨天,我们研究了如何在工作流步骤之一中设置自定义数据,以便在后续步骤中使用。我们通过向env上下文添加数据来做到这一点,它是一个你可以读写的属性包。

但是你不必将自己局限于仅在你的步骤中使用 env 上下文。你还可以在工作流本身中使用 env 上下文,并根据在先前步骤中设置的数据来设置条件

例如,你可能有一个每天要运行的工作流,并且你希望对该工作流在星期一的运行方式进行较小的修改。你可以使用 schedule 触发器每天运行工作流程。你可以复制该工作流程,并添加只希望在星期一运行的特殊更改。但是,呵呵,维持两个相似但只有一点点不同的工作流程是一个严重的难题。

取而代之的是,你可以查看星期几并在此基础上设置一个环境变量──在这里,我将使用bash语法运行 date 命令以打印缩写的星期几,并将其放入我的 echo 语句中,将 DAY_OF_WEEK 在我们的 env 上下文中设置变量 。然后,我将其 env.DAY_OF_WEEK 作为后续步骤的条件。

name: CI

on:
  schedule:
    - cron: 0 5 * * *

jobs:
  build:
    runs-on: [ubuntu-latest]
    steps:
    - run: echo "::set-env name=DAY_OF_WEEK::$( date +%a )"
    - run: echo "Somebody has a case of the mondays!"
      if: env.DAY_OF_WEEK == 'Mon'
    - run: echo "This runs every day..."

使用此配置,我将每天在世界标准时间05:00运行工作流。与今天一样,在星期一,将运行仅星期一的步骤。
在这里插入图片描述

但是在本周的剩余时间里,该步骤将被跳过。

在这里插入图片描述

这是另一个很好的例子,说明GitHub Actions如何为你提供简单的原语,你可以将它们组合在一起以创建功能强大的工作流。

依赖作业

如果你设置了包含多个作业的工作流程(无论是基于矩阵的工作流程还是只是单独定义了作业),这些作业将彼此独立地并行运行。通常,这是理想的。只要有可用的计算机即可执行你的作业。

但是有时你希望能够设置依赖于其他作业的作业。例如,你可能有一些要测试的服务。但是为了节省成本,你只想在实际运行测试时运行那些服务。因此,你可能想要一个启动服务的作业,一个运行测试的工作业,然后是一个停止服务的作业。

要指定作业之间的依赖关系,可以使用 needs 关键字指示哪些作业依赖于其他作业的完成。

name: CI

on: [push]

jobs:
  setup:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - run: ./setup_test_infrastructure.sh
  build:
    needs: setup
    runs-on: 'ubuntu-latest'
    steps:
      - uses: actions/checkout@v1
      - run: |
          ./build.sh
          ./test.sh
        shell: bash
  shutdown:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - run: ./shutdown_test_infrastructure.sh 

现在,这似乎不是一个很好的例子–我们可能不使用单独的作业,而可能只在一个作业中完成了这三个步骤。但是使用作业可以使我们“成长”:实际上,我们可以在一个作业中设置测试基础结构,然后并行运行多个作业以对其进行测试,然后最后运行清理作业。

在这里插入图片描述

这样一来,我们就可以在多个平台上并行运行测试作业,并通过设置将这些作业预定下来,然后停止作业。我们可以通过定义我们的安装作业,然后定义依赖于它的许多作业,然后依赖于这些作业的最终的工作。这通常称为“扇出”和“扇入”。

name: CI

on: [push]

jobs:
  setup:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - run: ./setup_test_infrastructure.sh
  build:
    needs: setup
    runs-on: ${{matrix.os}}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
    steps:
      - uses: actions/checkout@v1
      - run: |
          ./build.sh
          ./test.sh
        shell: bash
  shutdown:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - run: ./shutdown_test_infrastructure.sh 

通过此工作流程,我们的设置作业将运行,然后将使用矩阵在Windows,macOS和Linux上运行构建和测试作业,最后,我们将关闭启动的那些测试资源。

在这里插入图片描述

你可以通过相互指定作业来轻松地构建高级工作流, needs 以指定工作流的依赖关系图。

文件

当你构建执行pull request验证或持续集成构建的工作流时,你通常希望获取该构建输出并保存它,以便以后使用。有时创建一个软件包并将其发布到GitHub packages之类的软件包仓库中是有意义的 。但是有时你只想将其存储为构建输出的一部分,以后可以下载。GitHub Actions允许你将文件上传为工作流的一部分,以供日后下载。

要将文件作为构建的一部分进行上传,可以使用 upload-artifact 操作。你可以指定为其创建文件的路径–你可以指定单个文件或文件夹,以及文件的名称。你指定的路径将以你指定的工件名称存档到一个zip文件中。

例如,我可以构建和测试我的项目,然后创建一个nuget包,最后将该nuget包作为文件上传。

name: CI

on: [push]

jobs:
  build:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v1
      name: 'Checkout'
    - uses: actions/setup-dotnet@v1
      with:
        dotnet-version: '3.0.100-preview3-010431'
      name: 'Setup .NET Core 3'
    - run: |
        dotnet restore
        dotnet build --no-restore --configuration Release
        dotnet test Tests.csproj --no-build --configuration Release
        mkdir ${{ github.workspace }}/package
        dotnet pack --no-build -c Release --output "${{ github.workspace }}/package"
    - uses: actions/upload-artifact@v1
      with:
        name: nuget
        path: ${{ github.workspace }}/package
      name: 'Upload Package'

现在,当我的工作流程运行时,我将在该运行的右上角获得一个选项,向我展示我的文件并让我下载它们。

在这里插入图片描述

将构建输出作为文件上载可以与包仓库一起使用:我喜欢将CI构建包上载到GitHub packages,并从pull request中创建工件。这使我可以选择在本地运行和测试PR验证构建──我可以将它们作为文件下载──而不会影响我的GitHub Packages帐户。如果你希望选择在本地运行,那很好,即使你很少这样做。

下载文件

昨天,我们研究了如何在工作流运行过程中上传文件,然后手动下载它们。这在许多情况下都非常有用,但是我认为使用文件的更强大的部分是使用工件在不同步骤之间传输文件。

例如:你可能有一个项目,该项目在多个平台上创建二进制文件,将这些二进制文件作为文件上载,然后发布到最后运行作业以将这些不同的二进制文件聚合到一个程序包中。

或者,你可能想散开──拥有一个创建单个文件的作业,然后在不同平台上运行多个作业以测试该文件。

在这里,我有一个测试我的本机代码的工作流程:首先,我构建本机代码测试运行器,该运行器使用 clar 单元测试框架,以便它编译一个以 testapp 命名的包含我所有单元测试的二进制文件。该二进制文件作为名为的文件上传 tests。然后,我将创建一个依赖于第一个build 作业的矩阵作业。它将使用最新版本的Ubuntu,Debian,CentOS和Alpine建立一个在容器内执行的矩阵。每个作业将下载 tests 构建作业中生成的文件,然后将设置 testapp 为可执行文件(因为文件不保留Unix权限),最后运行测试应用程序。

name: CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Build
      run: make testapp
    - uses: actions/upload-artifact@v1
      with:
        name: tests
        path: testapp

  test:
    needs: build
    strategy:
      matrix:
        container: ['ubuntu:20.04', 'debian:buster', 'centos:8', 'alpine:3']
    runs-on: ubuntu-latest
    container: ${{matrix.container}}
    steps:
    - uses: actions/download-artifact@v1
      with:
        name: tests
    - name: Run Tests
      run: chmod 0755 tests/testapp && tests/testapp

当我运行它时,构建将产生一个文件,并且当该构建完成时,我的测试作业将全部开始,下载该文件,然后运行它。

在这里插入图片描述

你可以看到,上传文件对于生成构建输出非常有用,你可以在后续构建步骤中下载和使用这些输出。

容器服务

很难低估容器在DevOps实践中的重要性。通常,你会将容器部署到生产环境中──因此很自然地开始使用容器进行本地开发,并管理依赖项。我们研究了如何利用它在容器内部进行构建。但是,我们也可以使用容器服务,将正在运行的容器用作构建和测试工作流程的一部分。

你通常需要运行一些与其他服务(通常是数据库)进行通信的集成测试。你可以通过编写 docker run 命令来拉下容器,启动容器并映射必要的端口,从而编写脚本,但这在最佳情况下很烦人。而且,如果你要在容器中进行构建,则自己运行docker会变得非常棘手。

使用容器服务可以使GitHub Actions基础架构为你执行。你只需指定容器和要映射的任何端口,它将在作业开始时启动服务容器,并使该容器可用于作业中的步骤。

services:
  redis:
    image: 'redis:latest'
    ports:
    - 6379/tcp

这将启动 redis:latest 容器并将容器中的端口6379映射到虚拟机运行程序上的端口。这等同于运行 docker run redis:latest -p 6379/tcp,就像你要运行该命令一样,映射到本地运行程序上的端口不是确定性的。GitHub Actions可在job.services上下文中提供此信息。

你可以查看 $ 以标识本地端口号。(就像运行 docker run 一样,你还可以指定容器端口和本地端口,例如 6379:6379,将容器端口6379映射到本地端口6379。)

将其放入工作流中,如果我有一个 与Redis对话的 Node 脚本,并连接到 REDIS_HOST 环境变量所指定的Redis主机的 `REDIS_PORT 端口,那么我可以创建一个工作流,该工作流启动Redis容器并运行Node脚本。

name: Redis Service Example

on: push

jobs:
  talk-to-redis:
    runs-on: ubuntu-latest

    services:
      redis:
        image: redis
        ports:
        - 6379/tcp

    steps:
    - uses: actions/checkout@v1

    - run: npm ci
      working-directory: ./redis

    - run: node client.js
      working-directory: ./redis
      env:
        REDIS_HOST: localhost
        REDIS_PORT: ${{ job.services.redis.ports[6379] }}

你可以使用服务容器来启动服务,例如 Redis, PostgreSQL 或MySQL甚至是Selenium。服务容器的执行使工作流中的这些容器的执行和交互变得更加容易。

原文:https://qiwihui.com/

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GitHub Actions是GitHub的持续集成服务,它可以帮助开发者通过自动化的构建、发布和测试来验证代码,从而尽快发现集成错误。\[2\]GitHub Actions由多个操作组成,比如抓取代码、运行测试、登录远程服务器、发布到第三方服务等等,这些操作被称为actions。一个workflow是一次持续集成的运行过程,由一个或多个jobs构成,每个job又由多个steps构成,每个step可以执行一个或多个命令(action)。\[3\] GitHub Actions允许开发者把每个操作写成独立的脚本文件,存放到代码仓库,使得其他开发者可以引用该脚本,这个脚本就是一个Action。开发者可以从GitHub社区共享的官方市场查找需要的Action,也可以自己编写Action并开源供其他人使用Action可以通过指定commit、标签或分支来引用不同的版本。\[1\] 在使用GitHub Actions之前,需要了解持续集成/持续交付的概念、Git相关知识、Linux/Windows/macOS脚本相关知识以及Yaml基础语法。Yaml是一种用于配置文件的简洁易读的数据序列化格式。\[2\] GitHub Actions提供了Linux、Windows和macOS虚拟机来运行工作流程,也可以在自己的数据中心或云基础架构中托管自己的自托管运行器。通过在代码仓库中的.github/workflows目录下创建.yml文件,可以配置自动触发的工作流程。\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [GitHubActions详解](https://blog.csdn.net/unreliable_narrator/article/details/124468384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Github Actions](https://blog.csdn.net/SeriousLose/article/details/121476152)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值