github-actions

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

GitHub Actions CI/CD

GitHub Actions CI/CD

Summary

概述

GitHub Actions is GitHub's native CI/CD platform for automating software workflows. Define workflows in YAML files to build, test, and deploy code directly from your repository with event-driven automation.
GitHub Actions是GitHub原生的CI/CD平台,用于自动化软件工作流。通过YAML文件定义工作流,借助事件驱动的自动化机制,直接从代码仓库中完成代码的构建、测试与部署。

When to Use

使用场景

  • Automate testing on every pull request
  • Build and deploy applications on merge to main
  • Schedule regular tasks (nightly builds, backups)
  • Publish packages to registries (npm, PyPI, Docker Hub)
  • Run security scans and code quality checks
  • Automate release processes and changelog generation
  • 为每个Pull Request自动执行测试
  • 代码合并到main分支时自动构建并部署应用
  • 定期调度任务(夜间构建、备份)
  • 将包发布到注册中心(npm、PyPI、Docker Hub)
  • 运行安全扫描与代码质量检查
  • 自动化发布流程与变更日志生成

Quick Start

快速开始

Basic Test Workflow

基础测试工作流

Create
.github/workflows/test.yml
:
yaml
name: Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

创建
.github/workflows/test.yml
:
yaml
name: Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

Complete GitHub Actions Guide

GitHub Actions 完整指南

Core Concepts

核心概念

Workflows

Workflows

YAML files in
.github/workflows/
that define automation pipelines.
Structure:
  • Name: Workflow identifier
  • Triggers: Events that start the workflow
  • Jobs: One or more jobs to execute
  • Steps: Commands/actions within each job
yaml
name: CI Pipeline
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Building project"
位于
.github/workflows/
目录下的YAML文件,用于定义自动化流水线。
结构:
  • Name: 工作流标识符
  • Triggers: 触发工作流的事件
  • Jobs: 要执行的一个或多个作业
  • Steps: 每个作业中的命令/动作
yaml
name: CI Pipeline
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Building project"

Jobs

Jobs

Independent execution units that run in parallel by default.
yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    needs: lint  # Wait for lint to complete
    steps:
      - run: npm test

  deploy:
    runs-on: ubuntu-latest
    needs: [lint, test]  # Wait for both
    steps:
      - run: ./deploy.sh
独立的执行单元,默认并行运行。
yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    needs: lint  # 等待lint作业完成
    steps:
      - run: npm test

  deploy:
    runs-on: ubuntu-latest
    needs: [lint, test]  # 等待两个作业完成
    steps:
      - run: ./deploy.sh

Steps

Steps

Sequential commands or actions within a job.
yaml
steps:
  # Use pre-built action
  - uses: actions/checkout@v4

  # Run shell command
  - run: npm install

  # Named step with environment
  - name: Run tests
    run: npm test
    env:
      NODE_ENV: test
作业中的顺序命令或动作。
yaml
steps:
  # 使用预构建的Action
  - uses: actions/checkout@v4

  # 运行Shell命令
  - run: npm install

  # 带环境变量的命名步骤
  - name: Run tests
    run: npm test
    env:
      NODE_ENV: test

Actions

Actions

Reusable units of code (from marketplace or custom).
yaml
undefined
可复用的代码单元(来自市场或自定义)。
yaml
undefined

Official action

官方Action

  • uses: actions/checkout@v4
  • uses: actions/checkout@v4

Third-party action

第三方Action

  • uses: docker/build-push-action@v5 with: context: . push: true tags: user/app:latest
  • uses: docker/build-push-action@v5 with: context: . push: true tags: user/app:latest

Local action

本地Action

  • uses: ./.github/actions/custom-action
undefined
  • uses: ./.github/actions/custom-action
undefined

Workflow Syntax

工作流语法

Triggers (on)

触发器(on)

Push Events

推送事件

yaml
on:
  push:
    branches:
      - main
      - 'releases/**'  # Wildcard pattern
    tags:
      - 'v*'  # All version tags
    paths:
      - 'src/**'
      - '!src/docs/**'  # Exclude docs
yaml
on:
  push:
    branches:
      - main
      - 'releases/**'  # 通配符模式
    tags:
      - 'v*'  # 所有版本标签
    paths:
      - 'src/**'
      - '!src/docs/**'  # 排除文档目录

Pull Request Events

Pull Request事件

yaml
on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches: [main, develop]
    paths-ignore:
      - '**.md'
      - 'docs/**'
