GitHub Actions 组合动作 #

Composite Action允许你将多个步骤组合成一个可重用的动作。本节介绍如何创建和使用Composite Action。

概述 #

什么是Composite Action? #

Composite Action是一种特殊类型的动作:

  • 组合多个步骤
  • 不需要编写代码
  • 使用YAML定义
  • 易于创建和维护

适用场景 #

  • 封装常用操作
  • 简化工作流配置
  • 提高代码复用
  • 统一团队实践

创建Composite Action #

目录结构 #

text
.github/
└── actions/
    └── my-composite/
        └── action.yml

action.yml #

yaml
name: 'My Composite Action'
description: 学习如何创建Composite Action,组合多个步骤实现可重用的功能。

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

runs:
  using: 'composite'
  steps:
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}

    - name: Install dependencies
      shell: bash
      run: npm ci

    - name: Run tests
      shell: bash
      run: npm test

输入参数 #

定义输入 #

yaml
inputs:
  node-version:
    description: 'Node.js version'
    required: true
    default: '20'
  
  working-directory:
    description: 'Working directory'
    required: false
    default: '.'
  
  skip-tests:
    description: 'Skip tests'
    required: false
    default: 'false'

使用输入 #

yaml
steps:
  - name: Use input
    shell: bash
    run: |
      echo "Node version: ${{ inputs.node-version }}"
      echo "Working directory: ${{ inputs.working-directory }}"

输出参数 #

定义输出 #

yaml
outputs:
  version:
    description: 'Package version'
    value: ${{ steps.get-version.outputs.version }}
  
  artifact-path:
    description: 'Artifact path'
    value: ${{ steps.build.outputs.path }}

设置输出 #

yaml
steps:
  - id: get-version
    name: Get version
    shell: bash
    run: |
      version=$(node -p "require('./package.json').version")
      echo "version=$version" >> $GITHUB_OUTPUT

  - id: build
    name: Build
    shell: bash
    run: |
      npm run build
      echo "path=dist/" >> $GITHUB_OUTPUT

使用Composite Action #

基本用法 #

yaml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: ./.github/actions/my-composite
        with:
          node-version: '18'

使用输出 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - id: composite
        uses: ./.github/actions/my-composite
        with:
          node-version: '20'
      
      - name: Use output
        run: |
          echo "Version: ${{ steps.composite.outputs.version }}"
          echo "Path: ${{ steps.composite.outputs.artifact-path }}"

实际示例 #

Node.js CI动作 #

yaml
# .github/actions/node-ci/action.yml
name: 'Node.js CI'
description: 学习如何创建Composite Action,组合多个步骤实现可重用的功能。

inputs:
  node-version:
    description: 'Node.js version'
    required: false
    default: '20'
  
  working-directory:
    description: 'Working directory'
    required: false
    default: '.'
  
  cache:
    description: 'Enable dependency cache'
    required: false
    default: 'true'

runs:
  using: 'composite'
  steps:
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: ${{ inputs.cache == 'true' && 'npm' || '' }}
    
    - name: Install dependencies
      shell: bash
      working-directory: ${{ inputs.working-directory }}
      run: npm ci
    
    - name: Run linter
      shell: bash
      working-directory: ${{ inputs.working-directory }}
      run: npm run lint
    
    - name: Run tests
      shell: bash
      working-directory: ${{ inputs.working-directory }}
      run: npm test

使用 #

yaml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/node-ci
        with:
          node-version: '20'

部署动作 #

yaml
# .github/actions/deploy/action.yml
name: 'Deploy'
description: 学习如何创建Composite Action,组合多个步骤实现可重用的功能。

inputs:
  environment:
    description: 'Deployment environment'
    required: true
  
  version:
    description: 'Version to deploy'
    required: true
  
  config-path:
    description: 'Configuration file path'
    required: false
    default: 'config/default.json'

outputs:
  deployment-url:
    description: 'Deployment URL'
    value: ${{ steps.deploy.outputs.url }}

