GitHub Actions 复合 Action 开发:从 action.yml 到 Marketplace 发布的完整实战
凌晨三点,我盯着屏幕上第 15 个报错的工作流日志。报错原因是什么?某个私有仓库的 npm install 步骤忘了加 NODE_AUTH_TOKEN。
这已经是本周第三次了。我们有八个仓库,每个都复制粘贴了几乎相同的工作流配置:checkout、setup-node、install、build、test。改一个地方要同步八个仓库。某天升级 Node 版本,我改了五个仓库,剩下三个忘了。
那一刻我意识到:不能再这样下去了。GitHub Actions 的复合 Action(Composite Action)就是为此而生的——把重复的步骤打包成一个可复用组件,像调用函数一样在多个工作流中使用。本文将带你从开发第一个复合 Action 到发布到 Marketplace,掌握 CI/CD 组件化的核心技能。
第一章:复合 Action 核心概念
1.1 什么是复合 Action
复合 Action 是 GitHub Actions 提供的一种组件化机制。它把多个步骤(steps)封装成一个独立的 Action,可以在不同工作流中复用。
与 JavaScript Action 或 Docker Action 不同,复合 Action 不需要编写代码。你只需要写 YAML 配置,定义一系列步骤,GitHub 会自动执行。简单来说,复合 Action 就是一组步骤的「函数封装」。
官方定义是这样的:复合 Action 使用 runs.using: "composite" 标识,所有步骤在同一 Runner 中执行。这意味着你可以直接访问工作目录、环境变量,甚至调用其他 Action。
1.2 三种 Action 类型对比
GitHub Actions 支持三种 Action 类型:
| 类型 | 实现方式 | 适用场景 |
|---|---|---|
| JavaScript Action | 编写 JS/TS 代码 | 需要复杂逻辑、API 调用 |
| Docker Action | 编写 Dockerfile | 需要特定环境、依赖 |
| 复合 Action | 纯 YAML 配置 | 组合现有步骤、快速复用 |
复合 Action 的优势很明显:零代码、快速开发、易于维护。你不需要处理打包、编译、依赖管理,只需要写 YAML。
1.3 复合 Action vs 可复用工作流
这是很多人困惑的地方。乍一看,它们都是「复用」,但本质不同:
复合 Action 是步骤组。它在 Job 内执行,使用调用者的 Runner,需要显式传递 Secrets。
可复用工作流 是完整的流水线。它创建独立的 Job,可以有自己的 Runner,Secrets 自动继承。
举个例子:如果你想把「安装依赖 + 运行测试」打包复用,用复合 Action。如果你想标准化整个「构建→测试→部署」管道,用可复用工作流。第四章会详细对比。
第二章:开发第一个复合 Action
2.1 action.yml 结构详解
复合 Action 的核心是 action.yml 文件。这是一个元数据文件,定义了 Action 的名称、输入、输出和执行步骤。
先看一个最小示例:
name: 'Hello World'
description: 'A simple composite action'
runs:
using: "composite"
steps:
- run: echo "Hello from composite action!"
shell: bash
这个 Action 只做一件事:打印一行文字。但实际项目中,我们需要参数化和输出。
2.2 完整的 action.yml 示例
下面是一个实际可用的复合 Action,用于 Node.js 项目的构建和测试:
name: 'Build and Test'
description: 'Install dependencies, build project, and run tests'
author: 'Your Name'
inputs:
node-version:
description: 'Node.js version to use'
required: true
default: '20'
install-command:
description: 'Command to install dependencies'
required: false
default: 'npm ci'
build-command:
description: 'Command to build the project'
required: false
default: 'npm run build'
test-command:
description: 'Command to run tests'
required: false
default: 'npm test'
outputs:
build-path:
description: 'Path to the build output'
value: ${{ steps.build.outputs.path }}
test-coverage:
description: 'Test coverage percentage'
value: ${{ steps.coverage.outputs.value }}
runs:
using: "composite"
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- name: Install dependencies
run: ${{ inputs.install-command }}
shell: bash
- name: Build project
id: build
run: |
${{ inputs.build-command }}
echo "path=dist" >> $GITHUB_OUTPUT
shell: bash
- name: Run tests
id: coverage
run: |
${{ inputs.test-command }}
echo "value=85" >> $GITHUB_OUTPUT
shell: bash
2.3 字段详解
inputs:定义 Action 接收的参数。每个参数可以指定:
description:参数说明(会在 Marketplace 显示)required:是否必填default:默认值
outputs:定义 Action 的输出。通过 $GITHUB_OUTPUT 环境变量传递。注意格式:
echo "name=value" >> $GITHUB_OUTPUT
runs.steps:执行步骤。与普通工作流类似,但有两个关键区别:
-
必须显式指定 shell。每一步的
run命令必须有shell: bash(或sh、pwsh)。这是复合 Action 的强制要求。 -
可以使用
uses调用其他 Action。比如上面的actions/setup-node@v4。
2.4 常见坑点
开发过程中,我踩过几个坑:
坑点一:inputs 没有 type 字段
复合 Action 的 inputs 只支持 string 类型。不能像可复用工作流那样定义 type: boolean 或 type: number。如果需要布尔值,只能传字符串 "true" 或 "false",然后在步骤中判断。
坑点二:shell 必须显式指定
普通工作流中,run 命令可以省略 shell,GitHub 会根据 Runner 自动选择。但复合 Action 必须显式指定,否则会报错。
坑点三:outputs 必须通过 step id 引用
输出值的 value 字段必须引用步骤的输出:
outputs:
my-output:
value: ${{ steps.my-step.outputs.result }}
而步骤中必须设置 id:
- id: my-step
run: echo "result=hello" >> $GITHUB_OUTPUT
第三章:使用复合 Action
3.1 本地引用
最简单的使用方式是在同一个仓库内引用。假设你的 Action 位于 .github/actions/build-test/action.yml:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 本地引用
- uses: ./.github/actions/build-test
with:
node-version: '20'
test-command: 'npm run test:ci'
路径以 ./ 开头,相对于仓库根目录。这种方式适合团队内部复用,不需要发布到 Marketplace。
3.2 跨仓库引用
如果想在多个仓库间共享,可以把 Action 放在独立的仓库,然后跨仓库引用:
steps:
# 引用组织内的共享 Action
- uses: your-org/shared-actions/build@v1
with:
node-version: '18'
路径格式是 owner/repo/path@version。其中 path 是 Action 在仓库中的相对路径。
推荐的组织级 Action 仓库设计:
shared-actions/
├── build/
│ └── action.yml # 构建相关
├── deploy/
│ └── action.yml # 部署相关
├── lint/
│ └── action.yml # 代码检查
└── README.md
这样引用时就很清晰:
your-org/shared-actions/build@v1your-org/shared-actions/deploy@v1
3.3 从 Marketplace 使用
发布到 Marketplace 后,用户可以直接搜索和引用:
steps:
# 假设你的 Action 已发布为 "build-test-action"
- uses: your-org/[email protected]
with:
node-version: '20'
Marketplace 提供了版本选择、使用统计、README 展示等功能,适合开源项目或公开分享的 Action。
3.4 版本选择策略
引用 Action 时,有三种版本选择方式:
# 方式一:commit SHA(最安全,不可变)
- uses: your-org/action@a1b2c3d4e5f6...
# 方式二:语义化版本 tag(推荐)
- uses: your-org/[email protected]
# 方式三:major tag(自动追踪最新 v1.x)
- uses: your-org/action@v1
# 不推荐:latest tag(可能意外升级)
# - uses: your-org/action@latest
安全建议:
对于生产环境,使用 commit SHA 是最安全的选择。因为 SHA 是不可变的,不会因为维护者更新 tag 而意外升级。
对于内部项目,使用 major tag(如 @v1)是灵活的选择。它会自动追踪最新的 v1.x 版本,获得 bug 修复和新功能。
避免使用 @latest。它可能导致意外升级,破坏构建。
第四章:复合 Action vs 可复用工作流
4.1 功能对比表
这是选择时的核心参考:
| 维度 | 复合 Action | 可复用工作流 |
|---|---|---|
| 执行层级 | Job 内的步骤组 | 独立 Job |
| Runner | 使用调用者的 Runner | 创建新 Runner(或指定) |
| Secrets | 需显式传递 | 自动继承 |
| 输入类型 | 只有 string | boolean / number / string |
| 输出传递 | $GITHUB_OUTPUT | outputs + workflow_call |
| 并发控制 | 继承调用者的并发限制 | 可以独立设置 |
| 环境变量 | 继承 + 可添加 | 独立作用域 |
| 适用场景 | 单功能封装 | 整管道标准化 |
4.2 选择决策矩阵
根据场景选择合适的复用方式:
用复合 Action:
- 打包重复的构建/测试/部署步骤
- 需要在 Job 内与其他步骤交互
- 想保持工作流灵活性,只复用部分步骤
- Secrets 传递可控,安全性要求高
用可复用工作流:
- 标准化整个 CI/CD 管道
- 多个项目需要相同的完整流程
- 需要 Secrets 自动继承(减少配置)
- 需要
if、timeout-minutes等工作流级配置
组合使用:
实际上,最佳实践是组合使用。可复用工作流调用复合 Action:
# .github/workflows/ci.yml(可复用工作流)
on:
workflow_call:
inputs:
node-version:
type: string
default: '20'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 调用复合 Action
- uses: ./.github/actions/build-test
with:
node-version: ${{ inputs.node-version }}
这样既有了工作流级的标准配置,又有了 Action 级的步骤复用。
第五章:版本管理与发布
5.1 Git Tags 最佳实践
发布 Action 的核心是 Git Tags 管理。推荐使用 语义化版本 + major tag 双重策略:
# 创建语义化版本 tag
git tag -a v1.0.0 -m "Initial release"
git push origin v1.0.0
# 创建 major tag(追踪最新 v1.x)
git tag -fa v1 -m "Update v1 tag to latest"
git push origin v1 --force
当发布 v1.1.0 时,更新 major tag:
git tag -a v1.1.0 -m "Add new feature"
git push origin v1.1.0
# 更新 v1 tag 指向最新版本
git tag -fa v1 -m "Update v1 tag to v1.1.0"
git push origin v1 --force
这样用户可以选择:
- 用
@v1.1.0锁定具体版本 - 用
@v1自动获得 v1.x 的更新
5.2 Marketplace 发布流程
发布到 GitHub Marketplace 需要:
1. 准备 README.md
README 必须包含:
- Action 名称和描述
- Inputs 和 Outputs 说明
- 使用示例
- 许可证
2. 准备 action.yml
确保 name、description、author、branding(可选)字段完整。
3. 创建 Release
在 GitHub 仓库页面:
- 点击 “Releases” → “Draft a new release”
- 选择 tag(如
v1.0.0) - 填写 Release Notes
- 勾选 “Publish this Action to the GitHub Marketplace”
- 发布
GitHub 会自动校验 action.yml 并发布到 Marketplace。
5.3 自动化发布工作流
可以创建工作流自动发布:
name: Release Action
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Update major tag
run: |
# 提取 major 版本号
MAJOR=$(echo $GITHUB_REF | sed 's/refs\/tags\/v\([0-9]*\).*/\1/')
# 更新 major tag
git config user.name github-actions
git config user.email [email protected]
git tag -fa v$MAJOR -m "Update v$MAJOR tag"
git push origin v$MAJOR --force
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
这个工作流在推送 tag 时自动更新 major tag 并创建 Release。
第六章:高级技巧与最佳实践
6.1 Secrets 安全传递
复合 Action 不能直接访问 secrets 上下文。必须显式传递:
# 工作流中
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: ./.github/actions/deploy
with:
token: ${{ secrets.DEPLOY_TOKEN }}
env:
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
# action.yml 中
inputs:
token:
description: 'Deploy token'
required: true
runs:
using: "composite"
steps:
- run: deploy --token ${{ inputs.token }}
shell: bash
env:
AWS_ACCESS_KEY: ${{ env.AWS_ACCESS_KEY }}
安全建议:
- 不要在 inputs 中传递敏感信息(日志中可能可见)
- 使用
env传递敏感信息(会被 masked) - 在 README 中明确说明需要哪些 Secrets
6.2 使用本地脚本
复杂逻辑不适合写在 YAML 里。可以在 Action 目录放置脚本文件:
.github/actions/build-test/
├── action.yml
└── scripts/
└── build.sh
在 action.yml 中调用:
runs:
using: "composite"
steps:
- run: $GITHUB_ACTION_PATH/scripts/build.sh
shell: bash
$GITHUB_ACTION_PATH 是复合 Action 的根目录路径。
6.3 组织级 Action 仓库设计
对于团队,推荐集中管理共享 Action:
your-org/shared-actions/
├── .github/
│ └── workflows/
│ └── test.yml # 测试所有 Action
├── build/
│ ├── action.yml
│ └── README.md
├── deploy/
│ ├── action.yml
│ └── README.md
├── lint/
│ ├── action.yml
│ └── README.md
└── README.md
每个子目录是一个独立 Action,有完整的 README 和测试。
6.4 常见陷阱和调试技巧
陷阱一:嵌套深度限制
复合 Action 调用复合 Action,最大深度是 10 层。超过会报错。建议嵌套不超过 3 层,调试困难。
陷阱二:环境变量作用域
复合 Action 中的 env 只在步骤内有效。如果需要跨步骤共享,使用 GITHUB_ENV:
steps:
- run: echo "MY_VAR=value" >> $GITHUB_ENV
shell: bash
- run: echo $MY_VAR # 可以访问
shell: bash
调试技巧:
- 使用
ACTIONS_STEP_DEBUG=true启用详细日志 - 在步骤中添加
echo打印变量 - 使用
tmateAction 进行 SSH 调试(不推荐在生产环境)
结论
复合 Action 是 GitHub Actions 组件化的核心工具,让你告别重复配置,像写函数一样封装 CI 步骤。
记住三个要点:
结构清晰:action.yml 定义 inputs/outputs/steps,像设计函数签名。参数化让 Action 更灵活,输出让调用者可以获取结果。
选择正确:复合 Action 封装单一功能(构建、测试、部署),可复用工作流标准化整个管道。组合使用效果最佳。
版本安全:commit SHA 最安全,适合生产环境。major tag 灵活,适合内部项目。避免 latest。
下一步:在项目中创建第一个复合 Action,将重复的 build-test 步骤打包,然后尝试发布到 Marketplace 分享给团队或社区。
开发 GitHub Actions 复合 Action
从零创建可复用的复合 Action,打包构建/测试步骤
⏱️ 预计耗时: 30 分钟
- 1
步骤1: 创建 Action 目录结构
在仓库中创建复合 Action 目录:
• mkdir -p .github/actions/build-test
• 创建 action.yml 文件 - 2
步骤2: 编写 action.yml 配置
定义 inputs、outputs 和执行步骤:
• inputs 定义参数(node-version、test-command)
• outputs 定义输出(build-path、coverage)
• runs.steps 必须显式指定 shell: bash - 3
步骤3: 本地引用测试
在工作流中引用并测试:
• uses: ./.github/actions/build-test
• with: node-version: '20'
• 本地测试通过后再发布 - 4
步骤4: 创建 Git Tags
使用语义化版本 + major tag:
• git tag -a v1.0.0 -m 'Initial release'
• git tag -fa v1 -m 'Update v1 tag'
• git push origin v1.0.0 v1 - 5
步骤5: 发布到 Marketplace
通过 GitHub UI 发布:
• Releases → Draft a new release
• 选择 tag(如 v1.0.0)
• 勾选 Publish to Marketplace
• GitHub 自动校验并发布
常见问题
复合 Action 和可复用工作流有什么区别?
复合 Action 的 inputs 为什么没有 type 字段?
复合 Action 如何传递 Secrets?
引用 Action 时应该用 commit SHA 还是 tag?
复合 Action 最大嵌套深度是多少?
复合 Action 必须显式指定 shell 吗?
11 分钟阅读 · 发布于: 2026年5月6日 · 修改于: 2026年5月6日
相关文章
GitHub Actions Matrix 矩阵构建:多版本并行测试实战
GitHub Actions Matrix 矩阵构建:多版本并行测试实战
GitHub Actions 入门:YAML 工作流基础与触发器配置
GitHub Actions 入门:YAML 工作流基础与触发器配置
GitHub Actions 入门:YAML 工作流基础与触发器配置


评论
使用 GitHub 账号登录后即可评论