yaml
on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches: [main, develop]
    paths-ignore:
      - '**.md'
      - 'docs/**'

Schedule (Cron)

定时调度(Cron)

yaml
on:
  schedule:
    # Every day at 2:30 AM UTC
    - cron: '30 2 * * *'
    # Every Monday at 9:00 AM UTC
    - cron: '0 9 * * 1'
yaml
on:
  schedule:
    # 每天UTC时间2:30执行
    - cron: '30 2 * * *'
    # 每周一UTC时间9:00执行
    - cron: '0 9 * * 1'

Manual Trigger

手动触发

yaml
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deployment environment'
        required: true
        type: choice
        options:
          - staging
          - production
      version:
        description: 'Version to deploy'
        required: false
        default: 'latest'
yaml
on:
  workflow_dispatch:
    inputs:
      environment:
        description: '部署环境'
        required: true
        type: choice
        options:
          - staging
          - production
      version:
        description: '要部署的版本'
        required: false
        default: 'latest'

Multiple Triggers

多触发器

yaml
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 0 * * 0'  # Weekly
  workflow_dispatch:  # Manual
yaml
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 0 * * 0'  # 每周执行
  workflow_dispatch:  # 手动触发

Environment Variables

环境变量

Workflow-level

工作流级别

yaml
env:
  NODE_ENV: production
  API_URL: https://api.example.com

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo $NODE_ENV
yaml
env:
  NODE_ENV: production
  API_URL: https://api.example.com

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo $NODE_ENV

Job-level

作业级别

yaml
jobs:
  test:
    runs-on: ubuntu-latest
    env:
      TEST_DATABASE: test_db
    steps:
      - run: pytest
yaml
jobs:
  test:
    runs-on: ubuntu-latest
    env:
      TEST_DATABASE: test_db
    steps:
      - run: pytest

Step-level

步骤级别

yaml
steps:
  - name: Build
    run: npm run build
    env:
      BUILD_TARGET: production
yaml
steps:
  - name: Build
    run: npm run build
    env:
      BUILD_TARGET: production

Secrets

Secrets

Store sensitive data in repository settings.
yaml
steps:
  - name: Deploy
    run: ./deploy.sh
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
Best Practices:
  • Never commit secrets to code
  • Use GitHub encrypted secrets
  • Limit secret access to specific environments
  • Rotate secrets regularly
在仓库设置中存储敏感数据。
yaml
steps:
  - name: Deploy
    run: ./deploy.sh
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
最佳实践:
  • 切勿将Secrets提交到代码中
  • 使用GitHub加密Secrets
  • 限制Secrets对特定环境的访问
  • 定期轮换Secrets

Contexts

上下文

github Context

github上下文

Repository and workflow information.
yaml
steps:
  - name: Print context
    run: |
      echo "Repository: ${{ github.repository }}"
      echo "Ref: ${{ github.ref }}"
      echo "SHA: ${{ github.sha }}"
      echo "Actor: ${{ github.actor }}"
      echo "Event: ${{ github.event_name }}"
      echo "Branch: ${{ github.ref_name }}"
包含仓库与工作流的相关信息。
yaml
steps:
  - name: Print context
    run: |
      echo "Repository: ${{ github.repository }}"
      echo "Ref: ${{ github.ref }}"
      echo "SHA: ${{ github.sha }}"
      echo "Actor: ${{ github.actor }}"
      echo "Event: ${{ github.event_name }}"
      echo "Branch: ${{ github.ref_name }}"

env Context

env上下文

Access environment variables.
yaml
env:
  BUILD_ID: 12345

steps:
  - run: echo "Build ${{ env.BUILD_ID }}"
用于访问环境变量。
yaml
env:
  BUILD_ID: 12345

steps:
  - run: echo "Build ${{ env.BUILD_ID }}"

secrets Context

secrets上下文

Access repository secrets.
yaml
- run: echo "Token exists"
  env:
    TOKEN: ${{ secrets.GITHUB_TOKEN }}
用于访问仓库Secrets。
yaml
- run: echo "Token exists"
  env:
    TOKEN: ${{ secrets.GITHUB_TOKEN }}

matrix Context

matrix上下文

Access matrix values.
yaml
strategy:
  matrix:
    node: [18, 20, 22]
steps:
  - run: echo "Testing Node ${{ matrix.node }}"
