Github Actions 为什么这么香
本文存在大量纰漏待修正
Github Actions
为什么这么香,我为什么专门建了一个组织ccknbc-actions
来跑 actions 并储存博客源码,或者其他只是单纯来跑 actions 的项目,一开始就单纯只是想分类,forked 一堆,主账号自己的项目却混在其中,最新的反而是天天运行 actions 的(排在前面)
而对大多数博主来说,都是把自己的源码(包含源文章)仓库私有起来,而一个普通账号每个月私有仓库运行时间为 2000 分钟,确实,是完全够用的,对于我们这种月更博主来说一个月 100 分钟而已(好吧我就是懒);不过作为白嫖党我还是公开了仓库(这样就不限制运行时间了),但如果你选择了定时执行某些项目,注意间隔最小为5分钟
,而触发方式也是多种多样的,但最让人欣喜的是手动触发方式终于完成了技术革命,不再监控 star 动作了,而是只有项目所有者可执行,这样就不会再运行记录里出现一堆无关记录影响查看(虽然之前判断仓库所有者也是 OK,但是强迫症不接受两秒运行跳过无关记录)
而且由于分配的临时机性能还不错,速度还是很可观的,并且不受长城防火墙的限制,可以很方便的做一些其他事情,这里就不细说,回到标题,它为什么这么香呢?
可能在工作流文件书写上没其他第三方简单,用过Travis CI
或者Gitlab CI
的都应该有体会,但自家的经过这么久的发展,用起来还是比较舒服的,而且用户编写的 actions 可以直接拿来用发布到市场,这样有些功能的实现就不用再自己想半天去实现,几行代码就搞定,用 HEXO 写博客的都知道 Gitee 托管静态网页要更新的话就得手动点一下更新才行,而 actions 就可以帮我们去点一下以实现同步全自动更新,多平台部署
Github 本身自带的模板是 OK 的,但毕竟很多新手完全不懂,但其实上手一段时间就明白了每一步在做什么为什么要这样写,官方文档的例子虽然很简单但确实是包含了常用的一些步骤,再加上很多人分享,直接拿来用就行,毕竟搜索引擎不能摆在那不用,爬几篇文章学习一下就会了,这里我以部署 HEXO 博客为例来说一下
首先我们得明白,要让 Github 能在你 git push 上去后能自动部署博客,你得知道博客的源文件是必须要的,但备份哪些呢,下图只是以本站做一个示例,框中的是必须要有的(如果你不打算修改主题源码其实也不用备份,但毕竟可以节约时间,第一次备份前记得在主题文件夹删掉.git
隐藏文件夹,不然推上去是空的会导致运行失败),其他根据个人需求,,配一个证书或者 README 等,但你还在疑惑;我没有.github 文件夹啊,没错这个就是我们自己新建的文件夹,在博客根目录依次建立.github/workflows/*.yml
文件
就像下图这样,工作流文件.yml 你可以随便命名啦,然后我们在工作流文件中添加如下内容
1 | name: Update Blog Butterfly Site |
在 workflow 文档流里我们可以用 ${{ secrets.GITHUB_TOKEN }}
做权限认证,是一个默认存在的变量,并不需要我们去添加 ACCESS_TOKEN,跨仓库的话还是要自己手动生成一个,关于这点,可以查看官方文档相关内容
你可能有所疑惑但又看得懂一些命令,别急,请接着往下看
GitHub Actions 指南
GitHub Actions
使你可以直接在你的GitHub
库中创建自定义的工作流,工作流指的就是自动化的流程,比如构建、测试、打包、发布、部署等等,也就是说你可以直接进行 CI
(持续集成)和 CD
(持续部署)
基本概念
workflow
: 一个workflow
工作流就是一个完整的过程,每个workflow
包含一组jobs
任务job : jobs
任务包含一个或多个job
,每个job
包含一系列的steps
步骤step
: 每个step
步骤可以执行指令或者使用一个action
动作action
: 每个action
动作就是一个通用的基本单元
说明:
- 最外层的
name
指定了workflow
的名称 on
声明了一旦发生了push
操作就会触发这个workflow
jobs
定义了任务集,其中可以有一个或多个job
任务,示例中只有一个runs-on
声明了运行的环境steps
定义需要执行哪些步骤- 每个
step
可以定义自己的name
和id
,通过uses
可以声明使用一个具体的action
,通过run
声明需要执行哪些指令。 - 可以使用上下文参数
on
声明了何时触发workflow
,它可以是:- 一个或多个
GitHub
事件,比如push
了一个commit
、创建了一个issue
,产生了一次pull request
等等,示例:
- 一个或多个
1 | on:[push,pull_request] |
- 预定的时间,示例(每天零点零分触发,不过因为时差关系,是北京时间上午 8 点):
1 | on: |
- 某个外部事件。所谓外部事件触发,简而言之就是你可以通过
REST API
向GitHub
发送请求去触发,具体请查阅官方文档:repository-dispatch-event
配置多个事件,示例:
1 | ```yaml |
1 |
|
如果多个job
之间存在依赖关系,那么你可能需要使用 needs
:
1 | jobs: |
这里的needs
声明了job2
必须等待 job1
成功完成,job3
必须等待 job1
和 job2
依次成功完成
每个任务默认超时时间最长为 360
分钟,你可以通过 timeout-minutes
进行配置:
1 | jobs: |
runs-on & strategy
runs-on
指定了任务的 runner
即执行环境,runner
分两种:GitHub-hosted runner
和 self-hosted runner
所谓的 self-hosted runner
就是用你自己的机器,但是需要 GitHub
能进行访问并给与其所需的机器权限,这个不在本文描述范围内,有兴趣可参考 self-hosted runner
GitHub-hosted runner
其实就是 GitHub
提供的虚拟环境,目前有以下四种:
windows-latest : Windows Server 2019
ubuntu-latest
或ubuntu-18.04
ubuntu-16.04
:Ubuntu 16.04
macos-latest
:macOS Catalina 10.15
比较常见的:
1 | runs-on:ubuntu-latest |
runs-on 多环境
有时候我们常常需要对多个操作系统、多个平台、多个编程语言版本进行测试,为此我们可以配置一个构建矩阵
例如:
1 | runs-on: ${{ matrix.os }} |
示例中配置了两种os
操作系统和三种 node
版本即总共六种情况的构建矩阵, `${{matrix.os}}` 是一个上下文参数
strategy
策略,包括:
matrix
: 构建矩阵fail-fast
: 默认为true
,即一旦某个矩阵任务失败则立即取消所有还在进行中的任务max-paraller
: 可同时执行的最大并发数,默认情况下GitHub
会动态调整
示例:
1 | runs-on: ${{ matrix.os }} |
include
声明了 os
为 windows-latest
时,增加一个 node
和npm
分别使用特定的版本的矩阵环境
与include
相反的就是exclude
:
1 | runs-on: ${{ matrix.os }} |
exclude
用来删除特定的配置项,比如这里当os
为 macos-latest
,将 node
为 4 的版本从构建矩阵中移除
steps
steps
的通用格式类似于:
1 | steps: |
每个 step
步骤可以有:
id
: 每个步骤的唯一标识符name
: 步骤的名称uses
: 使用哪个action
run
: 执行哪些指令with
: 指定某个action
可能需要输入的参数continue-on-error
: 设置为true
允许此步骤失败job
仍然通过timeout-minutes : step
的超时时间
action
action
动作通常是可以通用的,这意味着你可以直接使用别人定义好的action
checkout action
checkout action
是一个标准动作,当以下情况时必须且需要率先使用:
workflow
需要项目库的代码副本,比如构建、测试、或持续集成这些操作workflow
中至少有一个action
是在同一个项目库下定义的
使用示例:
1 | - users:action/checkout@v1 |
如果你只想浅克隆你的库,或者只复制最新的版本,你可以在 with
中使用fetch-depth
声明,例如:
1 | - user:action/checkout@v1 |
引用 action
- 官方
action
标准库: github.com/actions - 社区库:
marketplace
引用公有库中的 action
引用 action
的格式是{owner}/{repo}@{ref}
或 {owner}/{repo}/{path}@{ref}
,例如上例的中actions/checkout@v1
,你还可以使用标准库中的其它 action
,如设置 node
版本:
1 | jobs: |
引用同一个库中的 action
引用格式:{owner}/{repo}@{ref}
或 ./path/to/dir
例如项目文件结构为:
1 | -- hello-world (repository) |
当你想要在workflow
中引用自己的action
时可以:
1 | jobs: |
引用 Docker Hub 上的 container
如果某个 action
定义在了一个docker container image
中且推送到了Docker Hub
上,你也可以引入它,格式是docker://{image}:{tag}
,示例:
1 | jobs: |
更多信息参考:Docker-image.yml workflow
和Creating a Docker container ``action
构建 actions
请参考:building-actions
env
环境变量可以配置在以下地方:
env
jobs.<job_id>.env
jobs.<job_id>.steps.env
示例:
1 | env: |
如果重复,优先使用最近的那个
if & context
你可以在 job
和step
中使用if
条件语句,只有满足条件时才执行具体的job
或 step
:
jobs.<job_id>.if
jobs.<job_id>.steps.if
任务状态检查函数:
success()
: 当上一步执行成功时返回true
always()
: 总是返回true
cancelled()
: 当workflow
被取消时返回true
failure()
: 当上一步执行失败时返回true
例如:
1 | steps: |
意思就是 step1
总是执行,step2
需要上一步执行成功才执行,step3
只有当上一步执行失败才执行
1 | ${{<expression>}} |
上下文和表达式: ${{
有时候我们需要与第三方平台进行交互,这时候通常需要配置一个token
,但是显然这个 token
不可能明文使用,这种个情况下我们要做的就是:
- 在具体
repository
库Settings
的Secrets
中添加一个密钥,如SOMEONE_TOKEN
注:关于如何获取 github 或者其他平台的密钥及授权不是本文重点,大家可以自行百度
- 然后在
workflow
中就可以通过${{secrets.SOMEONE_TOKEN}}
将token
安全地传递给环境变量
1 | steps: |
这里的secrets
就是一个上下文,除此之外还有很多,比如:
github.event_name
: 触发workflow
的事件名称job.status
: 当前job
的状态,如success, failure, or cancelled
steps.<step id>.outputs
: 某个action
的输出runner.os : runner
的操作系统如Linux, Windows, or macOS
这里只列举了少数几个
另外在if
中使用时不需要 ${{}}
符号,比如:
1 | steps: |
上下文和表达式详细信息请参考:contexts-and-expression
看到这里你应该对示例文件有了一定的理解,并且想自己去实验一下了,那就去 actions 页面找到官方示例去体验一下吧
但对于为什么要备份package.json
我想大家还是心存疑惑,那我们看看具体内容吧
1 | { |
我们看到里面包含了 npm 脚本和一些依赖(包含 dev 版本的),有了这个文件我们只需执行 npm i(install)即可自动安装所以所需依赖插件,而不用一个一个去敲一堆命令啦,理解了这个简单的例子,大家在部署其他项目时也许能更得心应手吧
今天的分享就到这里结束了,本文还有很多纰漏还请读者指出,后续将更正,下篇文章见