云萧的咕咕屋

以万象之不息,致不息之万象

博主头像
云萧是个咕咕怪
大一狗,在前端路上奋斗的人类
18
文章
4
分类
7
标签
本页内容

GitHub Actions上手全指南
GitHub Actions上手全指南
什么是 GitHub Actions? 如果项目需要编译、打包后才能变成能够被执行的可发行的软件,通常项目会需要一个 CI(Continuous Integration,即持续集成
2024-02-05 11 分钟 4327 字 折腾

什么是 GitHub Actions?

如果项目需要编译、打包后才能变成能够被执行的可发行的软件,通常项目会需要一个 CI(Continuous Integration,即持续集成)环境,以在特定事件(如一次提交或者 PR)之后,实时对项目进行编译、打包。

比如有些软件的 Nightly 或 Canary 版,甚至每提交一次 push 就自动构建一个版本,这样的版本实际上就是 CI 版啦。

以往多数人会选择使用 Jenkins 等框架在本地或者私有服务器上部署,或者通过 Travis CI、CircleCI 等平台实现云端 CI。作为全球最大的代码托管库,GitHub 相应地也自己也推出了 CI/CD 服务,即 GitHub Actions。

快速上手

如果你的项目的 CI 要跑的命令很大众,无需过多自定义规则或配置,那就可以直接到官方的插件市场,找别人造好的轮子,导入进你的项目,大功告成!

慢速上手

创建工作流

通常一个大型项目会同时拥有好几个工作流(即 workflow),像编译应用、评论审批、编译特定组件之类的工作,多是每一个工作由单独的工作流完成。而我们的小型项目最多也就编译打包下 App,一个工作流足矣。

由于 Actions 的工作流使用 YAML 文件进行配置,所以你需要了解一些基本的 YAML 前置常识。当然看不全懂没关系啦,只要有一点了解就行。

给工作流起好一个名字,在项目根目录下创建目录.github/workflows,然后在该目录创建相应的 yml 配置文件。

如图配置,当我们在向项目 push 一个 commit 的时候,就会启动这个工作流。按照预期,GitHub 会请求自己托管的专用于 Actions 环境的服务器(即 runner),来执行该工作流的内容。

打开导航栏的 “Actions” 一项,打开刚刚请求的工作流,在 “test” 流程的 “test01” 步骤里,控制台中果然输出了 “Hello, world!” 这段字符串。

设置名称和触发条件

name 字段是这个工作流的实际名称,用处似乎就是区分不同的工作流而已ᕕ(ᐛ)ᕗ

on 字段用于设置该工作流执行的触发条件,常见的有:pushpull_requestissue_commentrelease 等。

# 当 push commit 时触发工作流
on: push
 
# 当 push 到 dev 和 main 分支时触发工作流
on: 
   push:
      branches: [dev, main]
 
# 当 push commit 或新增 PR 时都触发工作流
on: [push, pull_request]
 
# 手动触发工作流
on: workflow_dispatch

配置工作流程

在 jobs 字段中,每一个流程都是独立的,只有数据可以进行迁移(稍后会谈),所以我们需要单独为每个流程设定相关配置。

runs-on 字段用于规定该流程运行的操作系统。一般情况下咱顶多使用以下三个值之一 ——windows-latestubuntu-latestmacos-latest——用于编译不同操作系统下的二进制文件。

接下来就是各个步骤(即 steps 字段)的内容!按照之前咱放的示例图,咕咕自己习惯将每个步骤开头冒号前的内容,叫做这个步骤的 “步骤 ID”,它是独一无二的,相当一个代表这个步骤的变量。

进入到具体的步骤中,首先是 name 字段,它能让每个步骤都有一个用于在 Actions 页面直观展示的名称。

其次就是 id 字段,一般推荐用小写字母 + 短横线连字符的方法命名,用于后面的数据交互!

最后就是 run 字段,就和咱在控制台上敲命令一样了,打根竖线再提行,一行写一个命令。

好嘞,完工!

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: 'Test Output'
      id: test-output
      run: |
        echo 'Hello, world!'

在某个步骤使用他人创建的 Actions 仓库

打个比方,咱跑前端项目需要设置好 Node.js 环境,但从下载 Node 二进制包到完成部署,即使在实际操作中也不可能不繁琐,更何况 Actions 这种需要盲打命令的情况。既然所有工作不可能全部手撸,能重复利用轮子的地方还是多多利用轮子的好!

所以 Actions 为我们提供了使用他人 Actions 仓库的功能。在步骤中,通过 uses 字段代替原有的 run,咱就能使用他人仓库的 Actions 脚本,写得就更快,写出来的配置文件就更加简洁易懂。

# 将项目源码 clone 到本地
- name: 🧐 Checkout
  id: checkout
  uses: actions/checkout@main
  with: 
    fetch-depth: '0'
 
# 部署 Node.js 环境
- name: 🛠️ Setup Node.js Environment
  id: setup-node
  uses: actions/setup-node@v4
  with: 
    node-version: latest

如上述示例,uses 字段中填写的应该是 GitHub 的项目,格式为 “项目拥有者 / 项目名称”,同时需要用 “@” 符号指定要执行哪一个分支或标签上的脚本,查看相关 Actions 脚本仓库的分支 / 标签填入即可。

同时,如上述 setup-node 脚本需要传入 node-version 参数才能正常执行,所以咱需要通过 with 字段来传递参数。

checkout 就相当于 git clone 的封装,故 fetch-depth 参数可根据需要改动或去除。咕咕此处添加,是因为当深度为 0 时才能正常获取项目当前分支的 commit 数,这是项目所需要的。

既然都用上 Node.js 了,不妨测试下它是否正常运行。

// test.js   注:此文件在根目录
const v = process.versions
console.log('当前 Node.js 版本:' + v.node)
console.log('当前 v8 引擎版本:' + v.v8)
console.warn('Not hello, world!')
 
// .github/workflows/test.yml 节选
- name: 👀 Test about Node.js
  id: test
  run: |
    node test.js

完美执行!

接下来我们就可以直接写构建生产版本的命令了!

上传构建好的文件

每次运行工作流的编译 / 构建好的东西叫作产物(即 artifact),GitHub 官方提供了一个 Actions 仓库——upload-artifact,用于给我们上传本次工作流的产物。

此 Action 脚本一般有两个参数 ——namepathname 参数规定了这个上传的 artifact 会展示为什么名字,而 path 参数规定了要上传的 artifact 位于工作目录下哪一个路径,并将它打包。(注:即使这个路径指向一个文件而非文件夹,最终也是以.zip 压缩包的形式上传)

由于咱项目打包好的文件位于 dist 文件夹内,所以最终如下配置:

 - name: 🌐 Upload the build
   id: upload
   uses: actions/upload-artifact@v4
   with: 
     name: dist
     path: dist
     # 此参数为可选参数,规定产物的有效天数,过期后不可下载
     retention-days: 30

不过注意了,此处产物的大小是以原始大小计算,而非压缩后大小计算,真是莫名其妙。

多 job 信息传递

导出变量

为了在 job 中使用前一个 job 获取到的信息,这时我们就需要在 step 中先将变量导出,再在 job 的 output 字段里将该变量输出。

现在 Actions 的变量导出方式和 Linux 中一致,通过 echo 实现。比如,我们要获取当前时间并导出,则可以:

steps:
 - name: Get current time
   id: get-time
   run: |
      TIME_VAR=$(date "+%Y%m%d %H:%M:%S")
      echo "TIME_EXPORT=${TIME_VAR}" >> $GITHUB_OUTPUT

然后再在上级的 job 中通过 outputs 字段将其输出,以给其它 job 使用:

jobs: 
   # 创建 id 为 setup 的 job,以将导出的数据输出,get-time 步骤就在其中
   setup:
      name: Setup Information
      runs-on: ubuntu-latest
      outputs: 
         # get-time 是导出数据的步骤的 id,TIME_EXPORT 是导出的数据的变量名称
         TIME_OUTPUT: ${{ steps.get-time.outputs.TIME_EXPORT }}
      steps: ......

其它 job 中使用变量

Actions 允许我们在 jobs 的 env 字段中,预置该 job 中可用的变量。同样地,咱可以先从 needs 字段中接收之前的 job 输出的内容,再在 env 字段中将其设为可用的变量。

jobs:
   setup:
      ......
 
   print:
      name: Print Information
      runs-on: ubuntu-latest
      needs: setup
      env:
         # 为该 job 的运行环境添加一个名为 TIME_ENV 的变量,变量的值来自于 id 为 setup 的 job 所输出的名为 TIME_OUTPUT 的变量
         TIME_ENV: ${{ needs.setup.outputs.TIME_OUTPUT }}
      steps:  ......

接下来,我们就能在在该 job 下任一步骤中使用变量了!

steps:
 - name: Print Time
   id: print-time
   run: |
      echo ${{ env.TIME_ENV }}

那么我们就能顺利地在控制台看到时间被打印出来了👀 此时可以看到,工作流的两个 job 已经形成前后合作的关系

此时可以看到,工作流的两个 job 已经形成前后合作的关系

注:上述变量名称可以自定,不一定非要加后缀,此处加上只是为了方便辨析,如果要变量全叫同一个名字也没问题。

实例

我们一般做这样的简单项目,多 job 信息传递的最大用处就是更改产物上传所显示的名字,以达到辨别版本的目的。

首先在之前 “创建生产页面” 的 Action 的基础上,在 build 之前创建一个 id 为 setup 的 job,以获取基本信息,然后让产物的命名从基本信息中拼接而来。

setup:
    name: Setup Project Info
    runs-on: ubuntu-latest
    outputs:
       DIST_SUFFIX: ${{ steps.get-suffix.outputs.DIST_SUFFIX }}
    steps: 
     - name: 🧐 Checkout
       id: checkout
       uses: actions/checkout@v4
       with: 
          fetch-depth: '0'
 
     - name: 📙 Get Package Suffix
       id: get-suffix
       run: |
         # 获取当前版本,此处直接从 package.json 读取
         sudo apt-get install jq
         VERSION=$(jq -r '.version' ./package.json)
         # 获取 commit 数
         COMMIT_COUNT=$(git rev-list --count HEAD)
         # 获取构建日期
         BUILD_DATE=$(date "+%y%m%d")
         # 获取构建 commit head 哈希
         HEAD_SHA=$(git rev-parse --short HEAD)
         echo "DIST_SUFFIX=${TAG_NAME}-${COMMIT_COUNT}-${BUILD_DATE}-${HEAD_SHA}" >> $GITHUB_OUTPUT
 
build:
   name: Build Production Page
   needs: setup
   env:
      DIST_NAME: dist-${{ needs.setup.outputs.DIST_SUFFIX }}
   runs-on: ubuntu-latest
   steps:
      ......
 
    - name: 🌐 Upload the build
      id: upload
      uses: actions/upload-artifact@v4
      with:
         name: ${{ env.DIST_NAME }}
         path: dist
         retention-days: 60

可以看到产物名称已经变得规范ᕕ(ᐛ)ᕗ

GitHub Actions上手全指南

https://blog.crrashh.com/posts/12-github-actions-startup.html

除特殊声明转载之外,本文由博主云萧原创且非 AI 生成内容,依据 CC BY-SA 4.0 许可协议授权,若需转载请注明出处及本声明。

尚未开启评论功能,敬请期待