用于访问矩阵值。
yaml
strategy:
  matrix:
    node: [18, 20, 22]
steps:
  - run: echo "Testing Node ${{ matrix.node }}"

needs Context

needs上下文

Access outputs from dependent jobs.
yaml
jobs:
  build:
    outputs:
      version: ${{ steps.get_version.outputs.version }}
    steps:
      - id: get_version
        run: echo "version=1.2.3" >> $GITHUB_OUTPUT

  deploy:
    needs: build
    steps:
      - run: echo "Deploying ${{ needs.build.outputs.version }}"
用于访问依赖作业的输出。
yaml
jobs:
  build:
    outputs:
      version: ${{ steps.get_version.outputs.version }}
    steps:
      - id: get_version
        run: echo "version=1.2.3" >> $GITHUB_OUTPUT

  deploy:
    needs: build
    steps:
      - run: echo "Deploying ${{ needs.build.outputs.version }}"

Runners

Runners

GitHub-hosted Runners

GitHub托管的Runners

yaml
jobs:
  ubuntu:
    runs-on: ubuntu-latest  # ubuntu-22.04

  macos:
    runs-on: macos-latest  # macOS 14

  windows:
    runs-on: windows-latest  # Windows 2022

  specific:
    runs-on: ubuntu-20.04  # Specific version
Available Runners:
  • ubuntu-latest
    ,
    ubuntu-22.04
    ,
    ubuntu-20.04
  • macos-latest
    ,
    macos-14
    ,
    macos-13
  • windows-latest
    ,
    windows-2022
    ,
    windows-2019
yaml
jobs:
  ubuntu:
    runs-on: ubuntu-latest  # ubuntu-22.04

  macos:
    runs-on: macos-latest  # macOS 14

  windows:
    runs-on: windows-latest  # Windows 2022

  specific:
    runs-on: ubuntu-20.04  # 指定版本
可用的Runners:
  • ubuntu-latest
    ,
    ubuntu-22.04
    ,
    ubuntu-20.04
  • macos-latest
    ,
    macos-14
    ,
    macos-13
  • windows-latest
    ,
    windows-2022
    ,
    windows-2019

Self-hosted Runners

自托管Runners

yaml
runs-on: self-hosted
yaml
runs-on: self-hosted

With labels

带标签

runs-on: [self-hosted, linux, x64, gpu]

**Setup**:
1. Go to Settings → Actions → Runners
2. Click "New self-hosted runner"
3. Follow platform-specific instructions
4. Add custom labels for targeting
runs-on: [self-hosted, linux, x64, gpu]

**设置步骤**:
1. 进入仓库的Settings → Actions → Runners
2. 点击"New self-hosted runner"
3. 按照平台专属的说明操作
4. 添加自定义标签用于定向触发

Matrix Strategies

矩阵策略

Basic Matrix

基础矩阵

Test across multiple versions.
yaml
strategy:
  matrix:
    node: [18, 20, 22]
    os: [ubuntu-latest, macos-latest, windows-latest]

runs-on: ${{ matrix.os }}
steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node }}
在多个版本间进行测试。
yaml
strategy:
  matrix:
    node: [18, 20, 22]
    os: [ubuntu-latest, macos-latest, windows-latest]

runs-on: ${{ matrix.os }}
steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node }}

Include/Exclude

包含/排除

yaml
strategy:
  matrix:
    node: [18, 20, 22]
    os: [ubuntu-latest, windows-latest]
    include:
      # Add specific combination
      - node: 22
        os: macos-latest
        experimental: true
    exclude:
      # Remove specific combination
      - node: 18
        os: windows-latest
yaml
strategy:
  matrix:
    node: [18, 20, 22]
    os: [ubuntu-latest, windows-latest]
    include:
      # 添加特定组合
      - node: 22
        os: macos-latest
        experimental: true
    exclude:
      # 移除特定组合
      - node: 18
        os: windows-latest

Fail-fast

快速失败

yaml
strategy:
  fail-fast: false  # Continue other jobs if one fails
  matrix:
    node: [18, 20, 22]
yaml
strategy:
  fail-fast: false  # 即使一个作业失败,继续执行其他作业
  matrix:
    node: [18, 20, 22]

Max Parallel

最大并行数

yaml
strategy:
  max-parallel: 2  # Run only 2 jobs concurrently
  matrix:
    node: [18, 20, 22]
yaml
strategy:
  max-parallel: 2  # 同时仅运行2个作业
  matrix:
    node: [18, 20, 22]

