GitHub Actions 步骤Step #

步骤(Step)是作业中的最小执行单元,可以执行命令或使用Action。本节深入探讨步骤的各个方面。

步骤概述 #

什么是步骤? #

步骤是作业中的执行单元,具有以下特点:

  • 在同一作业中顺序执行
  • 可以运行shell命令或使用Action
  • 可以访问文件系统和环境变量
  • 可以设置输出供后续步骤使用

步骤类型 #

yaml
steps:
  # 运行命令
  - run: echo "Hello World"
  
  # 使用Action
  - uses: actions/checkout@v4
  
  # 带名称的步骤
  - name: My Step
    run: echo "Hello"

运行命令 #

基本命令 #

yaml
steps:
  - run: echo "Hello World"
  
  - run: npm install
  
  - run: npm test

多行命令 #

yaml
steps:
  - name: Multiple commands
    run: |
      echo "Line 1"
      echo "Line 2"
      echo "Line 3"

使用变量 #

yaml
steps:
  - name: Use environment variables
    run: |
      echo "Runner OS: ${{ runner.os }}"
      echo "Repository: ${{ github.repository }}"
      echo "Branch: ${{ github.ref_name }}"

Shell选择 #

yaml
steps:
  - name: Using bash
    run: echo $PATH
    shell: bash

  - name: Using sh
    run: echo $PATH
    shell: sh

  - name: Using PowerShell
    run: Write-Host "Hello"
    shell: pwsh

  - name: Using cmd
    run: echo Hello
    shell: cmd

  - name: Using Python
    run: print("Hello")
    shell: python

工作目录 #

yaml
steps:
  - name: Run in subdirectory
    working-directory: ./app
    run: |
      pwd
      ls -la

使用Action #

基本用法 #

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

带参数的Action #

yaml
steps:
  - uses: actions/checkout@v4
    with:
      repository: owner/repo
      ref: main
      token: ${{ secrets.GITHUB_TOKEN }}
      path: ./checkout-dir

  - uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'
      cache-dependency-path: subdir/package-lock.json

本地Action #

yaml
steps:
  - uses: ./.github/actions/my-action
    with:
      param1: value1

Docker Action #

yaml
steps:
  - uses: docker://alpine:3.8
    with:
      args: echo "Hello from Docker"

条件执行 #

基本条件 #

yaml
steps:
  - name: Only on main branch
    if: github.ref == 'refs/heads/main'
    run: echo "This is main branch"

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

状态函数 #

yaml
steps:
  - name: Previous step
    run: exit 0

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

  - name: On failure
    if: failure()
    run: echo "Previous steps failed"

  - name: Always run
    if: always()
    run: echo "This always runs"

  - name: On cancelled
    if: cancelled()
    run: echo "Workflow was cancelled"

组合条件 #

yaml
steps:
  - name: Complex condition
    if: github.ref == 'refs/heads/main' && success()
    run: echo "Main branch and success"

  - name: With matrix
    if: matrix.node == '20' && matrix.os == 'ubuntu-latest'
    run: echo "Specific matrix configuration"

环境变量 #

步骤级环境变量 #

yaml
steps:
  - name: With environment variables
    env:
      MY_VAR: value
      ANOTHER_VAR: another
    run: |
      echo $MY_VAR
      echo $ANOTHER_VAR

使用Secrets #

yaml
steps:
  - name: Use secrets
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
    run: |
      echo "Using API_KEY"
      # 不要打印secrets的值!

动态环境变量 #

yaml
steps:
  - name: Set dynamic env
    id: set-env
    run: echo "MY_VAR=dynamic_value" >> $GITHUB_ENV

  - name: Use dynamic env
    run: echo $MY_VAR

输出变量 #

设置输出 #

yaml
steps:
  - id: set-output
    name: Set output
    run: |
      echo "name=value" >> $GITHUB_OUTPUT
      echo "version=1.0.0" >> $GITHUB_OUTPUT

  - name: Use output
    run: |
      echo "Name: ${{ steps.set-output.outputs.name }}"
      echo "Version: ${{ steps.set-output.outputs.version }}"

多行输出 #

yaml
steps:
  - id: multiline
    name: Set multiline output
    run: |
      {
        echo "content<<EOF"
        echo "Line 1"
        echo "Line 2"
        echo "Line 3"
        echo "EOF"
      } >> $GITHUB_OUTPUT

  - name: Use multiline output
    run: |
      echo "${{ steps.multiline.outputs.content }}"

JSON输出 #

yaml
steps:
  - id: json-output
    name: Set JSON output
    run: |
      echo "data={\"name\":\"test\",\"value\":123}" >> $GITHUB_OUTPUT

  - name: Use JSON output
    run: |
      echo "Name: ${{ fromJson(steps.json-output.outputs.data).name }}"
      echo "Value: ${{ fromJson(steps.json-output.outputs.data).value }}"

