文章
Github Actions使用指南
从基础概念、配置结构、常用用例与最佳实践四个方面,系统介绍如何使用 GitHub Actions 来自动化软件开发流程
目录
- 以下是一个完整的 GitHub Actions 使用指南,将基础概念、工作流结构、常见用例与最佳实践,帮助你在实际项目中更高效地编写和管理 CI/CD 流程。
- 一、基础概念与术语
- 4. Context 与 Expression(上下文与表达式) - 在 Workflow 中,用 ${{ ... }} 来引用上下文变量(Context)并做简单逻辑判断。 - 常用上下文示例: - github.ref、github.ref_name:当前 Branch 或 Tag 名称; - github.actor:发起事件的用户名; - runner.os:Runner 操作系统; - secrets.MY_SECRET:访问仓库中 Secrets 中的机密。 - Expression 例子: yaml if: ${{ github.ref == 'refs/heads/main' }} 或者在 Matrix 中: yaml runs-on: ${{ matrix.os }} 5. Job(作业) - Workflow 里并行或串行执行的一组 Steps。 - 默认不同 Job 之间彼此隔离、在不同 Runner 上运行,无法共享文件系统。 - 可以用 needs: 来声明 Job 之间的依赖,保证有依赖关系的 Job 按顺序执行。 6. Step(步骤) - Job 中的最小执行单元。可以是: - uses: 某个 Action——复用社区或官方 Action; - run: 某段 Shell/PowerShell 命令——由 Runner 直接执行。 - 可以通过 name: 给 Step 命名,在日志中更易识别。 7. Action(动作) - 单个独立的可复用组件,封装了某种任务(如检出代码、安装依赖、上传 Release 等)。 - 官方和社区发布了大量 Action,可直接在 .github/workflows/xxx.yml 中引用,例如: yaml uses: actions/checkout@v3 uses: actions/cache@v3 uses: actions/setup-node@v3 - 也可以自行编写并发布 Action(JavaScript、Docker、Composite Action 均可)。
- 二、工作流的基本结构
- 结构说明
- 三、常见配置及进阶用法
- 1. 触发器中的包含/排除路径(paths 与 paths-ignore)
- 1.1 paths(包含规则)
- 1.2 paths-ignore(排除规则)
- 1.3 同时使用 paths 和 paths-ignore
- 2. 缓存依赖(Cache)
- 3. 矩阵构建(Matrix)
- ① matrix.os 会分别取 ubuntu-latest、windows-latest、macos-latest, ② matrix.rust-version 会分别取 1.65.0、1.66.0, 这样一共会启动 3×2=6 个并行 Job,覆盖多环境多版本测试。
- 4. 多 Job 串行与并行
- 5. 使用 Secrets 与环境变量
- 6. 手动触发与输入参数(workflow_dispatch)
- 7. 定时触发(schedule)
- 四、示例场景
- 1. Node.js + Docker 自动化构建与发布
- 2. Rust 多平台构建与发布(Matrix + paths-ignore)
- 五、调试与最佳实践
- release: if: ${{ startsWith(github.ref, 'refs/tags/') }} # 只在 Tag 推送时跑发布 ```
- 六、小结
- 📎 参考文章
以下是一个完整的 GitHub Actions 使用指南,将基础概念、工作流结构、常见用例与最佳实践,帮助你在实际项目中更高效地编写和管理 CI/CD 流程。#
一、基础概念与术语#
- Runner(运行器)
- 负责在特定环境(如 Ubuntu、Windows、macOS)下执行你定义的任务。
- GitHub 提供托管型 Runner(如
ubuntu-latest、windows-latest、macos-latest),也支持自托管 Runner。
- Workflow(工作流)
- 存放在仓库的
.github/workflows/目录下,以 YAML 格式描述。 - 定义触发条件(Trigger)、一个或多个 Job,以及每个 Job 中的执行步骤(Step)。
- 每当满足触发条件时,GitHub Actions 会启动对应的 Workflow。
- 存放在仓库的
- Trigger(触发器)
- 规定何时启动 Workflow。常见写法在 YAML 顶层的
on:字段下声明。 - 例如:
- 规定何时启动 Workflow。常见写法在 YAML 顶层的
on: push: branches: [ main ] pull_request: branches: [ main ] schedule: - cron: '0 3 * * *' workflow_dispatch: {}
```
- **`push`**** / ****`pull_request`**:代码推送或 PR 创建/更新时触发;
- **`schedule`**:定时触发,例如每天凌晨;
- **`workflow_dispatch`**:手动触发,可以在仓库 UI 上点击按钮并传入自定义参数。
4. Context 与 Expression(上下文与表达式)
- 在 Workflow 中,用 ${{ ... }} 来引用上下文变量(Context)并做简单逻辑判断。
- 常用上下文示例:
- github.ref、github.ref_name:当前 Branch 或 Tag 名称;
- github.actor:发起事件的用户名;
- runner.os:Runner 操作系统;
- secrets.MY_SECRET:访问仓库中 Secrets 中的机密。
- Expression 例子:
yaml if: ${{ github.ref == 'refs/heads/main' }}
或者在 Matrix 中:
yaml runs-on: ${{ matrix.os }}
5. Job(作业)
- Workflow 里并行或串行执行的一组 Steps。
- 默认不同 Job 之间彼此隔离、在不同 Runner 上运行,无法共享文件系统。
- 可以用 needs: 来声明 Job 之间的依赖,保证有依赖关系的 Job 按顺序执行。
6. Step(步骤)
- Job 中的最小执行单元。可以是:
- uses: 某个 Action——复用社区或官方 Action;
- run: 某段 Shell/PowerShell 命令——由 Runner 直接执行。
- 可以通过 name: 给 Step 命名,在日志中更易识别。
7. Action(动作)
- 单个独立的可复用组件,封装了某种任务(如检出代码、安装依赖、上传 Release 等)。
- 官方和社区发布了大量 Action,可直接在 .github/workflows/xxx.yml 中引用,例如:
yaml uses: actions/checkout@v3 uses: actions/cache@v3 uses: actions/setup-node@v3
- 也可以自行编写并发布 Action(JavaScript、Docker、Composite Action 均可)。#
二、工作流的基本结构#
下面举一个最基础的示例,并逐层拆解其含义。假设文件路径为 .github/workflows/ci.yml:
name: CI Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build_and_test:
name: Build & Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
结构说明#
name: CI PipelineWorkflow 的可读名称,会显示在 GitHub Actions 页面顶部。on:定义了什么时候触发这个 Workflow:push.branches: [ main ]:当向main分支推送时执行。pull_request.branches: [ main ]:当向main分支发起或更新 PR 时也会执行。
jobs:下面可以定义多个 Job。本示例只有一个 Job,名字叫build_and_test。runs-on: ubuntu-latest:指定 Runner 类型为最新的 Ubuntu 虚拟机。
steps:uses: actions/checkout@v3:检出仓库到 Runner。uses: actions/setup-node@v3:安装并配置 Node.js 环境。run: npm install:运行 Shell 命令安装依赖。run: npm test:运行 Shell 命令执行测试。
三、常见配置及进阶用法#
1. 触发器中的包含/排除路径(paths 与 paths-ignore)#
1.1 paths(包含规则)#
on:
push:
branches:
- main
paths:
- 'src/**'
- 'package.json'
- 只有当推送的改动中至少有一个文件匹配
src/**或package.json时,才会触发 Workflow。 - 如果改动中没有任何文件落在这些路径下,Workflow 直接跳过。
1.2 paths-ignore(排除规则)#
on:
push:
branches:
- main
paths-ignore:
- 'docs/**'
- 'README.md'
- '.github/**'
- 如果此次推送中所有改动的文件都匹配
docs/**、README.md或.github/**,则不触发 Workflow。 - 只有当改动中存在至少一个文件不在忽略列表里时,Workflow 才会触发。
- 典型场景:
- 文档 (
docs/) 单独更新时不跑 CI; - 对
.github/workflows/下的 YAML 或 README 做改动时跳过。
- 文档 (
1.3 同时使用 paths 和 paths-ignore#
on:
push:
branches:
- main
paths:
- 'src/**'
paths-ignore:
- 'src/legacy/**'
- 'README.md'
- 先看“是否有改动在
paths列表里”——如果没有,就不触发; - 如果有,再看“这些改动是否都在
paths-ignore中”——如果都在忽略列表,就不触发;否则触发。
2. 缓存依赖(Cache)#
CI 中反复安装依赖会耗费大量时间。通过缓存可以显著加速:
-
Node.js 示例:
-
name: Cache node_modules uses: actions/cache@v3 with: path: node_modules key: runner.os−node−{{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node-
-
Rust 示例:
-
name: Cache Cargo registry and build artifacts uses: actions/cache@v3 with: path: | ~/.cargo/registry ~/.cargo/git target key: runner.os−cargo−{{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-
解释:
path:要缓存的目录,写多个路径时用列表形式。key:缓存的唯一标识,通常使用依赖锁文件(如package-lock.json、Cargo.lock)的哈希,以确保依赖变化时重新缓存。restore-keys:如果没有完全命中key,会尝试前缀匹配,使用更老的缓存。
3. 矩阵构建(Matrix)#
当想在多种环境(操作系统、语言版本、数据库版本等)下并行运行相同任务时,可使用矩阵:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust-version: [1.65.0, 1.66.0]
steps:
- uses: actions/checkout@v3
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust-version }}
override: true
- name: Run tests
run: cargo test --verbose
① matrix.os 会分别取 ubuntu-latest、windows-latest、macos-latest,
② matrix.rust-version 会分别取 1.65.0、1.66.0,
这样一共会启动 3×2=6 个并行 Job,覆盖多环境多版本测试。#
4. 多 Job 串行与并行#
默认情况下,一个 Workflow 中的所有 Job 并行运行。如果需要某个 Job 在另一个完成后再跑,则可用 needs::
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: cargo build --release
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v3
- run: ./deploy.sh
- 这样只有当
build成功后,才会触发deploy。 - 若
build失败,deploy将被跳过。
5. 使用 Secrets 与环境变量#
当需要提供访问令牌、私钥等敏感信息时,应将它们存放在仓库的 Settings → Secrets 中,然后在 Workflow 中以 ${{ secrets.NAME }} 的方式引用。例如:
env:
MY_SECRET: ${{ secrets.MY_SECRET }}
steps:
- name: Use Secret
run: |
echo "The secret is $MY_SECRET"
- GitHub Actions 会自动对日志中出现的 secrets 值进行遮蔽(
**),但尽量避免在run里明文打印完整内容。
6. 手动触发与输入参数(workflow_dispatch)#
如果希望在 GitHub UI 里手动触发 Workflow,并提供自定义参数,可这样写:
on:
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
- 触发时,用户可以在页面中填写
environment,例如production、staging。 - 在后续 Steps 中可用
${{ github.event.inputs.environment }}来获取该值。
7. 定时触发(schedule)#
on:
schedule:
- cron: '0 3 * * *'
- GitHub Actions 使用 UTC 时间。如果想在北京时间凌晨 3 点运行,需要把 cron 写成 UTC 对应的
19 * * *。 - 定时任务通常用来执行:自动化备份、定期扫描、安全检查、生成报告等。
四、示例场景#
下面以几个常见语言/框架为例,演示完整的 CI/CD 工作流。
1. Node.js + Docker 自动化构建与发布#
name: Node.js CI & Docker Build
on:
push:
branches:
- main
paths-ignore:
- 'docs/**'
- '.github/**'
pull_request:
branches:
- main
paths-ignore:
- 'docs/**'
- '.github/**'
workflow_dispatch: {}
jobs:
test:
name: Run Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Cache npm dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install deps
run: npm ci
- name: Lint code
run: npm run lint
- name: Run tests
run: npm test
build-and-push-docker:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: test
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
push: true
tags: myrepo/myapp:latest
- 触发条件:
push到main,且改动不全在docs/或.github/;pull_request针对main,同样忽略文档改动;- 支持手动触发。
- Job “test”:检出 → 安装 Node.js → 缓存依赖 → 安装 → Lint → 测试。
- Job “build-and-push-docker”:依赖于测试成功,仅当分支是
main时执行,构建并推送 Docker 镜像。
2. Rust 多平台构建与发布(Matrix + paths-ignore)#
name: Rust CI & Release
on:
push:
branches:
- main
tags:
- 'v*'
paths-ignore:
- 'docs/**'
- '.github/**'
pull_request:
branches:
- main
paths-ignore:
- 'docs/**'
- '.github/**'
env:
CARGO_TERM_COLOR: always
jobs:
build:
name: Build & Release (${{ matrix.os }})
runs-on: ${{ matrix.os }}
if: ${{ startsWith(github.ref, 'refs/tags/') }}
strategy:
matrix:
include:
- os: ubuntu-latest
cache_registry: ~/.cargo/registry
cache_git: ~/.cargo/git
shell: bash
ext: tar.gz
target: linux-x86_64
- os: windows-latest
cache_registry: "C:\\Users\\runneradmin\\.cargo\\registry"
cache_git: "C:\\Users\\runneradmin\\.cargo\\git"
shell: powershell
ext: zip
target: windows-x86_64
- os: macos-latest
cache_registry: ~/.cargo/registry
cache_git: ~/.cargo/git
shell: bash
ext: tar.gz
target: macos-x86_64
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Cache Cargo registry & build artifacts
uses: actions/cache@v3
with:
path: |
${{ matrix.cache_registry }}
${{ matrix.cache_git }}
target
key: ${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ matrix.os }}-cargo-
- name: Install sqlx-cli
run: cargo install sqlx-cli --no-default-features --features postgres
shell: ${{ matrix.shell }}
- name: Create DB & Run migrations
run: |
sqlx database create || echo "database already exists"
sqlx migrate run
shell: ${{ matrix.shell }}
- name: Run tests
run: cargo test --verbose
shell: ${{ matrix.shell }}
- name: Build (release)
run: cargo build --release
shell: ${{ matrix.shell }}
- name: Package (Windows)
if: ${{ matrix.os == 'windows-latest' }}
run: |
New-Item -ItemType Directory -Force -Path dist
Copy-Item target\release\zero2prod.exe dist\
Compress-Archive -Path dist\zero2prod.exe -DestinationPath zero2prod-${{ github.ref_name }}-${{ matrix.target }}.${{ matrix.ext }}
shell: powershell
- name: Package (Unix)
if: ${{ matrix.os != 'windows-latest' }}
run: |
mkdir -p dist
cp target/release/zero2prod dist/
chmod +x dist/zero2prod
tar -czf zero2prod-${{ github.ref_name }}-${{ matrix.target }}.${{ matrix.ext }} -C dist zero2prod
shell: bash
- name: Upload Artifact
uses: softprops/action-gh-release@v1
with:
files: zero2prod-${{ github.ref_name }}-${{ matrix.target }}.${{ matrix.ext }}
- 触发条件:
push到main分支或形如v*的 Tag 推送时。- 只要改动全部属于
docs/或.github/,即不触发。
- 矩阵构建内容:
- 三个平台:
ubuntu-latest、windows-latest、macos-latest; - 对应不同的缓存路径(Linux/Unix vs. Windows)、不同的 Shell;
- 全平台统一安装 Rust → 缓存依赖 → 安装
sqlx-cli→ 数据库迁移 → 测试 → Release 构建 → 平台打包 → 上传到 GitHub Release。
- 三个平台:
- 注意:
- Windows/macOS 上官方不支持
services:来启动容器化数据库,所以如果需要跑集成测试,建议仅在 Linux Job 中启动 Postgres(本示例中为了完整性而仍写了相关步骤,实际可根据项目需要删减); - 如果只想在 Linux 上做集成测试,可在 Windows/macOS 部分去掉数据库相关步骤,只保留构建/打包发布。
- Windows/macOS 上官方不支持
五、调试与最佳实践#
- 日志与调试
- 当某个 Step 或 Job 失败,浏览器中会显示红色❌,点击展开可以看到详细日志。
- 如果脚本输出不足,可以在 Step 里加上
set -x(Bash)或者Write-Host(PowerShell)来打印更多调试信息。
- 避免泄露敏感信息
- 使用
${{ secrets.MY_SECRET }}引用 Secrets,不要在日志中明文打印。 - GitHub 会自动遮蔽 secrets 的输出,但务必谨慎对待。
- 使用
- 善用缓存(Cache)
- 依赖缓存可以大幅加速 CI,推荐对于大多数语言/包管理工具都做相应缓存。
- 缓存 Key 尽量绑定锁文件的哈希,只有当锁文件变化时才刷新缓存,否则能高命中率地复用。
- 拆分开发分支与发布分支流程
- 开发分支(如
main)只跑“编译 + 单元测试 + 集成测试”流程; - 发布(Tag 或
release分支)才走“构建 Release 可执行文件 / Docker 镜像 / 发布到生产环境”等流程。 - 这样可以避免每次开发者合并 PR 都触发耗时的打包或部署,提高效率。
- 开发分支(如
- 矩阵策略不要过度膨胀
- 虽然可以把所有操作系统、所有语言版本、依赖版本都放进 Matrix,但会导致 Job 数量急剧增多,消耗更多并发额度和总时长。
- 先分析哪些组合真的必要,再做分组。比如只在 Ubuntu 上跑全面集成测试,在 Windows/macOS 上跑编译和单元测试即可。
- Composite Actions 和 可复用步骤
- 如果团队内部有固定的 Best Practice(如统一 Lint + 单元测试 + 安全扫描等),可以把这套步骤封装成一个 Composite Action,各项目直接复用。
- Composite Action 的目录结构示例:
.github/actions/lint-and-test/
action.yml
scripts/
run-lint.sh
run-test.sh
- 在 Workflow 中只需引用: yaml
-
name: Lint & Test uses: ./.github/actions/lint-and-test
```
- 定时任务(Cron)与手动触发并行
- 当同时需要定时执行和手动触发时,写成:
- 当同时需要定时执行和手动触发时,写成:
on:
push: { branches: [ main ] }
schedule:
- cron: '0 3 * * '
workflow_dispatch: {}
- **Push** 会按 `paths-ignore` 或 `paths` 规则判断是否触发; - **定时** 和 **手动** 无视 `paths-ignore`,每次都会执行。 8. **分支策略与分支名称判断** - 常见用法:只有推送 Tag(如 `v*`)时才发布 Release,合并 PR 到 `main` 时只跑测试。 - 例子: yaml
on:
push:
branches: [ main ]
tags: [ 'v' ]
jobs: test: if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/') }} # 只在 push 到 main(非 Tag)时跑测试
release: if: ${{ startsWith(github.ref, 'refs/tags/') }} # 只在 Tag 推送时跑发布 ```#
六、小结#
- 核心概念要熟悉:Runner、Workflow、Job、Step、Action、Trigger。
- 灵活使用
paths/ ****paths-ignore:可以精确控制何时触发 CI,节省资源。 - 缓存依赖:对常用语言都建议加速依赖、构建缓存。
- 矩阵构建要合理:覆盖必要环境,避免过度膨胀。
- 安全第一:所有敏感信息放在 Secrets,避免明文输出。
- 持续迭代与重用:将常见流程抽象为 Composite Action,方便维护、团队共享。 通过以上指南,你可以快速入门并掌握 GitHub Actions,在实际项目中实现从代码提交、测试、构建,到打包、发布的全自动化流水线,让开发效率和交付质量都得到显著提升。