Common Actions

常用Actions

Checkout Code

检出代码

yaml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0  # Full history for changelog
    submodules: true  # Include submodules
yaml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0  # 获取完整历史用于生成变更日志
    submodules: true  # 包含子模块

Setup Node.js

配置Node.js

yaml
- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'  # or 'yarn', 'pnpm'
    registry-url: 'https://registry.npmjs.org'
yaml
- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'  # 或'yarn'、'pnpm'
    registry-url: 'https://registry.npmjs.org'

Setup Python

配置Python

yaml
- uses: actions/setup-python@v5
  with:
    python-version: '3.11'
    cache: 'pip'
yaml
- uses: actions/setup-python@v5
  with:
    python-version: '3.11'
    cache: 'pip'

Setup Java

配置Java

yaml
- uses: actions/setup-java@v4
  with:
    distribution: 'temurin'
    java-version: '17'
    cache: 'maven'
yaml
- uses: actions/setup-java@v4
  with:
    distribution: 'temurin'
    java-version: '17'
    cache: 'maven'

Setup Go

配置Go

yaml
- uses: actions/setup-go@v5
  with:
    go-version: '1.21'
    cache: true
yaml
- uses: actions/setup-go@v5
  with:
    go-version: '1.21'
    cache: true

Cache Dependencies

缓存依赖

yaml
- uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-
yaml
- uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

Upload Artifacts

上传产物

yaml
- uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: dist/
    retention-days: 7
yaml
- uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: dist/
    retention-days: 7

Download Artifacts

下载产物

yaml
- uses: actions/download-artifact@v4
  with:
    name: build-output
    path: dist/
yaml
- uses: actions/download-artifact@v4
  with:
    name: build-output
    path: dist/

Conditional Execution

条件执行

if Conditions

if条件

yaml
steps:
  - name: Deploy to production
    if: github.ref == 'refs/heads/main'
    run: ./deploy.sh

  - name: Deploy to staging
    if: github.ref == 'refs/heads/develop'
    run: ./deploy-staging.sh

  - name: Only on PR
    if: github.event_name == 'pull_request'
    run: echo "This is a PR"

  - name: On success
    if: success()
    run: echo "Previous steps succeeded"

  - name: On failure
    if: failure()
    run: echo "A step failed"

  - name: Always run
    if: always()
    run: echo "Cleanup tasks"
yaml
steps:
  - name: 部署到生产环境
    if: github.ref == 'refs/heads/main'
    run: ./deploy.sh

  - name: 部署到预发布环境
    if: github.ref == 'refs/heads/develop'
    run: ./deploy-staging.sh

  - name: 仅在PR时执行
    if: github.event_name == 'pull_request'
    run: echo "这是一个Pull Request"

  - name: 成功时执行
    if: success()
    run: echo "之前的步骤执行成功"

  - name: 失败时执行
    if: failure()
    run: echo "某个步骤执行失败"

  - name: 始终执行
    if: always()
    run: echo "执行清理任务"

Job Conditions

作业条件

yaml
jobs:
  deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh
yaml
jobs:
  deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh

Framework-Specific Workflows

框架专属工作流

Node.js/TypeScript

Node.js/TypeScript

yaml
name: Node.js CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - run: npm ci

      - run: npm run lint

      - run: npm run type-check

      - run: npm test
        env:
          CI: true

      - run: npm run build

      - uses: codecov/codecov-action@v4
        if: matrix.node-version == 20
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
yaml
name: Node.js CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - run: npm ci

      - run: npm run lint

      - run: npm run type-check

      - run: npm test
        env:
          CI: true

      - run: npm run build

      - uses: codecov/codecov-action@v4
        if: matrix.node-version == 20
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

Python

Python

yaml
name: Python CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'

      - run: pip install -r requirements.txt

      - run: pip install pytest pytest-cov mypy ruff

      - run: ruff check .

      - run: mypy .

      - run: pytest --cov=. --cov-report=xml

      - uses: codecov/codecov-action@v4
        if: matrix.python-version == '3.11'
yaml
name: Python CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'

      - run: pip install -r requirements.txt

      - run: pip install pytest pytest-cov mypy ruff

      - run: ruff check .

      - run: mypy .

      - run: pytest --cov=. --cov-report=xml

      - uses: codecov/codecov-action@v4
        if: matrix.python-version == '3.11'

Docker

