概述

​ GitHub Actions 是一个持续集成和持续交付(CI/CD)平台,允许您自动化构建、测试和部署流水线。您可以创建工作流来构建和测试存储库中的每个请求,或者将合并的请求部署到生产环境中。

​ 很多操作在不同项目里面是类似的,完全可以共享。GitHub 注意到了这一点,想出了一个很妙的点子,允许开发者把每个操作写成独立的脚本文件,存放到代码仓库,使得其他开发者可以引用。

​ 如果你需要某个 action,不必自己写复杂的脚本,直接引用他人写好的 action 即可,整个持续集成过程,就变成了一个 actions 的组合。这就是 GitHub Actions 最特别的地方。

​ GitHub 做了一个官方市场,可以搜索到他人提交的 actions。另外,还有一个 awesome actions 的仓库,也可以找到不少 action。

上面说了,每个 action 就是一个独立脚本,因此可以做成代码仓库,使用userName/repoName的语法引用 action。比如,actions/setup-node就表示github.com/actions/setup-node这个仓库,它代表一个 action,作用是安装 Node.js。事实上,GitHub 官方的 actions 都放在 github.com/actions 里面。既然 actions 是代码仓库,当然就有版本的概念,用户可以引用某个具体版本的 action。下面都是合法的 action 引用,用的就是 Git 的指针概念,详见官方文档

1
2
3
actions/setup-node@74bc508 # 指向一个 commit
actions/setup-node@v1.0 # 指向一个标签
actions/setup-node@master # 指向一个分支

GitHub Actions 组件

1.Workflows 工作流

​ 工作流是一个可配置的自动化流程,它将运行一个或多个作业。工作流是由签入存储库的 YAML 文件定义的,并且在由 repository 中的事件触发时运行,或者可以手动触发,或者按照定义的时间表运行。

​ 工作流在.github/workflows 目录中定义, 并且存储库可以有多个工作流,每个工作流可以执行不同的任务集。例如,您可以使用一个工作流来构建和测试拉请求,使用另一个工作流在每次创建发行版时部署您的应用程序,还可以使用另一个工作流在每次有人打开新问题时添加标签。

2.Events 事件

​ 事件是存储库中触发工作流运行的特定活动。例如,活动可以来自 GitHub 创建请求(pull request)、打开问题(open an issue)或向存储库提交(push an commit)。您还可以通过向 REST API 发布或手动触发按计划运行的工作流。

3.Jobs 作业

​ 作业是工作流中在同一运行程序上执行的一组步骤。每个步骤要么是将要执行的 shell 脚本,要么是将要运行的操作。步骤按顺序执行,并相互依赖。由于每个步骤都在同一个运行程序上执行,因此可以将数据从一个步骤共享到另一个步骤。例如,您可以有一个生成应用程序的步骤,然后有一个测试生成的应用程序的步骤。

4.Actions 动作

​ 动作是 GitHub Actions 平台的自定义应用程序,它执行复杂但经常重复的任务。使用一个操作来帮助减少在工作流文件中编写的重复代码的数量。操作可以从 GitHub 获取 git 存储库,为构建环境设置正确的工具链,或者为云提供商设置身份验证.

GitHub Marketplace · Actions to improve your workflow · GitHub

5.Runners 运行器

​ 运行器是在工作流被触发时运行它们的服务器。每个运行器可以一次运行一个作业。GitHub 提供 Ubuntu Linux、 Microsoft Windows 和 macOS 运行程序来运行您的工作流; 每个工作流运行在一个全新的、新配置的虚拟机中执行。GitHub 还提供了更大的运行器,可以进行更大的配置。

Context 上下文

具体可看 Contexts - GitHub Docs

概念

Context 上下文就是工作流各个步骤的信息。例如env.sha,就是自己设置的环境变量里面的sha变量。

Context 上下文的种类

上下文种类和工作流步骤相关

共有十一种:

github、env、job、jobs、steps、runner、secrets、strategy、matrix、needs、inputs

访问上下文

你可以使用表达式语法访问上下文:

${{.}}${{[attribute]}}

secrets上下文

secrets可以通过仓库里的设置栏Actions选项进行设置。

image-20230126194551856

工作流示例

1.创建文件目录

在仓库中,创建.github/workflow/目录来存储工作流文件。

image-20230126194744665

2.配置工作流文件

主要工作流文件
用于触发的工作流、对照下面的可复用工作流

deploy-project.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 工作流名称
name: Deploy Project


# 工作流触发设置
on:
# push进入仓库时触发
push:
# 分支条件设置 之前是使用的master
branches:
- main

# 工作流作业
jobs:
# 作业名称
deploy-project:
# 使用可复用工作流
# 也可以通过GitHub仓库引用自己或其他人的工作流
uses: ./.github/workflows/deploy.yml
# 使用策略复用工作流,例如它会并发执行project-name为vblog-server-admin、
# vblog-server-portal、vblog-server-search 的作业,
strategy:
# 矩阵,就是搭配出各种可能,依次复用,可以有多维矩阵
matrix:
# 矩阵的一行,行名称用于引用(可以有多行,多列)
project-name: [ vblog-server-admin, vblog-server-portal, vblog-server-search ]
# 发送过去的普通属性
with:
# 引用上面的矩阵
project-name: ${{ matrix.project-name }}
# 秘密,秘密可以在仓库中设置,可复用工作流要获取秘密属性,只能通过这里传播过去之后获取
secrets:
# server-host是自定义的秘密名,后面为引用仓库的秘密
server-host: ${{ secrets.SERVER_HOST }}
mysql-root-password: ${{ secrets.MYSQL_ROOT_PASSWORD }}
jwt-secret: ${{ secrets.JWT_SECRET }}
elastic-password: ${{ secrets.ELASTIC_PASSWORD }}
docker-username: ${{ secrets.DOCKER_USERNAME }}
docker-password: ${{ secrets.DOCKER_PASSWORD }}

