导言
感到为了持续集成注册一堆账号、设置一堆 token 很麻烦?或是被自建 GitLab 的内存泄露烦扰?不如来尝试下 GitHub 新推出的内置 CI/CD 工具 GitHub Action!
作为 GitLab CI 和 Travis CI 的一个可能替代品,GitHub Action 同样提供免费方案,且对于个人用户完全够用。功能基本类似,但还是有些细微差别。本文将简要介绍其基本概念、工作流程和配置方法。
参考链接
- 帮助文档 (https://help.github.com/en/actions)
- 语法文档 (https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions)
- 应用市场 (https://github.com/marketplace?type=actions)
- 入门工作流 (https://github.com/actions/starter-workflows)
基本概念
CI/CD
持续集成、持续部署。不用多说了⑧,不知道这个也没必要看本文。
Event
触发一个 Workflow 的事件。包含了各种操作:推送、合并、合并请求、打标签、发行…
Action
说白了一个 Action 就是一步独立的操作。给力的是 Action 可以将复杂操作封装为一步,并且 GitHub 官方和社区提供了成吨的现成 Action 供引用。
Step
就是一步操作。可以是自己写的指令,也可以是引用 Action。
Job
在一个给定环境下(操作系统、容器)执行一系列 Step。(各个 Job 环境是独立的)
Runner
执行 Job 的机器。GitHub 提供了一些,你也可以自建。
Workflow
工作流。由一个 Event 触发的一系列 Job。
Artifact
产物。就是说干完一个活之后产出了什么(二进制文件、log、质量报告之类的)。
工作流程
这是一个 Job:根据配置创建出一个虚拟环境,然后执行一系列你指定的 Step 中的命令或 Action。
这是一个 Workflow:当一个事件发生了,这个 Workflow 里面的 Job 将按照依赖关系并行地或先后地执行。
Workflow 语法介绍
name
# File Path: /.github/workflows/main.yml
name: "A Sample Workflow"
on
# Trigger on Event
on: [push, pull_request]
# or
on:
push:
paths:
# Trigger only when src/** changes
- "src/**"
# Ignore when only doc/** changes
- "!doc/**"
paths-ignore:
- "doc/**"
branches:
- master
- "!ignored"
branches-ignore:
- ignored
tags:
- "v*"
- "!v0.*"
tags-ignore:
- "v0.*"
release:
types: [published, unpublished, created, edited, deleted, prereleased]
schedule:
# Trigger every 15 min(UTC)
- cron: '*/15 * * * *'
env
# Workflow Environment (Step ENV > Job ENV > Workflow ENV)
env:
SERVER: production
KEY: 123456
jobs
jobs:
job1:
name: Job 1
job2:
name: Job 2
needs: job1
job3:
name: A Job runs on Host machine
needs: [job1, job2]
job(host)
job3:
name: A Job runs on Host machine
needs: [job1, job2]
timeout-minutes: 20
# Or windows-latest, ubuntu-18.04, macos-10.15
runs-on: ubuntu-latest
env:
# override workflow env
KEY: 12345678
# See https://help.github.com/en/actions/reference/contexts-and-expression-syntax-for-github-actions
if: <expression>
steps:
- name: Step A(simply run)
if: <expression>
continue-on-error: true
timeout-minutes: 10
env:
# override workflow, job env
KEY: 1234567890
working-directory: ./docs
# or python, cmd, powershell, ...
shell: bash
run: |
npm ci
npm run build
- name: Step B(uses action)
uses: "{owner}/{repo}/{path}@{ref}"
# or
uses: "./path/to/action"
with:
tag_name: ${{ github.ref }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Step B(uses docker)
uses: "docker://{image}:{tag}"
with:
entrypoint: /bin/echo
args: The ${{ github.event_name }} event triggered this step.
job(container)
job4:
name: A Job runs in Container
image: ubuntu:bionic
env:
KEY: 123
ports:
- 80:80
volumes:
- /source:/data
# See https://docs.docker.com/engine/reference/commandline/create/#options
options: --cpus 1
steps:
- name: Same as host jobs
run: echo hello
job(service)
job5:
name: A Job uses services
services:
nginx:
image: nginx
ports:
- 8080:80
volumes:
- /src:/data
options: --cpus 1
redis:
image: redis
ports:
- 6379/tcp
job(matrix)
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-18.04]
node: [4, 6, 8, 10]
include:
# includes a new variable of npm with a value of 2 for the matrix leg matching the os and version
- os: windows-latest
node: 4
npm: 2
exclude:
# excludes node 4 on macOS
- os: macos-latest
node: 4
steps:
- uses: actions/[email protected]
with:
node-version: ${{ matrix.node }}
Filter pattern
常用 Action
checkout
- uses: actions/[email protected]
with:
# Repository name with owner. For example, actions/checkout
# Default: ${{ github.repository }}
repository: ''
# The branch, tag or SHA to checkout. When checking out the repository that
# triggered a workflow, this defaults to the reference or SHA for that event.
# Otherwise, defaults to `master`.
ref: ''
# Auth token used to fetch the repository. The token is stored in the local git
# config, which enables your scripts to run authenticated git commands. The
# post-job step removes the token from the git config. [Learn more about creating
# and using encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
# Default: ${{ github.token }}
token: ''
# Whether to persist the token in the git config
# Default: true
persist-credentials: ''
# Relative path under $GITHUB_WORKSPACE to place the repository
path: ''
# Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching
# Default: true
clean: ''
# Number of commits to fetch. 0 indicates all history.
# Default: 1
fetch-depth: ''
# Whether to download Git-LFS files
# Default: false
lfs: ''
upload-artifacts
steps:
- uses: actions/[email protected]
- run: mkdir -p path/to/artifact
- run: echo hello > path/to/artifact/world.txt
- uses: actions/[email protected]
with:
name: my-artifact
path: path/to/artifact
download-artifacts
steps:
- uses: actions/[email protected]
- uses: actions/[email protected]
with:
name: my-artifact
path: path/to/artifact
- run: cat path/to/artifact
create-release
- name: Create Release
id: create_release
uses: actions/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: |
Changes in this Release
- First Change
- Second Change
draft: false
prerelease: false
upload-release-asset
- name: Upload Release Asset
id: upload-release-asset
uses: actions/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./my-artifact.zip
asset_name: my-artifact.zip
asset_content_type: application/zip
setup-python
steps:
- uses: actions/[email protected]
- uses: actions/[email protected]
with:
# Version range or exact version of a Python version to use, using SemVer's version range syntax
python-version: '3.x'
# optional x64 or x86. Defaults to x64 if not specified
architecture: 'x64'
- run: python my_script.py