Github Actions—解放双手
一、前置知识
CI\CD 即:持续集成(Continuous Integration)、持续交付(Continuous Delivery)、持续部署(Continuous Deployment)。GitHub Actions 是一个持续集成和持续交付 (CI/CD) 平台,可用于自动执行构建、测试和部署管道。
最近几个月拿Github Actions写了一些CI\CD,是看别人怎么写然后边学边敲得,比如定时执行脚本、自动化博客部署、打包pip、npm等等,自动化以后甚是好用(主要是懒)!故翻文档整理一则入门笔记,本以为我精通了,一翻文档翻出了一堆,写成了进阶,主要是jobs😭文档中分好细,实际生产工作中并没用到太多,感觉比较偏,剩下的on、evn、secret都是高频且只要有一定的git基础很容易搞懂并上手,但如果你是新手文档会显得晦涩,推荐两篇快速入门:
在阅读以前应该有一些基础:git常识,yml文件书写规范,善于查阅文档
参考文档:Workflow syntax for GitHub Actions - GitHub Docs
二、文件结构
Github项目路径下创建.github/workflows/xxx.yml,每一个.yml文件对应一个workflows
基本概念:
workflow(流程):持续集成一次运行的过程,就是一个 workflow
jobs(任务):一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务
step(步骤):每个 job 由多个 step 构成,一步步完成
action(动作):每个 step 可以依次执行一个或多个命令
name
工作流名称,留空为文件名
name: hello-github-actions |
on
触发的条件:Events that trigger workflows - GitHub Docs
基本用法
# push时触发 |
对事件细分,又可以增加事件活动类型(types)和筛选器(branches、tags、paths)规定事件的触发条件
on: |
types
语法:on.<event_name>.types,定义事件活动类型
issues时,触发条件
- 创建issues
- 为issues做标签
当创建一个带两个标签的issues,则触发三个工作流
on: |
『pull_request』:branches & branches-ignore
语法:on.<pull_request|pull_request_target>.<branches|branches-ignore>
如果同时定义 branches/branches-ignore 筛选器和 paths筛选器,则工作流将只在这两个筛选器都满足条件时运行
branches与branches-ignore不能同时使用,可以使用!排除分支,当branches中使用!需要至少定义一个不带!的分支,支持glob模式(一种正则表达)
pull_request时,触发条件
releases/开头分支releases/开头-alpha结尾分支
on: |
pull_request时触发,但不包括
main分支releases/开头-alpha结尾分支
on: |
pull_request时,触发条件
releases/开头分支- 但不包括
releases/开头-alpha结尾分支
on: |
『push』:branches & tags & branches-ignore & tags-ignore
语法:on.push.<branches|tags|branches-ignore|tags-ignore>
如果仅定义 tags/tags-ignore 或 branches/branches-ignore,则工作流不会针对影响未定义的 Git ref 的事件运行。如果两者 tags/tags-ignore 或 branches/branches-ignore 均未定义,则工作流将针对影响分支或标记的事件运行。 如果你同时定义 branches/branches-ignore 筛选器和 paths 筛选器,则工作流将只在这两个筛选器都满足条件时运行
branches与branches-ignore不能同时使用, tags 与 tags-ignore 不能同时使用,可以使用!排除分支|标签,当branches|tags中使用!需要至少定义一个不带!的分支,支持glob模式(一种正则表达)
push时,触发条件
main分支releases/开头分支v2标签v1.开头的标签
on: |
push时触发,但不包括
main分支releases/开头分支v2标签v1.开头的标签
on: |
push时,触发条件
releases/开头的分支- 但不包括
releases/开头-alpha结尾的分支
on: |
『push & pull_request』:paths & paths-ignore
语法:on.<push|pull_request|pull_request_target>.<paths|paths-ignore>
如果同时定义 branches/branches-ignore 筛选器和 paths 筛选器,则工作流将只在这两个筛选器都满足条件时运行
paths 与 paths-ignore 不能同时使用,可以使用!排除标签,当paths中使用!需要至少定义一个不带!的路径,支持glob模式(一种正则表达)
push时,触发条件
- 包含
.js文件名
on: |
push时触发,但不包括
docs目录下
on: |
push时,触发条件
sub-project目录下,但不包括sub-project/docs
on: |
schedule
定时cron,推荐在线验证网站:Crontab.guru - The cron schedule expression editor
on: |
workflow
语法:on.workflow_call,调用其它工作流,但这部分没理解,也从未见过示例,先留个坑
语法:on.workflow_run.<branches|branches-ignore>:指定运行分支
仅当名为 Build 的工作流在名称以 releases/ 开头的分支上运行时,具有以下触发器的工作流才会运行
on: |
仅当名为 Build 的工作流不在名为 canary 的分支上运行时,具有以下触发器的工作流才会运行
on: |
语法:on.workflow_dispatch:手动触发
on: |
语法:on.workflow_dispatch.inputs:带表单的手动触发
# 格式 |
on: |
evn
语法:jobs.steps[*\].env,读取环境变量,其中GITHUB_TOKEN是一个特殊的变量,并不需要在仓库下『Setting->Secrets->Actions』定义的一个变量,而是工作流运行时自动创建的临时TOKEN,不需要自己配置,源自:Automatic token authentication - GitHub Docs
jobs: |
jobs
jobs表示要执行的一项或多项任务。jobs可以包含一个或多个job,这个任务可以包含多个步骤(steps)
语法:
jobs.<job_id>:jobs的唯一标识符jobs.<job_id>.name:作业名称(如果留空,则为job_id)
job_id 值为 my_first_job 和 my_second_job。默认多个job是并发执行的
jobs: |
语法:jobs.<job_id>.needs:等待前面的jobs成功完成才执行
job1 必须在 job2 开始之前成功完成,并且 job3 等待 job1 和 job2 完成
jobs: |
语法:jobs.<job_id>.if:执行条件
job3 使用 always() 条件表达式,确保始终在 job1 和 job2 完成(无论是否成功)后运行
jobs: |
语法:
jobs.<job_id>.runs-on:运行镜像,查表:Workflow syntax for GitHub Actions - GitHub Docsjobs.<job_id>.steps:作业步骤,步骤中可以包括多个命令jobs.<job_id>.steps[*].name:步骤中又分小任务,每个任务的名称,将会展示在Actionsjobs.<job_id>.steps[*].run:执行shell命令
name: Greeting from Mona |
语法:jobs.<job_id>.steps[*].if:执行条件。if可取值:Expressions - GitHub Docs
# 仅当`pull_request`时且action为`unassigned`触发 |
语法:jobs.<job_id>.steps[*].uses:这个就很有意思了,可以减少我们重复造轮子,调用别人做好的Actions。可以在GitHub Marketplace · Actions 找到需要的轮子
# 指定uses的分支、版本 |
语法:jobs.<job_id>.steps[*].shell:指定shell,默认bash
steps: |
语法:jobs.<job_id>.steps[*].with:定义变量,可以被hello_world所访问
jobs: |
语法:
jobs.<job_id>.steps[*].with.args:文档解释『Astringthat defines the inputs for a Docker container. GitHub passes theargsto the container’sENTRYPOINTwhen the container starts up』,我的理解是给docker容器启动时传入参数?第二个坑jobs.<job_id>.steps[*].with.entrypoint:覆盖Dockerfile中的ENTRYPOINT
steps: |
语法:jobs.<job_id>.steps[*].env、jobs.<job_id>.env:传入变量
steps: |
语法:
jobs.<job_id>.steps[*].continue-on-error: true:表示,此步运行失败时,工作流仍继续执行下一个任务jobs.<job_id>.steps[*].timeout-minutes:任务最大执行时间jobs.<job_id>.timeout-minutes:作业最大执行时间,默认360minjobs.<job_id>.strategy.matrix:使用矩阵策略
可以使用矩阵策略,两个操作系统会分别在三个版本下分别运行即6个作业
jobs: |
语法:jobs.<job_id>.strategy.matrix.include:include下是一个列表,如果对象中的键:值对均未覆盖任何原始矩阵值,则会将键:值对添加到每个矩阵组合中。 如果对象不能添加到任何矩阵组合中,将改为创建新的矩阵组合。
strategy: |
解释
{color: green}添加到所有原始矩阵组合,因为它可以添加,而不会覆盖原始组合的任何部分。{color: pink, animal: cat}仅将color:pink添加到包含animal: cat的原始矩阵组合中。 这会覆盖上一个include条目添加的color: green。{fruit: apple, shape: circle}仅将shape: circle添加到包含fruit: apple的原始矩阵组合中。{fruit: banana}添加到任何原始矩阵组合时都会覆盖值,因此会将其作为其他矩阵组合进行添加。{fruit: banana, animal: cat}添加到任何原始矩阵组合时都会覆盖值,因此会将其作为其他矩阵组合进行添加。 它不会添加到{fruit: banana}矩阵组合中,因为该组合不是原始矩阵组合之一
即生成六个作业
{fruit: apple, animal: cat, color: pink, shape: circle}{fruit: apple, animal: dog, color: green, shape: circle}{fruit: pear, animal: cat, color: pink}{fruit: pear, animal: dog, color: green}{fruit: banana}{fruit: banana, animal: cat}
工作流将运行六个作业,其中针对每个 os 和 node 变量组合提供一个作业。 当对应于 windows-latest 的 os 值和 16 的 node 值的作业运行时,作业中将包含一个被称为 npm 且值为 6 的其他变量
jobs: |
将运行 10 个作业,矩阵中每个 os 和 version 的组合一个作业,再加上一个用于 windows-latest 的 os 值和 17 的 version 值的作业
jobs: |
工作流将运行两个作业,每个 include 一个作业。 这样你可以利用矩阵策略,而无需完全填充矩阵
jobs: |
语法:jobs.<job_id>.strategy.matrix.exclude:移除矩阵中定义的特定配置
工作流将运行 9 个作业:每 12 个配置一个作业,再减去一个与 {os: macos-latest, version: 12, environment: production} 匹配的排除作业,以及两个与 {os: windows-latest, version: 16} 匹配的排除作业
strategy: |
语法:
jobs.<job_id>.strategy.fail-fast:设置为true,则在矩阵中的任何作业失败的情况下,GitHub 将取消矩阵中所有正在进行和加入队列的作业。 此属性的默认值为truejobs.<job_id>.continue-on-error:适用于单个作业。 如果jobs.<job_id>.continue-on-error为true,即使具有jobs.<job_id>.continue-on-error: true的作业失败,矩阵中的其他作业也将继续运行
可以同时使用 jobs.<job_id>.strategy.fail-fast 和 jobs.<job_id>.continue-on-error。 例如,以下工作流将启动四个作业。 对于每个作业,continue-on-error 都由 matrix.experimental 的值确定。 如果任何具有 continue-on-error: false 的作业失败,所有正在进行或加入队列的作业都将被取消。 如果具有 continue-on-error: true 的作业失败,则其他作业将不会受到影响
jobs: |
语法:jobs.<job_id>.strategy.max-parallel:GitHub 将根据运行器的可用性将并行运行的作业数最大化
工作流一次最多运行两个作业,即使运行器可同时运行六个作业
jobs: |
关于docker,这部分挺好理解的,跟compose.yaml差不多,所以简述了
jobs.<job_id>.container:创建一个容器
jobs.<job_id>.container.image:定义要用作运行操作的容器的 Docker 映像
jobs.<job_id>.container.credentials:映像的容器注册表需要身份验证才能拉取映像
jobs.<job_id>.container.env:容器中设置环境变量
jobs.<job_id>.container.ports:容器的端口
jobs.<job_id>.container.volumes:挂载卷
jobs.<job_id>.container.options:容器的其它选项
name: CI |
jobs.<job_id>.services:If you configure the job to run directly on the runner machine and your step doesn’t use a container action, you must map any required Docker service container ports to the Docker host (the runner machine). You can access the service container using localhost and the mapped port.译:如果您将作业配置为直接在运行程序机器上运行,并且您的步骤不使用容器操作,那么您必须将任何所需的Docker服务容器端口映射到Docker主机(运行程序机器)
services: |
Secret
前文,写了很多类似于『secret.xxx』的东西,在写Actions时,文件或者仓库中可能会涉及一些密码不希望被泄露,可以在在仓库下『Setting->Secrets->Actions』定义的该变量,之后在Actions中读取
三、Rule
Github Actions并非完全免费,但对于日常使用足够
以官方最新说明为主:Usage limits, billing, and administration - GitHub Docs
Job execution time - Each job in a workflow can run for up to 6 hours of execution time. If a job reaches this limit, the job is terminated and fails to complete.
Workflow run time - Each workflow run is limited to 35 days. If a workflow run reaches this limit, the workflow run is cancelled. This period includes execution duration, and time spent on waiting and approval.
API requests - You can execute up to 1000 requests to the GitHub API in an hour across all actions within a repository. If requests are exceeded, additional API calls will fail which might cause jobs to fail.
Concurrent jobs - The number of concurrent jobs you can run in your account depends on your GitHub plan, as indicated in the following table. If exceeded, any additional jobs are queued.
GitHub plan Total concurrent jobs Maximum concurrent macOS jobs Free 20 5 Pro 40 5 Team 60 5 Enterprise 180 50 Job matrix - A job matrix can generate a maximum of 256 jobs per workflow run. This limit applies to both GitHub-hosted and self-hosted runners.
Workflow run queue - No more than 500 workflow runs can be queued in a 10 second interval per repository. If a workflow run reaches this limit, the workflow run is terminated and fails to complete.
作业时间:每一个作业运行时间不得超过6小时,如果超过六小时,这个作业将会终止而无法完成
工作流时间:每一个工作流不得超过35天,如果超出此限制,这个工作流将被取消,此时间段包括执行持续时间以及等待和批准所花费的时间
API请求:在同一个仓库中一个小时内最多可以执行1000次API请求,如果请求超出,API将调用失败可能导致作业失败
并发作业:账户中可以运行的并发数量取决于Github计划,如果超出将排队作业
GitHub plan 并发数量 MacOS 最大并发数 Free 20 5 Pro 40 5 Team 60 5 Enterprise 180 50 作业矩阵:一个作业中的矩阵最多可以生成256个,此限制适用于 Github 托管(GitHub-hosted)和自托管运行(self-hosted runners)
工作流队列:每一个仓库不超过500个工作流可以被排队,间隔10s。如果超出限制,这个工作流将终止且运行失败
四、自用整理常用Actions
善用GitHub Marketplace会减少我们做Actions的工作量,以下为自己常用的Actions
Clone From Github
需要对当前仓库操作时,手撕版
- name: Clone |
Checkout:最常见的Actions,clone当前仓库的默认分支,指定仓库/分支详见文档
- name: Checkout |
Environment
Ubuntu自带py环境但没有node环境
Setup Python:python环境
Setup Node.js environment:nodejs
# 默认版本由 runs-on 决定 |
Push To GitHub
当工作流对仓库工作区改动需要push时,手撕版
- name: Commit & Push |
EndBug/add-and-commit:简化push
| 参数 | 说明 | 默认 | 示例 |
|---|---|---|---|
| add | 添加暂存区文件 | add: ‘.’ | add: ‘src’ |
| author_name | 用户名 | 作者用户名 | |
| author_email | 邮箱 | 作者邮箱 | |
| commit | 提交信息 | commit: ‘’ | commit: ‘Commit & Push’ |
- name: Push to GitHub |
主页美化
Blog Post Workflow:拉取最新博文
# 参考:https://github.com/CCKNBC/CCKNBC |
GitHub-Profile-3D-Contrib:绘制3D贡献图
name: GitHub-Profile-3D-Contrib |
Platane/snk:贪吃蛇版贡献图
name: Generate Snake |
其它美化Actions:
Github sync to other repo
Mirror a repository using SSH:同步Github中的仓库到其它平台
Gitee Pages Action · Actions:如果需要开启Gitee Page,参考此Actions
以Github同步Gitee为例:
ssh-keygen -t rsa -C "任意命名" -f "id_rsa_github to gitee"生成 SSH Key。(⚠️注意直接连续三次回车,此处不要设置密码,生成的公私钥用于下面 GitHub / Gitee 的配置,以保证公私钥成对,否则从 GitHub -> Gitee 的同步将会失败)。生成的id_rsa_github to gitee是私钥,id_rsa_github to gitee.pub是公钥在仓库 的「Settings -> Secrets」路径下配置好命名为
GITEE_RSA_PRIVATE_KEY和GITEE_PASSWORD的两个变量。其中:GITEE_RSA_PRIVATE_KEY存放id_rsa私钥;GITEE_PASSWORD存放 Gitee 帐号的密码
- 在 GitHub 的个人设置页面「Settings -> SSH and GPG keys」配置 SSH 公钥(即:
id_rsa_github to gitee.pub),命名随意 - 在 Gitee 的个人设置页面「安全设置 -> SSH 公钥」配置 SSH 公钥(即:
id_rsa_github to gitee.pub),命名随意
- name: Sync to Gitee |
操作云服务器
手撕版,DEPLOY_PRI为连接服务器的私钥
- name: ssh |
ssh-pipeline:连接服务器并对服务器操作
| 参数 | 说明 | 默认 |
|---|---|---|
| host* | ip | |
| user* | 用户 | |
| pass(与key二选一) | 密码 | |
| key(与pass二选一) | 私钥 | |
| port | 端口 | 22 |
| connect_timeout | 连接超时时间 | 30s |
| script | 命令 |
- name: ssh pipelines |
ssh-scp-ssh-pipelines:同一作者的优化版,与上表不同的是去除了script,新增
first_ssh:scp之前需要做的命令scp:sync copy,复制本地到服务器中,支持正则last_ssh:scp之后需要做的命令
- name: ssh scp ssh pipelines |
ssh deploy:更倾向于服务器同步文件操作的工作流,最大的特点是利用 rsync(remote sync 远程同步)命令备份数据时,不会直接覆盖以前的数据,而是先判断已经存在的数据和新数据的差异,只有数据不同时才会把不相同的部分覆盖,所以速度上会很快
| 参数 | 说明 |
|---|---|
| SSH_PRIVATE_KEY* | 服务器私钥 |
| ARGS* | rsync的参数 |
| SOURCE | 源路径 |
| TARGET | 目标路径 |
| REMOTE_HOST* | 服务器ip |
| REMOTE_USER* | 服务器用户名 |
| EXCLUDE | 排除文件 |
| SCRIPT_BEFORE | 同步前的操作 |
| SCRIPT_AFTER | 同步后的操作 |
- name: Deploy to Staging server |
小tips
一些不常用的Actions及使用技巧
waline-comments-backup:@二花的数据库备份方案,使用了gpg对文件加密,不错的点子!
# 使用 gpg 加密备份文件,需要提前生成随机密码,保存到 github action secrets 中,环境变量名称为 `COMMENTS_DECRYPT_KEY` |
dawidd6/action-send-mail:利用Actions发送邮件
justjavac/auto-green:自动保持 GitHub 提交状态常绿 a commit every day, keep your girlfriend far away. (仅定时运行脚本无提交,60天后会自动关闭Actions,可以借助这个)





