GitHub-Workflow 实操


传统开发流程的缺点

以前我们写完代码,往往是这样一套流程:本地改完 → 手动打包 → 手动测试 → 再手动丢到服务器上部署。看着简单,但项目一变大、人一变多,问题就出来了:

重复劳动多、容易出错

每次发版都要敲一堆命令,换台机器环境还可能不一样。别人机器能跑、你机器跑不了,服务器上更是玄学。一不小心少跑一步测试,线上就炸了。

这时 CI/CD 便应运而生。

什么是 CI/CD

CI(Continuous Integration,持续集成):代码合并后自动跑构建、测试,尽早发现问题。
CD(Continuous Delivery / Deployment,持续交付/部署):通过测试后,自动发布到测试环境或生产环境。

简单点说:把「打包、测试、部署」这些重复步骤写成脚本,交给机器自动干,人只负责写代码和看结果。

常见的 CI/CD 工具有 Jenkins、GitLab CI、Travis CI,以及今天要讲的 GitHub Actions

GitHub Actions

GitHub Actions 是 GitHub 提供的持续集成与持续交付平台,可以自动完成构建、测试和部署等流水线任务。你通过 YAML 文件定义工作流(Workflow),在指定事件发生时(比如 push、pull request)自动执行。

简单翻译下就是:

在仓库里放一份配置文件,告诉 GitHub:「什么时候跑、在什么环境跑、跑哪些命令」。事件一触发,GitHub 就帮你在云端机器上把这些事干完。

官方文档:GitHub Actions 文档

GitHub Actions 的核心是 Workflow(工作流),它由以下几部分组成

  • Workflow(工作流):一次完整的自动化流程,对应一个 YAML 文件
  • Event(事件):触发工作流的条件,如 push、pull_request、定时任务
  • Job(任务):工作流里的一组步骤,默认在同一台机器上顺序执行
  • Step(步骤):Job 里的最小执行单元,可以是一条命令,也可以是一个 Action
  • Action(动作):可复用的封装步骤,比如 checkout 代码、安装 Node
  • Runner(运行器):真正执行任务的机器,可以是 GitHub 托管的,也可以是自己的

可以粗暴理解成:

概念类比
Workflow一整条流水线
Event按下流水线的开关
Job流水线上的一个工位
Step工位里的每一道工序
Action别人做好的半成品工序
Runner真正干活的那台机器

配置文件放哪

Workflow 配置文件统一放在仓库根目录下:

.github/workflows/
  ├── ci.yml
  ├── deploy.yml
  └── release.yml
  • 目录必须是 .github/workflows/
  • 文件后缀一般是 .yml.yaml
  • 一个文件就是一个 Workflow,可以写多个

一份最简单的 Workflow

name: Hello Workflow

on:
  push:
    branches: [ main ]

jobs:
  say-hello:
    runs-on: ubuntu-latest
    steps:
      - name: 打印一句你好
        run: echo "Hello GitHub Actions"

简单翻译下这段配置:

当代码 push 到 main 分支时,在一台 Ubuntu 机器上跑一个叫 say-hello 的任务,任务里只干一件事:打印 Hello GitHub Actions

配置文件字段说明

顶层常用字段

字段作用
name工作流名称,会显示在 Actions 页面
on触发条件,决定什么时候跑
env全局环境变量,对所有 Job 生效
jobs定义有哪些 Job
defaults默认配置,比如默认的 shell、工作目录
concurrency并发控制,避免同一类任务同时跑多份

on:触发事件

这是 Workflow 的开关,常用的有:

事件作用
push推送代码时触发
pull_request创建或更新 PR 时触发
schedule定时触发(cron 表达式)
workflow_dispatch在网页上手动点一下运行
release发布 Release 时触发
workflow_call被其他工作流当作可复用流程调用

示例:

on:
  push:
    branches: [ main, develop ]
    paths:
      - 'src/**'
      - 'package.json'
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 2 * * *'   # 每天凌晨 2 点(UTC)
  workflow_dispatch:       # 允许手动触发

简单点说:

  • branches:限定分支
  • paths:只有改了指定路径才触发,避免无关改动白跑一遍
  • cron:定时任务,注意时间是 UTC,不是北京时间

jobs:任务定义

