Action 的三种类型
JavaScript Action
使用 Node.js 编写,直接在 Runner 上运行(无需容器),启动速度最快。适合需要调用 GitHub API、处理文件、复杂逻辑的 Action。依赖
@actions/core、@actions/exec 等官方 SDK。Docker Container Action
运行在自定义 Docker 容器中,可以使用任意语言和依赖。环境完全可控,适合需要特定系统依赖的工具(如特定版本的编译器、二进制工具)。只能在 Linux Runner 上运行。
Composite Action
将多个 Workflow Steps 组合成可复用单元,使用 YAML 定义(无需编程)。适合将常用步骤序列封装复用,如"安装依赖 + 缓存 + 运行测试"的标准流程。
action.yml 元数据文件
# action.yml(所有 Action 都需要这个文件)
name: 'Deploy to Server'
description: '通过 SSH 将构建产物部署到远程服务器'
author: 'YourName'
inputs:
host:
description: '服务器 IP 或域名'
required: true
username:
description: 'SSH 用户名'
required: true
default: 'ubuntu'
private-key:
description: 'SSH 私钥内容'
required: true
source-path:
description: '本地构建产物路径'
required: false
default: './dist'
target-path:
description: '远程目标路径'
required: false
default: '/var/www/html'
outputs:
deployed-at:
description: '部署完成的时间戳'
value: ${{ steps.deploy.outputs.timestamp }}
runs:
using: 'composite'
steps:
- id: deploy
shell: bash
run: |
# 实现部署逻辑
echo "timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_OUTPUT
JavaScript Action 实战
// src/index.js
const core = require('@actions/core');
const github = require('@actions/github');
const exec = require('@actions/exec');
async function run() {
try {
// 获取输入参数
const token = core.getInput('github-token', { required: true });
const message = core.getInput('comment-message');
const severity = core.getInput('severity');
// 使用 GitHub API
const octokit = github.getOctokit(token);
const context = github.context;
// 只对 PR 添加评论
if (context.eventName === 'pull_request') {
const { data: comment } = await octokit.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: `## 代码质量报告\n\n${message}\n\n严重程度:**${severity}**`
});
// 设置输出
core.setOutput('comment-id', comment.id);
core.info(`✅ 评论已创建:${comment.html_url}`);
}
// 执行 Shell 命令
let output = '';
await exec.exec('npm', ['run', 'lint'], {
listeners: {
stdout: (data) => { output += data.toString(); }
}
});
core.setOutput('lint-output', output);
} catch (error) {
// 标记 Action 失败
core.setFailed(error.message);
}
}
run();
package.json 配置
{
"name": "my-github-action",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"build": "ncc build src/index.js -o dist",
"test": "jest"
},
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.0"
},
"devDependencies": {
"@vercel/ncc": "^0.38.0",
"jest": "^29.0.0"
}
}
必须打包 node_modules
JavaScript Action 需要将所有依赖打包进仓库(使用 @vercel/ncc 打包为单文件),或者在 action.yml 中指定 using: 'node20' 后将 node_modules 提交到仓库。不能依赖 Runner 上的全局安装,因为 GitHub 托管 Runner 只有标准系统工具。
Composite Action:最简单的复用方式
# .github/actions/setup-and-cache/action.yml
name: 'Setup Node and Cache'
description: '配置 Node.js 并缓存依赖(常用步骤复用)'
inputs:
node-version:
description: 'Node.js 版本'
default: '20'
package-manager:
description: 'npm 或 yarn'
default: 'npm'
outputs:
cache-hit:
description: '是否命中缓存'
value: ${{ steps.cache.outputs.cache-hit }}
runs:
using: 'composite'
steps:
- name: 配置 Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- id: cache
name: 缓存依赖
uses: actions/cache@v4
with:
path: node_modules
key: node-${{ inputs.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
node-${{ inputs.node-version }}-
- name: 安装依赖
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: ${{ inputs.package-manager }} ci
使用自定义 Composite Action
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 使用本地 composite action(本仓库内)
- uses: ./.github/actions/setup-and-cache
with:
node-version: '20'
# 使用外部仓库的 Action(格式:owner/repo@ref)
- uses: myorg/my-actions/setup-and-cache@v2
- run: npm run build
发布 Action 到 GitHub Marketplace
# 发布 Action 的标准目录结构
my-action/
├── action.yml # Action 元数据(必须在根目录)
├── src/
│ └── index.ts # 源代码
├── dist/
│ └── index.js # 打包后的文件(ncc 生成,必须提交到仓库)
├── package.json
└── README.md # 使用文档
# CI/CD:自动打包并发布新版本
# .github/workflows/release.yml
name: Release Action
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装依赖
run: npm ci
- name: 打包(生成 dist/index.js)
run: npm run build
# 将打包后的代码提交到标签
- name: 创建 Release
uses: softprops/action-gh-release@v2
with:
files: dist/index.js
generate_release_notes: true
三种 Action 类型选择建议
- Composite Action:首选,无需编程,适合封装常用 YAML 步骤序列,维护简单
- JavaScript Action:需要调用 GitHub API、处理复杂逻辑或操作文件时选择
- Docker Action:需要特定 Linux 环境或非 Node.js 语言时选择,但只能在 Linux Runner 上运行且启动较慢
本章小结
本章核心要点
- 三种 Action 类型:JavaScript(速度最快,使用 @actions/core SDK)、Docker Container(环境可控,只能在 Linux 上运行)、Composite(最易上手,用 YAML 组合步骤无需编程)。
- action.yml 元数据:定义 inputs/outputs 和 runs 配置;composite 类型用 using: composite + steps 直接写 YAML;JavaScript 类型用 using: node20 + main: dist/index.js。
- JavaScript Action 核心 SDK:core.getInput 获取参数;core.setOutput 设置输出;core.setFailed 标记失败;github.getOctokit 调用 GitHub REST API;exec.exec 执行 Shell 命令。
- Composite Action 的优势:存放在 .github/actions/ 目录,直接用 uses: ./.github/actions/my-action 引用;无需打包,修改即生效,适合团队内部复用常见步骤。
- 必须打包 JS Action:使用 @vercel/ncc 将 Node.js 代码及 node_modules 打包为单文件并提交到仓库,Runner 执行时才不需要先运行 npm install。