GitHub Actions 环境配置的两个真实坑:inputs默认值和secrets作用域

封面图

用 GitHub Actions 的 workflow_dispatch 配合 environment 字段,蓝绿部署、灰度发布都能搭。但跑起来有两个容易踩的坑:inputs 的默认值在特定触发方式下不生效,以及 environment secrets 在保护规则审批前读不到空值。本文说清楚,给出能直接抄的解法。

inputs 默认值:被其他 workflow 触发时变成 null

看这个配置:

on:
  workflow_dispatch:
    inputs:
      deploy_target:
        type: choice
        default: staging
        options:
          - staging
          - production

直觉上"不填就走 staging"。在 GitHub Web UI 上确实如此。但换一种触发方式就不一样了:

触发方式 不传 input 时,默认值生效?
Web UI 手动触发 ✅ 生效
REST API 触发,不传 inputs 字段 ✅ 生效
另一个 workflow 触发,不传这个 input ❌ 值为 null,不是 default

第三种情况最容易被忽略。触发方如果没有显式传某个 input,接收方 workflow 的 github.event.inputs.<name>null,而不是 YAML 里写的 default

场景:workflow A 触发 workflow B:

curl -X POST "https://api.github.com/repos/owner/repo/actions/workflows/deploy.yml/dispatches" \
  -H "Authorization: Bearer $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  -d '{"ref":"main"}'

workflow B 跑起来后,github.event.inputs.deploy_targetnull。踩到这个坑的代码:

- name: Deploy
  run: |
    TARGET="${{ github.event.inputs.deploy_target }}"
    if [ "$TARGET" = "production" ]; then
      echo "Going to production!"
    fi

$TARGET 是空字符串,条件判断为 false,部署目标静默变成了空——不是 staging,不是 production,而是完全没部署到预期环境。

正确做法:永远给默认值留后路。

- name: Deploy
  run: |
    TARGET="${{ github.event.inputs.deploy_target || 'staging' }}"
    echo "Deploying to $TARGET"

触发方也要显式传 input,不依赖接收方的默认值:

jobs:
  trigger-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger deploy
        run: |
          curl -X POST "https://api.github.com/repos/owner/repo/actions/workflows/deploy.yml/dispatches" \
            -H "Authorization: Bearer ${{ secrets.GH_TOKEN }}" \
            -H "Accept: application/vnd.github+json" \
            -d '{
              "ref": "main",
              "inputs": {"deploy_target": "staging"}
            }'

environment secrets:保护规则审批前读不到值

jobs:
  deploy:
    environment:
      name: production
    steps:
      - run: echo "${{ secrets.PROD_DEPLOY_KEY }}"

绑定了 production environment,environment 里配了 PROD_DEPLOY_KEY。实际跑的时候,这个 secret 有时是空字符串

流程是这样的:job 开始初始化时,GitHub Actions 注入 environment secrets。此时如果 required reviewers 保护规则还没审批,secrets 拿到的是空值。只有审批者点通过后,job 才真正开始执行,secrets 才正确注入。

如果保护规则要求 2 人审批,只通过了 1 人,job 一直等到第 2 人点下去,之前 secrets 都是空的。

实测场景:设置了 2 人审批的 production environment:

jobs:
  deploy:
    environment:
      name: production
    steps:
      - name: Read secret
        run: |
          KEY="${{ secrets.PROD_DEPLOY_KEY }}"
          if [ ${#KEY} -eq 0 ]; then
            echo "ERROR: PROD_DEPLOY_KEY is empty"
            exit 1
          fi
          ./deploy.sh

Web UI 手动触发后,workflow 状态是 Waiting(等审批)。用 API 触发返回 202 Accepted,但 workflow run 同样在等审批。必须等 2 人全部审批后,job 才真正启动,secrets 才正常。

解法:把触发审批和实际部署拆成两个 job。审批 job 专门触发保护规则审批,deploy job 依赖它完成后再读取 secrets。

jobs:
  request-approval:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: echo "Approval requested for production deployment"

  deploy:
    needs: request-approval
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        env:
          KEY: ${{ secrets.PROD_DEPLOY_KEY }}
        run: |
          echo "Key length: ${#KEY}"
          ./deploy.sh

request-approval job 触发保护规则审批流程(Web UI 显示 Waiting)。审批通过后,deploy job 才启动,environment secrets 正确注入。

用 curl 快速验证 workflow 状态

诊断 workflow 状态:

# 查看 recent runs
curl -s "https://api.github.com/repos/{owner}/{repo}/actions/workflows/deploy.yml/runs" \
  -H "Authorization: Bearer $GITHUB_TOKEN" | \
  jq '.workflow_runs[] | {id, status, event, environment}'

# 查看某个 run 的 jobs
curl -s "https://api.github.com/repos/{owner}/{repo}/actions/runs/{run_id}/jobs" \
  -H "Authorization: Bearer $GITHUB_TOKEN" | \
  jq '.jobs[] | {name, status, conclusion}'

# 手动触发
curl -X POST "https://api.github.com/repos/{owner}/{repo}/actions/workflows/deploy.yml/dispatches" \
  -H "Authorization: Bearer $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  -d '{"ref":"main","inputs":{"env":"production"}}'

正常情况下,手动触发后 job 状态在几秒内从 queued 变成 in_progress。如果长时间卡在 in_progress 或跳到 waiting,说明 environment 保护规则在起作用。

完整配置模板

name: Deploy with Environment Selection

on:
  workflow_dispatch:
    inputs:
      env:
        description: 'Target environment'
        required: true
        type: choice
        options:
          - staging
          - production
          - production-manual

jobs:
  request-approval:
    if: github.event.inputs.env == 'production'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: echo "Production approval requested"

  deploy:
    needs: request-approval
    runs-on: ubuntu-latest
    environment: ${{ github.event.inputs.env }}
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        env:
          DEPLOY_ENV: ${{ github.event.inputs.env }}
        run: |
          KEY="${{ secrets.DEPLOY_KEY }}"
          if [ ${#KEY} -eq 0 ]; then
            echo "ERROR: DEPLOY_KEY is empty"
            exit 1
          fi
          echo "Deploying to $DEPLOY_ENV"
          ./deploy.sh "$DEPLOY_ENV"

关键点:

  • needs: request-approval:staging 和 production-manual 没有 request-approval job,GitHub Actions 视为立即满足,不会卡住
  • if: github.event.inputs.env == 'production':只有选 production 时才触发审批
  • secrets 读取前有长度检查,避免空值静默失败

现在你可以做什么

  1. 搜索你的 workflow 文件,找出所有 workflow_dispatch 配合 environment 的配置。在 Web UI 上手动触发一次,观察 workflow 状态是 Running 还是 Waiting。卡在 Waiting 说明触发了保护规则审批。
  2. 检查所有读取 environment secrets 的 job,如果它们直接跑而没有前置审批 job,在它们前面加一个 needs 依赖的 approval job,确保审批完成后才读取 secrets。
  3. 搜索所有 workflow_dispatch 触发其他 workflow 的地方,确认触发方是否显式传了所有 input。缺少的 input 不会使用 default,值为 null。给每个 input 引用加 || '默认值' 后缀。
  4. 用上面的 curl 命令验证 workflow 行为。触发一次后轮询 jobs 状态,确认 staging 不需要审批(直接进 in_progress),production 需要等审批。
© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享