runs:
  using: 'composite'
  steps:
    - name: Load configuration
      shell: bash
      run: |
        echo "Loading config from ${{ inputs.config-path }}"
    
    - name: Deploy
      id: deploy
      shell: bash
      run: |
        echo "Deploying version ${{ inputs.version }} to ${{ inputs.environment }}"
        url="https://${{ inputs.environment }}.example.com"
        echo "url=$url" >> $GITHUB_OUTPUT
    
    - name: Verify deployment
      shell: bash
      run: |
        echo "Verifying deployment at ${{ steps.deploy.outputs.url }}"

使用 #

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - id: deploy
        uses: ./.github/actions/deploy
        with:
          environment: production
          version: ${{ github.sha }}
      
      - name: Print URL
        run: echo "Deployed to ${{ steps.deploy.outputs.deployment-url }}"

通知动作 #

yaml
# .github/actions/notify/action.yml
name: 'Notify'
description: 学习如何创建Composite Action,组合多个步骤实现可重用的功能。

inputs:
  status:
    description: 'Job status'
    required: true
  
  channel:
    description: 'Slack channel'
    required: false
    default: 'deployments'

runs:
  using: 'composite'
  steps:
    - name: Send Slack notification
      if: inputs.status == 'success'
      uses: slackapi/slack-github-action@v1
      with:
        channel-id: ${{ inputs.channel }}
        slack-message: '✅ Deployment succeeded'
      env:
        SLACK_BOT_TOKEN: ${{ env.SLACK_BOT_TOKEN }}
    
    - name: Send failure notification
      if: inputs.status == 'failure'
      uses: slackapi/slack-github-action@v1
      with:
        channel-id: ${{ inputs.channel }}
        slack-message: '❌ Deployment failed'
      env:
        SLACK_BOT_TOKEN: ${{ env.SLACK_BOT_TOKEN }}

使用 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."
  
  notify:
    needs: build
    if: always()
    runs-on: ubuntu-latest
    env:
      SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
    steps:
      - uses: ./.github/actions/notify
        with:
          status: ${{ needs.build.result }}

条件执行 #

yaml
runs:
  using: 'composite'
  steps:
    - name: Conditional step
      if: inputs.skip-tests != 'true'
      shell: bash
      run: npm test
    
    - name: Always run
      if: always()
      shell: bash
      run: echo "This always runs"

环境变量 #

yaml
runs:
  using: 'composite'
  steps:
    - name: Use environment variable
      shell: bash
      env:
        MY_VAR: ${{ inputs.my-input }}
      run: |
        echo $MY_VAR

最佳实践 #

1. 使用默认值 #

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

2. 添加描述 #

yaml
name: 'My Composite Action'
description: 学习如何创建Composite Action,组合多个步骤实现可重用的功能。

3. 使用shell指定 #

yaml
steps:
  - name: My step
    shell: bash
    run: echo "Hello"

4. 支持工作目录 #

yaml
inputs:
  working-directory:
    description: 'Working directory'
    required: false
    default: '.'

steps:
  - name: My step
    shell: bash
    working-directory: ${{ inputs.working-directory }}
    run: echo "Hello"

5. 提供输出 #

yaml
outputs:
  result:
    description: 'Action result'
    value: ${{ steps.main.outputs.result }}

调试Composite Action #

启用调试 #

在仓库设置中添加Secret:

  • ACTIONS_RUNNER_DEBUG = true
  • ACTIONS_STEP_DEBUG = true

添加日志 #

yaml
steps:
  - name: Debug
    shell: bash
    run: |
      echo "Input: ${{ inputs.my-input }}"
      echo "Working directory: $(pwd)"

与其他动作类型比较 #

特性 Composite JavaScript Docker
创建难度
执行速度 最快 较慢
灵活性 最高
适用场景 简单封装 复杂逻辑 特殊环境

下一步学习 #

小结 #

  • Composite Action使用YAML定义
  • 适合封装常用操作
  • 支持输入和输出参数
  • 可以使用条件执行
  • 添加shell指定确保跨平台
  • 使用默认值提高易用性
最后更新:2026-03-28