ci-cd-pipelines

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CI/CD Pipelines

CI/CD 流水线

GitHub Actions Workflow

GitHub Actions 工作流

yaml
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck

  test:
    runs-on: ubuntu-latest
    needs: lint
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_DB: test
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
        ports: ["5432:5432"]
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test -- --coverage
        env:
          DATABASE_URL: postgres://test:test@localhost:5432/test
      - uses: codecov/codecov-action@v4

  deploy:
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/deploy.sh
Use
concurrency
to cancel stale runs. Use
needs
to define job dependencies.
yaml
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck

  test:
    runs-on: ubuntu-latest
    needs: lint
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_DB: test
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
        ports: ["5432:5432"]
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test -- --coverage
        env:
          DATABASE_URL: postgres://test:test@localhost:5432/test
      - uses: codecov/codecov-action@v4

  deploy:
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/deploy.sh
使用
concurrency
取消过时的运行任务。使用
needs
定义任务依赖关系。

GitLab CI Pipeline

GitLab CI 流水线

yaml
stages:
  - validate
  - test
  - build
  - deploy

variables:
  NODE_IMAGE: node:22-alpine

lint:
  stage: validate
  image: $NODE_IMAGE
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths: [node_modules/]
  script:
    - npm ci
    - npm run lint
    - npm run typecheck

test:
  stage: test
  image: $NODE_IMAGE
  services:
    - postgres:16
  variables:
    POSTGRES_DB: test
    DATABASE_URL: postgres://runner:@postgres:5432/test
  script:
    - npm ci
    - npm test -- --coverage
  coverage: '/Statements\s*:\s*(\d+\.?\d*)%/'
  artifacts:
    reports:
      junit: coverage/junit.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura.xml

build:
  stage: build
  image: docker:24
  services: [docker:24-dind]
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

deploy:
  stage: deploy
  environment:
    name: production
    url: https://app.example.com
  script:
    - ./deploy.sh $CI_COMMIT_SHA
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual
yaml
stages:
  - validate
  - test
  - build
  - deploy

variables:
  NODE_IMAGE: node:22-alpine

lint:
  stage: validate
  image: $NODE_IMAGE
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths: [node_modules/]
  script:
    - npm ci
    - npm run lint
    - npm run typecheck

test:
  stage: test
  image: $NODE_IMAGE
  services:
    - postgres:16
  variables:
    POSTGRES_DB: test
    DATABASE_URL: postgres://runner:@postgres:5432/test
  script:
    - npm ci
    - npm test -- --coverage
  coverage: '/Statements\s*:\s*(\d+\.?\d*)%/'
  artifacts:
    reports:
      junit: coverage/junit.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura.xml

build:
  stage: build
  image: docker:24
  services: [docker:24-dind]
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

deploy:
  stage: deploy
  environment:
    name: production
    url: https://app.example.com
  script:
    - ./deploy.sh $CI_COMMIT_SHA
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual

Reusable GitHub Action

可复用 GitHub Action

yaml
undefined
yaml
undefined

.github/actions/setup/action.yml

.github/actions/setup/action.yml

name: Setup description: Install dependencies and cache inputs: node-version: default: "22" runs: using: composite steps: - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} cache: npm - run: npm ci shell: bash

```yaml
name: Setup description: Install dependencies and cache inputs: node-version: default: "22" runs: using: composite steps: - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} cache: npm - run: npm ci shell: bash

```yaml

Usage in workflow

在工作流中使用

steps:
  • uses: actions/checkout@v4
  • uses: ./.github/actions/setup
  • run: npm test
undefined
steps:
  • uses: actions/checkout@v4
  • uses: ./.github/actions/setup
  • run: npm test
undefined

Matrix Strategy

矩阵构建策略

yaml
test:
  strategy:
    fail-fast: false
    matrix:
      node: [20, 22]
      os: [ubuntu-latest, macos-latest]
  runs-on: ${{ matrix.os }}
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node }}
    - run: npm ci && npm test
yaml
test:
  strategy:
    fail-fast: false
    matrix:
      node: [20, 22]
      os: [ubuntu-latest, macos-latest]
  runs-on: ${{ matrix.os }}
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node }}
    - run: npm ci && npm test

Anti-Patterns

反模式

  • Not caching dependencies (npm, pip, cargo) between runs
  • Running all jobs sequentially when lint and test can parallelize
  • Storing secrets in workflow files instead of repository/environment secrets
  • Missing
    concurrency
    groups causing redundant CI runs on rapid pushes
  • Not using
    fail-fast: false
    in matrix builds (one failure cancels others)
  • Deploying without an approval gate or environment protection rule
  • 不在运行任务之间缓存依赖(npm、pip、cargo)
  • lint和test可并行执行时却串行运行所有任务
  • 将密钥存储在工作流文件中,而非仓库/环境密钥管理处
  • 缺少
    concurrency
    分组,导致频繁推送时产生冗余CI运行任务
  • 矩阵构建中未使用
    fail-fast: false
    (一个任务失败会取消其他所有任务)
  • 未设置审批关口或环境保护规则就直接部署

Checklist

检查清单

  • Dependencies cached between CI runs
  • Concurrency groups cancel stale pipeline runs
  • Lint, typecheck, and test run as separate parallelizable jobs
  • Database services use health checks before tests start
  • Coverage reports uploaded and tracked
  • Deploy job requires approval for production
  • Reusable actions/templates extract common setup steps
  • Secrets stored in CI platform, never in code
  • CI运行任务之间已缓存依赖
  • 已配置并发分组取消过时的流水线运行任务
  • 代码检查、类型检查和测试作为独立的可并行任务运行
  • 数据库服务在测试启动前已通过健康检查
  • 覆盖率报告已上传并可追踪
  • 生产环境的部署任务需要审批
  • 已通过可复用的action/模板抽离通用的初始化步骤
  • 密钥存储在CI平台中,绝不硬编码在代码里