Docker

yaml
name: Docker Build

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: user/app
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
yaml
name: Docker Build

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: user/app
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Next.js with Vercel

Next.js + Vercel

yaml
name: Next.js CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm run lint

      - run: npm run build

      - run: npm test

  deploy-preview:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4

      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

  deploy-production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4

      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
yaml
name: Next.js CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm run lint

      - run: npm run build

      - run: npm test

  deploy-preview:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4

      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

  deploy-production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4

      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

Deployment Patterns

部署模式

Vercel Deployment

Vercel部署

yaml
name: Deploy to Vercel

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
yaml
name: Deploy to Vercel

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

Netlify Deployment

Netlify部署

yaml
name: Deploy to Netlify

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm run build

      - uses: netlify/actions/cli@master
        with:
          args: deploy --prod --dir=dist
        env:
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
yaml
name: Deploy to Netlify

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm run build

      - uses: netlify/actions/cli@master
        with:
          args: deploy --prod --dir=dist
        env:
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}

AWS S3 + CloudFront

AWS S3 + CloudFront

yaml
name: Deploy to AWS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm run build

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - run: aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete

      - run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"
yaml
name: Deploy to AWS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm run build

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - run: aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete

      - run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"

Docker Registry Push

Docker镜像仓库推送

yaml
name: Publish Docker Image

on:
  release:
    types: [published]

jobs:
  push:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:latest
            ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }}
yaml
name: Publish Docker Image

on:
  release:
    types: [published]

jobs:
  push:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:latest
            ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }}

Testing Workflows

测试工作流

Unit Tests with Coverage

带覆盖率的单元测试

yaml
name: Test Coverage

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm test -- --coverage

      - uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: ./coverage/coverage-final.json
          fail_ci_if_error: true
yaml
name: Test Coverage

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm test -- --coverage

      - uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: ./coverage/coverage-final.json
          fail_ci_if_error: true

Integration Tests

集成测试

yaml
name: Integration Tests

on: [push, pull_request]

jobs:
  integration:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

      redis:
        image: redis:7
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 6379:6379

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - run: npm run test:integration
        env:
          DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
          REDIS_URL: redis://localhost:6379
yaml
name: Integration Tests

on: [push, pull_request]

jobs:
  integration:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

      redis:
        image: redis:7
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 6379:6379

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - run: npm run test:integration
        env:
          DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
          REDIS_URL: redis://localhost:6379

E2E Tests with Playwright

基于Playwright的E2E测试

yaml
name: E2E Tests

on: [push, pull_request]

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npx playwright install --with-deps

      - run: npm run build

      - run: npm run test:e2e

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30
yaml
name: E2E Tests

on: [push, pull_request]

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npx playwright install --with-deps

      - run: npm run build

      - run: npm run test:e2e

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

Release Automation

发布自动化

Semantic Release

语义化发布

yaml
name: Release

on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for changelog

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
yaml
name: Release

on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # 获取完整历史用于生成变更日志

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Create Release with Changelog

生成变更日志并创建发布

yaml
name: Create Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Generate changelog
        id: changelog
        run: |
          # Generate changelog from commits
          CHANGELOG=$(git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --pretty=format:"- %s (%h)" --no-merges)
          echo "changelog<<EOF" >> $GITHUB_OUTPUT
          echo "$CHANGELOG" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref_name }}
          release_name: Release ${{ github.ref_name }}
          body: |
            ## Changes
            ${{ steps.changelog.outputs.changelog }}
          draft: false
          prerelease: false
yaml
name: Create Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: 生成变更日志
        id: changelog
        run: |
          # 从提交记录生成变更日志
          CHANGELOG=$(git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --pretty=format:"- %s (%h)" --no-merges)
          echo "changelog<<EOF" >> $GITHUB_OUTPUT
          echo "$CHANGELOG" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref_name }}
          release_name: Release ${{ github.ref_name }}
          body: |
            ## 变更内容
            ${{ steps.changelog.outputs.changelog }}
          draft: false
          prerelease: false

Publish npm Package

发布npm包

yaml
name: Publish to npm

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'

      - run: npm ci

      - run: npm test

      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
yaml
name: Publish to npm

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'

      - run: npm ci

      - run: npm test

      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Security Scanning

安全扫描

CodeQL Analysis

CodeQL分析

