在现代软件开发中,持续集成(CI)和持续部署(CD)已成为不可或缺的实践。GitHub Actions 作为 GitHub 平台原生的自动化工具,为开发者提供了强大的工作流(Workflow)能力。本文将深入探讨 GitHub Actions 工作流文件(Workflow File)的编写,从基础概念到高级技巧,助你全面掌握这一核心技能。
1. GitHub Actions 核心概念
在深入工作流文件之前,我们需要理解 GitHub Actions 的基本组成:
- 工作流 (Workflow) :自动化流程的定义,由一个或多个作业组成,定义在
.github/workflows/
目录下的 YAML 文件中。 - 作业 (Job):工作流中的独立任务单元,可以并行或串行执行。
- 步骤 (Step):作业中的单个操作,可以是运行命令或使用一个动作(Action)。
- 动作 (Action):执行特定任务的最小单元,可以是 GitHub 社区提供的,也可以是自定义的。
- 运行器 (Runner) :执行工作流的服务器,可以是 GitHub 托管的(
ubuntu-latest
,windows-latest
,macos-latest
)或自托管的。 - 事件 (Event) :触发工作流执行的条件,如
push
、pull_request
等。
2. 工作流文件基础结构
所有工作流文件都位于仓库根目录下的 .github/workflows/
目录中,文件扩展名为 .yml
或 .yaml
。
一个最基础的工作流文件结构如下:
yaml
# 工作流的名称
name: My CI/CD Pipeline
# 触发工作流的事件
on:
push:
branches: [main]
pull_request:
branches: [main]
# 定义一个或多个作业
jobs:
# 作业的唯一标识符
build:
# 作业运行的环境
runs-on: ubuntu-latest
# 作业包含的步骤
steps:
# 第一个步骤:检出代码
- name: Checkout code
uses: actions/checkout@v4
# 第二个步骤:设置 Node.js 环境
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
# 第三个步骤:安装依赖
- name: Install dependencies
run: npm ci
# 第四个步骤:运行测试
- name: Run tests
run: npm test
2.1 name
字段
可选,但强烈推荐。定义工作流在 GitHub UI 中显示的名称。
yaml
name: CI Pipeline for Backend Service
2.2 on
字段:触发事件详解
on
是工作流的核心,定义了何时触发执行。
常见事件类型
yaml
on:
# 推送到 main 分支时触发
push:
branches: [main]
# 创建或更新针对 main 分支的 PR 时触发
pull_request:
branches: [main]
# 定时触发 (Cron 表达式)
schedule:
- cron: "0 2 * * 1" # 每周一凌晨 2 点
# 手动触发
workflow_dispatch:
# 发布新版本时触发
release:
types: [created]
# 合并 PR 时触发
merge_group:
types: [checks_requested]
高级 on
配置
-
路径过滤:只在特定文件更改时触发。
yamlon: push: paths: - "src/**" - "package.json"
-
标签过滤:只在推送到特定标签时触发。
yamlon: push: tags: - "v*.*.*"
-
多事件组合:一个工作流响应多个事件。
yamlon: [push, pull_request]
2.3 jobs
字段:作业定义
jobs
是一个映射(Map),包含一个或多个作业。
2.3.1 runs-on
:指定运行器
yaml
jobs:
build:
runs-on: ubuntu-latest # 最新 Ubuntu
# runs-on: windows-latest
# runs-on: macos-latest
# runs-on: self-hosted # 自托管运行器
2.3.2 steps
:步骤详解
每个步骤可以是:
-
使用
uses
调用 Action:yaml- name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 获取完整历史
-
使用
run
执行 Shell 命令:yaml- name: Print environment run: | echo "Hello World" echo "Current branch: ${{ github.ref }}"
-
使用
id
标识步骤:方便后续步骤引用。yaml- id: get_version run: echo "VERSION=$(cat VERSION.txt)" >> $GITHUB_OUTPUT
2.3.3 env
:环境变量
在作业级别定义环境变量,对所有步骤生效。
yaml
jobs:
build:
runs-on: ubuntu-latest
env:
NODE_ENV: production
API_URL: https://api.example.com
2.3.4 strategy
:矩阵策略
用于并行运行多个配置的作业。
yaml
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
2.3.5 if
条件判断
控制步骤或作业是否执行。
yaml
jobs:
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' # 仅在 main 分支执行
steps:
- name: Deploy to production
if: steps.test.outcome == 'success' # 仅当测试成功时部署
run: ./deploy.sh
3. 高级工作流配置
3.1 作业依赖与顺序
使用 needs
定义作业间的依赖关系。
yaml
jobs:
setup:
runs-on: ubuntu-latest
steps:
- run: echo "Setup complete"
build:
needs: setup
runs-on: ubuntu-latest
steps:
- run: echo "Building..."
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: echo "Testing..."
# 部署作业需要 setup 和 build 都成功
deploy:
needs: [setup, build]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- run: echo "Deploying..."
3.2 输出与上下文
3.2.1 步骤输出 (outputs
)
允许一个步骤将值传递给后续步骤或作业。
yaml
jobs:
job1:
runs-on: ubuntu-latest
outputs:
result: ${{ steps.step1.outputs.test_result }}
steps:
- id: step1
run: echo "test_result=success" >> $GITHUB_OUTPUT
job2:
needs: job1
runs-on: ubuntu-latest
steps:
- run: echo "Job1 result was ${{ needs.job1.outputs.result }}"
3.2.2 环境变量 (env
)
除了在作业级别,也可以在步骤级别设置。
yaml
- name: Set env var
run: echo "MY_VAR=value" >> $GITHUB_ENV
- name: Use env var
run: echo "My var is $MY_VAR"
3.3 机密 (Secrets)
用于存储敏感信息,如 API 密钥、密码。
yaml
- name: Deploy
run: ./deploy.sh
env:
API_KEY: ${{ secrets.API_KEY }} # 从仓库 Settings -> Secrets 中获取
3.4 缓存依赖
加速工作流执行,避免重复下载依赖。
yaml
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
3.5 工件 (Artifacts)
在作业间或工作流后保存文件。
yaml
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results.xml
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: test-results
path: results/
4. 实用工作流示例
4.1 完整的 Node.js CI/CD 流程
yaml
name: Node.js CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# 单元测试
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- run: npm ci
- run: npm test
- name: Upload coverage
if: matrix.node-version == '20'
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
# 构建和部署 (仅 main 分支)
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci
- run: npm run build
- name: Deploy to Production
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
echo "$DEPLOY_KEY" > deploy_key
chmod 600 deploy_key
ssh -i deploy_key user@server "cd /app && git pull && npm install && pm2 restart app"
4.2 Python 项目工作流
yaml
name: Python CI
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install flake8
- run: flake8 .
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9, 3.10, 3.11]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- run: pip install -r requirements.txt
- run: python -m pytest
5. 最佳实践与技巧
- 命名规范:为工作流、作业、步骤使用清晰、有意义的名称。
- 版本锁定 :始终为使用的 Actions 指定具体版本(如
@v4
),避免因 Action 更新导致工作流中断。 - 缓存利用:合理使用缓存大幅缩短执行时间。
- 矩阵测试 :利用
strategy.matrix
在不同环境(OS、语言版本)下测试。 - 条件执行 :使用
if
避免不必要的执行,节省资源。 - 错误处理:确保关键步骤失败时工作流能正确终止。
- 日志记录 :添加
name
和适当的echo
命令,便于调试。 - 安全第一 :敏感信息使用
secrets
,避免硬编码。 - 模块化:对于复杂流程,考虑使用复合运行器或自定义 Actions。
- 文档化:在工作流文件中添加注释,说明其目的和逻辑。
6. 调试与故障排除
- 查看日志:GitHub Actions UI 提供详细的步骤日志。
- 启用调试日志 :在仓库 Secrets 中设置
ACTIONS_RUNNER_DEBUG
为true
。 - 本地测试 :使用
act
工具在本地运行工作流。 - 检查语法:使用 YAML 验证工具或 GitHub 的语法检查。
结语
GitHub Actions 工作流文件是实现自动化 CI/CD 的核心。通过掌握其语法、结构和最佳实践,你可以构建高效、可靠、可维护的自动化流程,显著提升软件开发和交付的效率。从简单的测试到复杂的多阶段部署,GitHub Actions 提供了强大的灵活性和控制力。不断实践和探索,你将能充分利用其潜力,为你的项目赋能。
提示:GitHub 官方文档是学习和参考的最佳资源。随着新功能的不断推出,保持关注官方更新至关重要。