基本概念
- Workflows
- 工作流,可以添加到存储库中的自动化过程。工作流由一个或多个作业组成,可以由事件调度或触发。
- Event
- 事件,触发工作流的特定动作。例如,向存储库提交 pr 或 pull 请求。
- Jobs
- 作业,在同一跑步器上执行的一组步骤。默认情况下,具有多个作业的工作流将并行运行这些作业。
- Steps
- 步骤,可以在作业中运行命令的单个任务。步骤可以是操作,也可以是 shell 命令。作业中的每个步骤都在同一个运行程序上执行,从而允许该作业中的操作彼此共享数据。
- Actions
- 操作是独立的命令,它们被组合成创建作业的步骤。操作是工作流中最小的可移植构建块。你可以创建自己的动作,或者使用 GitHub 社区创建的动作。
- Runners
- 运行器,安装了 GitHub Actions 运行器应用程序的服务器。。Github 托管的运行器基于 Ubuntu Linux、Microsoft Windows 和 macOS,工作流中的每个作业都在一个新的虚拟环境中运行。
Action
从基础概念不难得知,Action是最基础的操作之一,而Action实际上有一个市场GitHub Marketplace · Tools to improve your workflow,可以从这个市场里选择自己需要的Action去组合成Steps。
选择对应的Action使用@
指定对应版本,以actions/checkout
为例,使用v2
版本就是actions/checkout@v2
;Action一般需要指定名称、Action及版本、输入参数,当然Action完成后会输出一部分的参数,输入参数使用with指定,一个示例如下:
- name: Login Registry
id: login-docker
uses: docker/login-action@v1
with:
registry: registry.cn-shanghai.aliyuncs.com
username: ${{ secrets.ALIYUN_USER }}
password: ${{ secrets.ALIYUN_PASSWORD }}
需要注意的是,名称可以任意,但是id则必须符合规范,禁止使用空格等特殊符号,可以参考常规变量命名规则。
如果不选择对应的Action,则可以直接执行命令来完成部分操作,如下:
- name: Echo
id: echo
run: |
echo "msg=OK" >> $GITHUB_OUTPUT
获取对应Action
的输出需要通过id指定,如:
- name: Echo result
id: echo-result
run: |
echo ${{ steps.echo.outputs.msg }}
说明
直接以示例会更好理解
事件触发
Github Action是在指定事件发生后触发的,而事件有很多,这里只介绍常用的几种,其余可以参考文档Events that trigger workflows - GitHub Docs
Push
事件通过on
关键字指定,譬如,在push
后运行Github Action
,则可以:
on:
push
如果还需要指定对应的分支,则可以:
on:
push:
branches:
- 'main'
- 'releases/**'
注意这里可以使用通配符;而一般来说,我们可能在发布一个Release时,会push一个tag,而只想在发布Release时才运行Action的话,则可以:
on:
push:
tags:
- v1.**
又或者,只需要在push了指定的文件的时候才运行Action,则可以:
on:
push:
paths:
- '**.js'
这表明只有在push了js文件时才会运行Action。
上面的条件实际可以组合起来,譬如只有在releases/**
分支下push了js文件才运行Action:
on:
push:
branches:
- 'releases/**'
paths:
- '**.js'
workflow_dispatch
Note: This event will only trigger a workflow run if the workflow file is on the default branch.
这个实际上是提供一个手动调用Github Action
的事件,它仅会被手动触发。
schedule
这是一个定时的事件,在指定事件触发,如下格式:
on:
schedule:
# * is a special character in YAML so you have to quote this string
- cron: '30 5,17 * * *'
定时可以组合起来:
on:
schedule:
- cron: '30 5 * * 1,3'
- cron: '30 5 * * 2,4'
你可以在Workflow
中取到具体的定时时间,通过github.event.schedule
获取,例如:
on:
schedule:
- cron: '30 5 * * 1,3'
- cron: '30 5 * * 2,4'
jobs:
test_schedule:
runs-on: ubuntu-latest
steps:
- name: Not on Monday or Wednesday
if: github.event.schedule != '30 5 * * 1,3'
run: echo "This step will be skipped on Monday and Wednesday"
- name: Every time
run: echo "This step will always run"
Docker登陆
使用Docker的官方Action即可:
- name: Login Registry
uses: docker/login-action@v1
with:
registry: ${{ secrets.REGISTRY }}
username: ${{ secrets.USER }}
password: ${{ secrets.PASSWORD }}
将账密保存到仓库的Secrets中,不要直接写到文件里。
配置环境
Java环境
使用actions/setup-java@v3
进行配置,如下:
- uses: actions/setup-java@v3
with:
distribution: 'zulu' # See 'Supported distributions' for available options
java-version: '17'
支持的分支如下:
Keyword | Distribution | Official site | License |
---|---|---|---|
temurin | Eclipse Temurin | Link | Link |
zulu | Azul Zulu OpenJDK | Link | Link |
adopt or adopt-hotspot | AdoptOpenJDK Hotspot | Link | Link |
adopt-openj9 | AdoptOpenJDK OpenJ9 | Link | Link |
liberica | Liberica JDK | Link | Link |
microsoft | Microsoft Build of OpenJDK | Link | Link |
corretto | Amazon Corretto Build of OpenJDK | Link | Link |
semeru | IBM Semeru Runtime Open Edition | Link | Link |
oracle | Oracle JDK | Link | Link |
dragonwell | Alibaba Dragonwell JDK | Link | Link |
支持的版本如下:
- 主版本:
8
,11
,16
,17
- 指定小版本:
17.0
,11.0
,11.0.4
,8.0.232
,8.0.282+8
- EA(Early Access)版本:
15-ea
,15.0.0-ea
,15.0.0-ea.2
,15.0.0+2-ea
Nodejs
使用actions/setup-node@v3
,如下:
- uses: actions/setup-node@v3
with:
node-version: 18
支持的版本如下:
- 主版本:
14
,16
,18
- 指定小版本:
10.15
,16.15.1
,18.4.0
- NVM LTS语法:
lts/erbium
,lts/fermium
,lts/*
,lts/-n
- 使用最新版:
*
orlatest
/current
/node
Golang
使用actions/setup-go@v4
,如下:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: '^1.13.1' # The Go version to download (if necessary) and use.
- run: go version
支持的版本如下:
- 指定版本:
1.15
,1.16.1
,1.17.0-rc.2
,1.16.0-beta.1
- SemVer版本范围语法:
^1.13.1
,>=1.18.0-rc.1
元数据提取
使用docker/metadata-action@v3
提取:
- name: Get Tag
id: meta
uses: docker/metadata-action@v3
with:
images: |
xxx/yyy
提取出来的元数据实例如下:
Event | Ref | Docker Tags |
---|---|---|
pull_request | refs/pull/2/merge | pr-2 |
push | refs/heads/master | master |
push | refs/heads/releases/v1 | releases-v1 |
push tag | refs/tags/v1.2.3 | v1.2.3 , latest |
push tag | refs/tags/v2.0.8-beta.67 | v2.0.8-beta.67 , latest |
workflow_dispatch | refs/heads/master | master |
推送仓库
使用ad-m/github-push-action@master
,如下:
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
这里的secrets.GITHUB_TOKEN
,不需要自己去定义,这是在Github Action中默认存在的,在推送前需要有commit
操作,如下:
- name: Commits files
run: |
echo "Update repo version file..."
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add .
git commit -m "commment"
echo "File has been committed"
直接推送是默认禁用的,如果确实有需要,可以在仓库设置中的Actions/General
设置成为可写:
示例
静态博客构建镜像并推送到Registry
直接看配置:
name: Blog CI
on:
push:
tags:
- "*-build"
jobs:
build:
name: Build Docker image and auto deploy
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v2
- name: Get Tag
id: meta
uses: docker/metadata-action@v3
with:
images: |
registry.cn-shanghai.aliyuncs.com/evalexp-private/blog
- name: Setup Nodejs
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Hexo
run: npm install hexo -g
- name: Install dependencies
run: npm install
- name: Generate Blog
run: hexo g
- name: Login Registry
uses: docker/login-action@v1
with:
registry: registry.cn-shanghai.aliyuncs.com
username: ${{ secrets.ALIYUN_USER }}
password: ${{ secrets.ALIYUN_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
定时检查基础镜像是否更新并更新本镜像
直接看配置:
name: Auto Build Latest DERP
on:
push:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
build:
name: Build Docker image and push
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v2
- name: Login Registry
uses: docker/login-action@v1
with:
registry: registry.cn-shanghai.aliyuncs.com
username: ${{ secrets.ALIYUN_USER }}
password: ${{ secrets.ALIYUN_PASSWORD }}
- name: Check version
id: check-version
run: |
docker pull ghcr.io/tailscale/tailscale:latest
REMOTE_VER=$(docker inspect ghcr.io/tailscale/tailscale | grep -oE "\"Id\": \"sha256:([0-9a-f]+)\"" | sed "s/\"Id\": \"sha256://g" | sed "s/\"//g")
CURRENT_VER=$(cat current_ver)
echo "Remote Latest Verion is SHA256:$REMOTE_VER"
echo "Current built verion is SHA256:$CURRENT_VER"
if [ "$REMOTE_VER" != "$CURRENT_VER" ];then
echo $REMOTE_VER > current_ver
echo "build=true" >> $GITHUB_OUTPUT
echo "push=true" >> $GITHUB_OUTPUT
echo "version=$REMOTE_VER" >> $GITHUB_OUTPUT
echo "Version is outdated, build latest version..."
else
echo "Version is latest."
fi
- name: Build Image and Push
if: ${{ steps.check-version.outputs.build == 'true' }}
run: |
echo "Build Latest Version Right now: "
docker build . -t registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:${{steps.check-version.outputs.version}}
docker tag registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:${{steps.check-version.outputs.version}} registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:latest
docker push registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:${{steps.check-version.outputs.version}}
docker push registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:latest
echo "Build done."
- name: Commits files
if: ${{ steps.check-version.outputs.push == 'true' }}
run: |
echo "Update repo version file..."
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add .
git commit -m "Update tailscale version to SHA256:${{steps.check-version.outputs.version}}"
echo "File has been committed"
- name: Push changes
if: ${{ steps.check-version.outputs.push == 'true' }}
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
- name: Done
if: ${{ steps.check-version.outputs.push == 'true' }}
run: |
echo "Changes have been push to repo."