yaml
name: CodeQL

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 0 * * 1'  # Weekly

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: ['javascript', 'python']

    steps:
      - uses: actions/checkout@v4

      - uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}

      - uses: github/codeql-action/autobuild@v3

      - uses: github/codeql-action/analyze@v3
yaml
name: CodeQL

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 0 * * 1'  # 每周执行

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: ['javascript', 'python']

    steps:
      - uses: actions/checkout@v4

      - uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}

      - uses: github/codeql-action/autobuild@v3

      - uses: github/codeql-action/analyze@v3

Dependency Scanning

依赖扫描

yaml
name: Dependency Check

on:
  push:
    branches: [main]
  schedule:
    - cron: '0 0 * * 1'

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm audit --audit-level=moderate

      - run: npx snyk test
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        continue-on-error: true
yaml
name: Dependency Check

on:
  push:
    branches: [main]
  schedule:
    - cron: '0 0 * * 1'

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm audit --audit-level=moderate

      - run: npx snyk test
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        continue-on-error: true

Trivy Container Scan

Trivy容器扫描

yaml
name: Container Security Scan

on:
  push:
    branches: [main]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - run: docker build -t myapp:${{ github.sha }} .

      - uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          format: 'sarif'
          output: 'trivy-results.sarif'

      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: 'trivy-results.sarif'
yaml
name: Container Security Scan

on:
  push:
    branches: [main]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - run: docker build -t myapp:${{ github.sha }} .

      - uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          format: 'sarif'
          output: 'trivy-results.sarif'

      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: 'trivy-results.sarif'

Composite Actions

复合Actions

Create reusable actions in
.github/actions/
.
.github/actions/
目录下创建可复用的Actions。

Simple Composite Action

简单复合Action

.github/actions/setup-project/action.yml
:
yaml
name: 'Setup Project'
description: 'Install dependencies and cache'

inputs:
  node-version:
    description: 'Node.js version'
    required: false
    default: '20'

runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: 'npm'

    - run: npm ci
      shell: bash
Usage:
yaml
steps:
  - uses: actions/checkout@v4
  - uses: ./.github/actions/setup-project
    with:
      node-version: '20'
.github/actions/setup-project/action.yml
:
yaml
name: 'Setup Project'
description: 'Install dependencies and cache'

inputs:
  node-version:
    description: 'Node.js version'
    required: false
    default: '20'

runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: 'npm'

    - run: npm ci
      shell: bash
使用方式:
yaml
steps:
  - uses: actions/checkout@v4
  - uses: ./.github/actions/setup-project
    with:
      node-version: '20'

Reusable Workflows

可复用工作流

.github/workflows/reusable-deploy.yml
:
yaml
name: Reusable Deploy

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
    secrets:
      deploy-token:
        required: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - uses: actions/checkout@v4

      - run: ./deploy.sh
        env:
          DEPLOY_TOKEN: ${{ secrets.deploy-token }}
          ENVIRONMENT: ${{ inputs.environment }}
Usage:
yaml
name: Deploy Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    uses: ./.github/workflows/reusable-deploy.yml
    with:
      environment: production
    secrets:
      deploy-token: ${{ secrets.PRODUCTION_TOKEN }}
.github/workflows/reusable-deploy.yml
:
yaml
name: Reusable Deploy

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
    secrets:
      deploy-token:
        required: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - uses: actions/checkout@v4

      - run: ./deploy.sh
        env:
          DEPLOY_TOKEN: ${{ secrets.deploy-token }}
          ENVIRONMENT: ${{ inputs.environment }}
使用方式:
yaml
name: Deploy Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    uses: ./.github/workflows/reusable-deploy.yml
    with:
      environment: production
    secrets:
      deploy-token: ${{ secrets.PRODUCTION_TOKEN }}

Performance Optimization

性能优化

Dependency Caching

依赖缓存

yaml
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-
yaml
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

Docker Layer Caching

Docker层缓存

yaml
- uses: docker/build-push-action@v5
  with:
    context: .
    cache-from: type=gha
    cache-to: type=gha,mode=max
yaml
- uses: docker/build-push-action@v5
  with:
    context: .
    cache-from: type=gha
    cache-to: type=gha,mode=max

Parallelization

并行化

yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test-unit:
    runs-on: ubuntu-latest
    steps:
      - run: npm run test:unit

  test-integration:
    runs-on: ubuntu-latest
    steps:
      - run: npm run test:integration

  # All run in parallel
yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test-unit:
    runs-on: ubuntu-latest
    steps:
      - run: npm run test:unit

  test-integration:
    runs-on: ubuntu-latest
    steps:
      - run: npm run test:integration

  # 所有作业并行运行

Conditional Job Execution

条件作业执行

yaml
jobs:
  deploy:
    # Skip deploy on draft PRs
    if: github.event.pull_request.draft == false
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh
yaml
jobs:
  deploy:
    # 草稿PR跳过部署
    if: github.event.pull_request.draft == false
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh

Debugging Workflows

工作流调试

Enable Debug Logging

启用调试日志

Set repository secrets:
  • ACTIONS_RUNNER_DEBUG
    :
    true
  • ACTIONS_STEP_DEBUG
    :
    true
设置仓库Secrets:
  • ACTIONS_RUNNER_DEBUG
    :
    true
  • ACTIONS_STEP_DEBUG
    :
    true

Debug Step

调试步骤

yaml
- name: Debug Info
  run: |
    echo "Event: ${{ github.event_name }}"
    echo "Ref: ${{ github.ref }}"
    echo "SHA: ${{ github.sha }}"
    echo "Actor: ${{ github.actor }}"
    env
yaml
- name: 调试信息
  run: |
    echo "事件: ${{ github.event_name }}"
    echo "Ref: ${{ github.ref }}"
    echo "SHA: ${{ github.sha }}"
    echo "执行者: ${{ github.actor }}"
    env

Interactive Debugging with tmate

使用tmate进行交互式调试

yaml
- name: Setup tmate session
  if: failure()
  uses: mxschmitt/action-tmate@v3
  timeout-minutes: 15
yaml
- name: 启动tmate会话
  if: failure()
  uses: mxschmitt/action-tmate@v3
  timeout-minutes: 15

Best Practices

最佳实践

Security

安全

  • Use secrets for sensitive data
  • Pin action versions to SHA:
    uses: actions/checkout@8e5e7e5a...
  • Minimize token permissions
  • Use environment protection rules
  • Enable branch protection with required checks
  • 使用Secrets存储敏感数据
  • 将Action版本固定到SHA:
    uses: actions/checkout@8e5e7e5a...
  • 最小化令牌权限
  • 使用环境保护规则
  • 启用分支保护并设置必需检查

Performance

性能

  • Cache dependencies aggressively
  • Use matrix strategies for parallel testing
  • Minimize checkout depth when possible
  • Use artifacts for job-to-job data transfer
  • Optimize Docker builds with multi-stage builds
  • 积极缓存依赖
  • 使用矩阵策略进行并行测试
  • 尽可能最小化检出深度
  • 使用产物在作业间传输数据
  • 使用多阶段构建优化Docker镜像

Maintainability

可维护性

  • Use reusable workflows for common patterns
  • Create composite actions for repeated steps
  • Document workflow purpose and triggers
  • Use meaningful job and step names
  • Keep workflows focused (single responsibility)
  • 对通用模式使用可复用工作流
  • 为重复步骤创建复合Actions
  • 记录工作流的用途与触发器
  • 使用有意义的作业和步骤名称
  • 保持工作流聚焦(单一职责)

Reliability

可靠性

  • Set appropriate timeouts
  • Use
    continue-on-error
    strategically
  • Implement retry logic for flaky tests
  • Monitor workflow run times
  • Clean up old artifacts and caches
  • 设置合理的超时时间
  • 策略性使用
    continue-on-error
  • 为不稳定的测试实现重试逻辑
  • 监控工作流运行时间
  • 清理旧的产物与缓存

Common Patterns

常见模式

PR Comment on Failure

PR失败时添加评论

yaml
- name: Comment on PR
  if: failure() && github.event_name == 'pull_request'
  uses: actions/github-script@v7
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '❌ Tests failed. Please check the workflow logs.'
      })
yaml
- name: 在PR上添加评论
  if: failure() && github.event_name == 'pull_request'
  uses: actions/github-script@v7
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '❌ 测试失败,请查看工作流日志。'
      })

Auto-merge Dependabot PRs

自动合并Dependabot PR

yaml
name: Auto-merge Dependabot

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  auto-merge:
    if: github.actor == 'dependabot[bot]'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - run: npm ci
      - run: npm test

      - uses: gh enable-auto-merge --merge
        if: success()
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
yaml
name: Auto-merge Dependabot

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  auto-merge:
    if: github.actor == 'dependabot[bot]'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - run: npm ci
      - run: npm test

      - uses: gh enable-auto-merge --merge
        if: success()
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Notify on Deploy

