GitHub Actions 是 GitHub 官方推出的持续集成和持续交付(CI/CD)平台,可以让用户便捷实现自动化构建、测试和部署流程。
关于 GitHub Actions
GitHub Actions 有几个概念(workflow、event、job、action、step、runner),下面会简单介绍常用的workflow、job、step的使用。
workflow (工作流程)
workflow 是可配置的自动化流程,可以运行一个或多个job。workflow 由仓库 .github\workflows
目录下的 yaml 文件定义。每个项目可以有一个或多个workflow。下面是一个简单的webpack构建的流程:
name: webpack
on:
workflow_dispatch:
push:
tags:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- name: Build
id: build
run: |
npm install
npm run build
Workflow文件语法特别多也比较复杂,详细参考官方文档 Workflow syntax for GitHub Actions,一般我们需要使用下面的几个字段的定义。
(1) name
name
workflow的名称,可为空默认是workflow文件的名称,配置示例如下:
name: 'workflow name'
(2) on
on
指定触发workflow的条件,配置示例如下:
on:
workflow_dispatch:
push:
tags:
- '*'
上面的示例表示 手动触发(workflow_dispatch) 和 任意tag push的时候触发,更多触发条件,可以参考官方的文档 Triggering a workflow
(3) jobs
1) jobs..name
name
表示任务的名称,可以不填
jobs:
job1:
name: job1
job2:
name: job2
2) jobs..needs
needs 指定当前任务的依赖关系,可以通过设置needs来控制job的运行顺序。示例代码如下:
jobs:
job1:
name: job1
job2:
name: job2
needs: job1
job3:
name: job3
needs: [job1, job2]
上面代码表示任务按照 job1 > job2 > job3 的顺序执行。
3) jobs..runs-on
runs-on 必填字段,表示当前指定的运行环境。目前支持的环境如下:
- ubuntu-latest 或 ubuntu-20.04、ubuntu-22.04
- windows-latest 或 windows-2019、windows-2022
- macos-latest 或 macos-14、macos-13
更多配置和环境说明可以参考官方文档。About GitHub-hosted runners
不同的任务可以使用不同环境,比如部分跨平台的项目可以在各自平台的宿主容器上面单独编译,示例代码如下:
jobs:
job1:
runs-on: ubuntu-latest
job2:
runs-on: windows-latest
job3:
runs-on: macos-latest
4) jobs..steps
steps 指定每个job下运行的步骤,可以有一个或多个step。step参数定义:
- jobs.
.steps.name: 步骤名称 - jobs.
.steps.id: 步骤ID - jobs.
.steps.uses: 使用的action,如actions/checkout@v4,表示用户actions的checkout 库 的v4 tag - jobs.
.steps.env: 步骤需要的环境变量 - jobs.
.steps.run: 步骤上运行的命令 - jobs.
.steps.with: action需要的参数
示例代码如下:
jobs:
build:
runs-on: ubuntu-latest
env:
FIRST_NAME: Mona
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: npm
- name: My first step
uses: actions/hello_world@main
with:
first_name: Mona
middle_name: The
last_name: Octocat
- name: Print a greeting
env:
MY_VAR: Hi there! My name is
FIRST_NAME: Mona
MIDDLE_NAME: The
LAST_NAME: Octocat
run: |
echo $MY_VAR $FIRST_NAME $MIDDLE_NAME $LAST_NAME.
定制 GitHub Actions
GitHub 官方提供了一个插件市场(Marketplace),可以在里面找到其他人开发的actions,基本上你需要的功能都可以在上面找到。
但是有些时候没有合适的action我们可以考虑创建自己的action。GitHub官方也非常贴心提供了一个体验课程《Creating actions》开发一个专属的action。
目前支持创建 Docker/Javascript/Composite Actions 三种 action, 下面以一个实际的例子来介绍如何开发一个Javascript action。
1、创建
GitHub 官方提供两个模板工程 typescript-action、javascript-action,在创建的时候可以选择。
点右上角的 Use this template
可以快速创建一个项目仓库
2、开发
需要开发一个action实现将编译产物上传到upyun的功能,要求支持上传多个文件。使用upyun官方提供的npm库实现。
npm install upyun --save
npm install @types/upyun --save-dev
(1) 定义 action 描述文件
每个 action 的输入输出定义在 action.yml 文件中,下面是示例代码:
name: 'upyun-deploy-action'
description: 'GitHub Actions upyun deploy'
author: 'zengjing'
# Define your inputs here.
inputs:
path:
description: 'input path parameters'
required: true
# Define your outputs here.
outputs:
result:
description: 'output result'
runs:
using: node20
main: dist/index.js
(2) 获取输入参数
import * as core from '@actions/core'
export interface UploadInputs {
srcPath: string
destPath: string
}
export function getInputs(): UploadInputs[] {
const path = core.getInput(Inputs.Path, { required: true })
const lines = path.split(/[\s\n]/)
const inputs: UploadInputs[] = []
for (const line of lines) {
const items = line.split('->')
if (items.length === 2) {
const srcPath: string = items[0].trim()
const destPath: string = items[1].trim()
const input = { srcPath: srcPath, destPath: destPath } as UploadInputs
inputs.push(input)
}
}
return inputs
}
(3) 上传文件
import * as core from '@actions/core'
export interface UploadOutputs {
srcPath: string
destPath: string
result: boolean
}
export function uploadArtifacts(inputs: UploadInputs[]): UploadOutputs[] {
const results: UploadOutputs[] = []
for (const input of inputs) {
core.info(`Start to upload artifact from ${input.srcPath} to ${input.destPath}`)
try {
const result = await uploadArtifact(input.srcPath, input.destPath)
results.push({ srcPath: input.srcPath, destPath: input.destPath, result: result })
} catch (e) {
results.push({ srcPath: input.srcPath, destPath: input.destPath, result: false })
}
}
return results
}
(4) 输出结果
import * as core from '@actions/core'
// Set outputs for other workflow steps to use
core.setOutput('result', JSON.stringify(results))
(5)发布
npm run bundle
打包完成后提交代码,项目根目录下面有个 script\release
这个脚本可以创建tag并发布。
3、使用
因为上传到upyun需要三个配置 service/operator/password,在代码里面是通过环境变量获取的
需要先在项目设置里面配置 (Settings -> Security -> Secrets and variables -> Actions),点 New repository secret
添加Secrets。
在workflow添加step:
- name: Upload
uses: hhtczengjing/upyun-deploy@v1
env:
UPYUN_SERVICE_NAME: $
UPYUN_OPERATOR: $
UPYUN_PASSWORD: $
with:
path: |
version.json->/versions/products
package.json->/versions/products
最终的代码在:https://github.com/hhtczengjing/upyun-deploy.git