可复用工作流文件
可复用工作流顾名思义就是可以复用的工作流、对照上面的主工作流

官方可复用工作流平台

能用平台上面的可复用工作流就用平台上面的可复用工作流。

deploy.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 工作流名称
name: Deploy

# 设置触发条件
on:
# 说明该工作流为可复用工作流(可被其他工作流引用)
workflow_call:
# 定义参数,就和函数参数一样
# function inputs(string project-name){}
inputs:
# 自定义参数名
project-name:
# 设置是否必须
required: true
# 类型(必要)
type: string
# 安全参数,只能
secrets:
# 自定义参数名
server-host:
# 是否必须
required: true
mysql-root-password:
required: true
jwt-secret:
required: true
elastic-password:
required: true
docker-username:
required: true
docker-password:
required: true
# 工作流作业
jobs:
# 自定义作业名称
check-update:
# 运行时名称
name: Check if the project is updated
# 运行的操作系统
runs-on: ubuntu-latest
# 其他作业能从该作业获取的变量设置
outputs:
# 自定义变量, 该变量为步骤2输出的 'is_update' 变量
is_update: ${{ steps.step2.outputs.is_update }}
# 设置步骤名称
steps:
# 步骤 id 用于上面的outputs
- id: step1
# 步骤名
name: Check out the repository
# 复用其他仓库的工作流 "actions/checkout",该工作流的作用是拉取最近仓库的代码
uses: actions/checkout@v3
# 设置输入到复用工作流属性
with:
# 拉取仓库的深度,这是 "actions/checkout" 工作流规定的
fetch-depth: 2
# 步骤 id 用于上面的outputs
- id: step2
# 步骤名
name: Check out project update
# 在设置的操作系统的 shell 或 bash 上运行脚本,该脚本的功能是检测传入项目是否更新
run: |
if [ -n "$(git diff HEAD^ -- ${{ inputs.project-name }})" ];
then
echo "is_update=true" >> $GITHUB_OUTPUT
fi
# 自定义作业名称
push-to-docker-registry:
# 依赖 check-update, 只有check-update 运行完才开始启动
needs: check-update
# 运行时名称
name: Build, test and push docker image to docker hub
# 运行的操作系统
runs-on: ubuntu-latest
# 运行条件,这里使用了上面作业输出的 is_update变量
if: ${{ needs.check-update.outputs.is_update == 'true' }}
# 设置步骤名称
steps:
# 使用可复用工作流,拉取最新代码
- name: Check out the repo
uses: actions/checkout@v3
# 使用可复用工作流,安装JDK17
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
# 验证gradle包是否错误
- name: Checkout gradle
uses: gradle/wrapper-validation-action@v1
# 安装Gradle
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
# 运行Gradle进行构建
- name: Run build with Gradle wrapper
# 设置进行构建时的环境变量,环境变量会输入运行操作系统的环境变量中
env:
# 这里通过主工作流输入的秘密设置环境变量
SERVER_HOST: ${{ secrets.server-host }}
MYSQL_ROOT_PASSWORD: ${{ secrets.mysql-root-password }}
JWT_SECRET: ${{ secrets.jwt-secret }}
ELASTIC_PASSWORD: ${{ secrets.elastic-password }}
run: |
./gradlew :${{ inputs.project-name }}:build;
# 上传构建完成后的报告
- name: Upload build reports
uses: actions/upload-artifact@v3
with:
name: build-reports
path: build/reports/
# 登陆Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.docker-username }}
password: ${{ secrets.docker-password }}
# 获取Docker tags和 labels
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ secrets.docker-username }}/${{ inputs.project-name }}
# 通过上面步骤获取的tags和labels构建docker 镜像
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: ./${{ inputs.project-name }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

3.推送代码,工作流自动运行

4.查看工作流

​ 当您的工作流被触发时,将创建一个执行该工作流的工作流运行。工作流运行开始后,您可以看到运行进度的可视化图表,并在 GitHub 上查看每个步骤的活动。

image-20230126195419858

image-20230126195442050

例子

打包React项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
name: 打包React项目
on: push

permissions:
contents: write

jobs:
npm-build:
name: npm-build工作
runs-on: ubuntu-latest

steps:
- name: 读取仓库内容
uses: actions/checkout@v4

- name: 安装依赖和项目打包
run: |
npm install
npm run build

- name: 部署
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: gh-pages
folder: build

构建镜像并推送到Docker Hub

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
name: 构建镜像并推送到Docker Hub
on: push

permissions:
contents: write

jobs:
docker-build:
name: docker-build工作
runs-on: ubuntu-latest

steps:
- name: 读取仓库内容
uses: actions/checkout@v4

- name: 登录Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: 构建镜像并推送镜像
uses: docker/build-push-action@v5
with:
push: true
tags: ${{ github.repository }}:latest

参考

  1. GitHub Actions文档 - GitHub Docs
  2. GitHub Marketplace · Actions to improve your workflow · GitHub