部署通知

yaml
- name: Slack Notification
  if: always()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    text: 'Deploy to ${{ inputs.environment }}: ${{ job.status }}'
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}
yaml
- name: Slack通知
  if: always()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    text: '部署到${{ inputs.environment }}: ${{ job.status }}'
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Troubleshooting

故障排除

Common Issues

常见问题

Workflow not triggering:
  • Check branch filters match actual branch names
  • Verify workflow file is in
    .github/workflows/
  • Ensure YAML syntax is valid
Job skipped:
  • Check
    if
    conditions
  • Verify
    needs
    dependencies succeeded
  • Check branch protection rules
Timeout:
  • Default timeout is 360 minutes
  • Set explicit timeout:
    timeout-minutes: 30
  • Optimize long-running steps
Permission denied:
  • Update workflow permissions:
    yaml
    permissions:
      contents: write
      pull-requests: write
Secrets not available:
  • Verify secret names match exactly (case-sensitive)
  • Check secret scope (repo, organization, environment)
  • Ensure workflow has access to environment secrets

工作流未触发:
  • 检查分支过滤器与实际分支名称是否匹配
  • 验证工作流文件是否位于
    .github/workflows/
    目录下
  • 确保YAML语法有效
作业被跳过:
  • 检查
    if
    条件
  • 验证
    needs
    依赖是否执行成功
  • 检查分支保护规则
超时:
  • 默认超时时间为360分钟
  • 设置显式超时:
    timeout-minutes: 30
  • 优化长时间运行的步骤
权限被拒绝:
  • 更新工作流权限:
    yaml
    permissions:
      contents: write
      pull-requests: write
Secrets不可用:
  • 验证Secret名称是否完全匹配(区分大小写)
  • 检查Secret作用域(仓库、组织、环境)
  • 确保工作流有权访问环境Secrets

Local Workflow Patterns (Your Repos)

本地工作流模式(你的仓库)

Python + uv CI (mcp-vector-search)

Python + uv CI (mcp-vector-search)

  • Install uv:
    astral-sh/setup-uv@v3
    and
    uv python install 3.11
    .
  • Use
    uv sync --dev
    and run
    uv run ruff
    ,
    uv run mypy
    ,
    uv run pytest
    .
  • Use OS + Python version matrix and upload coverage to Codecov on linux.
  • 安装uv: 使用
    astral-sh/setup-uv@v3
    uv python install 3.11
  • 执行
    uv sync --dev
    ,然后运行
    uv run ruff
    uv run mypy
    uv run pytest
  • 使用操作系统+Python版本矩阵,并在Linux上将覆盖率数据上传到Codecov。

Node + pnpm CI (ai-code-review)

Node + pnpm CI (ai-code-review)

  • Use
    pnpm/action-setup@v4
    and
    actions/setup-node@v4
    with pnpm cache.
  • Install with
    pnpm install --frozen-lockfile
    , then
    pnpm run lint
    ,
    pnpm run build:types
    ,
    pnpm test
    .
  • 使用
    pnpm/action-setup@v4
    actions/setup-node@v4
    并配置pnpm缓存。
  • 执行
    pnpm install --frozen-lockfile
    ,然后运行
    pnpm run lint
    pnpm run build:types
    pnpm test

Release on Tags

标签触发发布

  • Trigger on
    push
    tags
    v*
    .
  • Build, create GitHub Release notes, and publish to npm or PyPI.
  • Use
    pypa/gh-action-pypi-publish@release/v1
    or
    NODE_AUTH_TOKEN
    for npm publish.
  • 触发条件为
    push
    标签
    v*
  • 构建、创建GitHub发布说明,并发布到npm或PyPI。
  • 使用
    pypa/gh-action-pypi-publish@release/v1
    NODE_AUTH_TOKEN
    进行npm发布。

Homebrew Update Pipeline

Homebrew更新流水线

  • Trigger on
    workflow_run
    after CI success.
  • Run
    scripts/update_homebrew_formula.py
    with
    HOMEBREW_TAP_TOKEN
    .
  • On failure, open an issue with manual update steps.
  • CI成功后通过
    workflow_run
    触发。
  • 使用
    HOMEBREW_TAP_TOKEN
    运行
    scripts/update_homebrew_formula.py
  • 失败时,创建包含手动更新步骤的Issue。

Resources

资源