继续执行 #

continue-on-error #

yaml
steps:
  - name: Might fail
    run: exit 1
    continue-on-error: true

  - name: Will still run
    run: echo "This runs even if previous step failed"

条件继续 #

yaml
steps:
  - name: Conditional continue
    run: exit 1
    continue-on-error: ${{ github.ref != 'refs/heads/main' }}

超时设置 #

yaml
steps:
  - name: Long running task
    run: ./long-script.sh
    timeout-minutes: 10

工作流命令 #

设置环境变量 #

yaml
steps:
  - name: Set env var
    run: echo "MY_VAR=hello" >> $GITHUB_ENV

  - name: Use env var
    run: echo $MY_VAR

添加系统路径 #

yaml
steps:
  - name: Add to PATH
    run: echo "$HOME/mybin" >> $GITHUB_PATH

  - name: Use new path
    run: my-custom-command

输出分组 #

yaml
steps:
  - name: Grouped output
    run: |
      echo "::group::My group title"
      echo "Line 1"
      echo "Line 2"
      echo "::endgroup::"

掩码值 #

yaml
steps:
  - name: Mask secret
    run: echo "::add-mask::${{ secrets.MY_SECRET }}"

  - name: Use masked value
    run: echo "The value is masked in logs"

调试消息 #

yaml
steps:
  - name: Debug output
    run: |
      echo "::debug::This is a debug message"
      echo "::warning::This is a warning"
      echo "::error::This is an error"

步骤摘要 #

yaml
steps:
  - name: Generate summary
    run: |
      echo "## Build Results" >> $GITHUB_STEP_SUMMARY
      echo "" >> $GITHUB_STEP_SUMMARY
      echo "✅ Build succeeded" >> $GITHUB_STEP_SUMMARY
      echo "" >> $GITHUB_STEP_SUMMARY
      echo "### Test Results" >> $GITHUB_STEP_SUMMARY
      echo "| Test | Status |" >> $GITHUB_STEP_SUMMARY
      echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
      echo "| Unit | ✅ |" >> $GITHUB_STEP_SUMMARY
      echo "| E2E  | ✅ |" >> $GITHUB_STEP_SUMMARY

步骤示例 #

检出代码 #

yaml
steps:
  - name: Checkout
    uses: actions/checkout@v4
    with:
      fetch-depth: 0  # 获取完整历史

设置语言环境 #

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

  - name: Setup Python
    uses: actions/setup-python@v5
    with:
      python-version: '3.11'
      cache: 'pip'

  - name: Setup Go
    uses: actions/setup-go@v5
    with:
      go-version: '1.21'
      cache: true

缓存依赖 #

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

上传制品 #

yaml
steps:
  - name: Upload artifact
    uses: actions/upload-artifact@v4
    with:
      name: my-artifact
      path: dist/
      retention-days: 5

下载制品 #

yaml
steps:
  - name: Download artifact
    uses: actions/download-artifact@v4
    with:
      name: my-artifact
      path: ./downloaded

部署 #

yaml
steps:
  - name: Deploy to GitHub Pages
    uses: peaceiris/actions-gh-pages@v3
    with:
      github_token: ${{ secrets.GITHUB_TOKEN }}
      publish_dir: ./dist

  - name: Deploy to AWS S3
    uses: jakejarvis/s3-sync-action@master
    with:
      args: --acl public-read --follow-symlinks
    env:
      AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }}
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

完整示例 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run tests
        run: npm test -- --coverage
        env:
          CI: true

      - name: Build
        run: npm run build

      - name: Upload coverage
        if: success()
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

      - name: Upload build
        if: success()
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

      - name: Generate summary
        if: always()
        run: |
          echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "✅ Build completed" >> $GITHUB_STEP_SUMMARY

最佳实践 #

1. 使用有意义的名称 #

yaml
steps:
  - name: Install dependencies
    run: npm ci

  - name: Run unit tests
    run: npm test

2. 合理使用条件 #

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

  - name: Notify on failure
    if: failure()
    run: ./notify.sh

3. 使用环境变量 #

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

4. 设置超时 #

yaml
steps:
  - name: Long running task
    timeout-minutes: 10
    run: ./long-script.sh

5. 使用步骤摘要 #

yaml
steps:
  - name: Summary
    if: always()
    run: |
      echo "## Results" >> $GITHUB_STEP_SUMMARY
      echo "Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY

下一步学习 #

小结 #

  • 步骤是作业中的最小执行单元
  • 可以运行命令或使用Action
  • 支持条件执行和状态检查
  • 可以设置和使用输出变量
  • 支持环境变量和工作目录配置
  • 使用工作流命令增强功能
  • 遵循最佳实践提高可读性和可维护性
最后更新:2026-03-28