字段作用
runs-on指定运行环境,如 ubuntu-latest、windows-latest、macos-latest
needs依赖其他 Job,实现先后顺序
if条件表达式,满足才执行
env仅当前 Job 生效的环境变量
strategy矩阵构建,一次跑多种版本/系统
timeout-minutesJob 超时时间
permissions控制 GITHUB_TOKEN 的权限
services启动附属服务,比如临时起一个 MySQL、Redis

示例:Job 之间有依赖

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "先构建"

  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "构建完再测试"

  deploy:
    needs: [build, test]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - run: echo "只有 main 分支才部署"

steps:步骤

每个 Step 通常二选一:

  • run:直接执行 shell 命令
  • uses:引用一个现成的 Action
字段作用
name步骤名称,方便在日志里看
run执行命令
uses使用某个 Action
with传给 Action 的参数
env仅当前 Step 生效的环境变量
if条件执行
id给步骤起个 id,方便后面取输出结果
working-directory指定命令的工作目录

示例:

steps:
  - name: 检出代码
    uses: actions/checkout@v4

  - name: 安装 Node
    uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'

  - name: 安装依赖
    run: npm ci

  - name: 跑测试
    run: npm test
    env:
      NODE_ENV: test

常用官方 Action

Action作用
actions/checkout把仓库代码拉到 Runner 上
actions/setup-node安装指定版本的 Node.js
actions/setup-python安装指定版本的 Python
actions/setup-go安装指定版本的 Go
actions/cache缓存依赖,加快构建
actions/upload-artifact上传构建产物
actions/download-artifact下载之前上传的产物
docker/build-push-action构建并推送 Docker 镜像

注意:uses 后面最好带版本号,比如 @v4,不要裸用 @main,免得上游一改你流水线也跟着一起改。

环境变量与密钥

环境变量

env:
  APP_ENV: production

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      BUILD_MODE: release
    steps:
      - run: echo $APP_ENV
      - run: echo $BUILD_MODE

Secrets(密钥)

密码、Token、私钥这类敏感信息,千万别写死在 YAML 里

去仓库:SettingsSecrets and variablesActions 里添加,然后这样用:

steps:
  - name: 部署
    run: ./deploy.sh
    env:
      DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

简单点说:

  • secrets.XXX:敏感信息,日志里会自动打码
  • vars.XXX:普通配置变量,不敏感
  • ${{ }}:GitHub Actions 的表达式语法,用来取值、写条件

几个常用上下文

表达式含义
github.ref当前分支/标签引用
github.sha当前提交的 commit id
github.repository仓库名 owner/repo
github.event_name触发事件名称
runner.osRunner 的操作系统
secrets.NAME读取密钥
needs.job_id.outputs.xxx读取上游 Job 的输出

矩阵构建(strategy.matrix)

一份配置,同时测多种环境,很香。

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        node: [18, 20]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

简单翻译下:

在 Ubuntu / Windows 上,分别用 Node 18 和 Node 20 跑测试,一共 2 × 2 = 4 组任务。

一个更完整的示例:Node 项目 CI

name: Node CI

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

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

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

      - name: Install
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test

      - name: Build
        run: npm run build

再来一个带部署的简版:

name: Deploy

on:
  push:
    branches: [ main ]

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

      - name: 构建
        run: |
          npm ci
          npm run build

      - name: 发布
        if: success()
        run: ./scripts/deploy.sh
        env:
          TOKEN: ${{ secrets.DEPLOY_TOKEN }}

本地怎么调试、线上怎么看

在 GitHub 上看结果

仓库页签里点 Actions,左边选对应 Workflow,右边看每次运行日志。某一步红了,点开 Step 就能看到报错。

权限不够时

有时候 push 到别的仓库、创建 Release 会报权限问题,可以在 Job 里显式声明:

permissions:
  contents: write
  pull-requests: write

几个实用小技巧

技巧说明
continue-on-error: true某步失败也不阻断后续(慎用)
if: always()不管前面成败都执行,适合清理
if: failure()仅失败时执行,适合发告警
shell: bash指定 shell,Windows 上尤其有用
working-directory: ./app命令跑在子目录里

关于 Workflow 的选用建议

官方/实践建议

能拆就拆:CI(构建测试)和 CD(部署)尽量分两个 Workflow,职责更清晰。
敏感信息一律走 Secrets,别硬编码。
Action 固定版本号,避免上游更新把你干翻。
paths 过滤无关改动,省分钟数也省时间。
先在小仓库把流程跑通,再搬到正式项目。

(完)


  目录