什么是 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 字段用于设置该工作流执行的触发条件,常见的有:push、pull_request、issue_comment、release 等。
# 当 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-latest、ubuntu-latest、macos-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 脚本一般有两个参数 ——name 和 path。name 参数规定了这个上传的 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 信息传递的最大用处就是更改产物上传所显示的名字,以达到辨别版本的目的。
首先在之前 “创建生产页面” 的 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
可以看到产物名称已经变得规范ᕕ(ᐛ)ᕗ

https://blog.crrashh.com/posts/12-github-actions-startup.html
除特殊声明转载之外,本文由博主云萧原创且非 AI 生成内容,依据 CC BY-SA 4.0 许可协议授权,若需转载请注明出处及本声明。
尚未开启评论功能,敬请期待