github-actions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGitHub Actions
GitHub Actions
Activate when creating, modifying, troubleshooting, or optimizing GitHub Actions components. This skill covers action development, marketplace integration, and best practices.
当你需要创建、修改、排查问题或优化GitHub Actions组件时启用此技能。本技能涵盖Action开发、Marketplace集成以及最佳实践。
When to Use This Skill
适用场景
Activate when:
- Creating custom GitHub Actions (JavaScript, Docker, or composite)
- Publishing actions to GitHub Marketplace
- Configuring action metadata and inputs/outputs
- Implementing action security and permissions
- Troubleshooting action execution
- Selecting or evaluating marketplace actions
- Optimizing action performance and reliability
在以下场景中启用:
- 创建自定义GitHub Actions(JavaScript、Docker或Composite类型)
- 将Action发布至GitHub Marketplace
- 配置Action元数据与输入/输出
- 实施Action安全与权限控制
- 排查Action执行问题
- 选择或评估Marketplace中的Action
- 优化Action的性能与可靠性
Action Types
Action类型
JavaScript Actions
JavaScript Actions
Execute directly on runners with fast startup and cross-platform compatibility.
Structure:
my-action/
├── action.yml # Metadata and interface
├── index.js # Entry point
├── package.json # Dependencies
└── node_modules/ # Bundled dependenciesKey Requirements:
- Use for inputs/outputs
@actions/core - Use for GitHub API access
@actions/github - Bundle all dependencies (use @vercel/ncc)
- Support Node.js LTS versions
Example action.yml:
yaml
name: 'My JavaScript Action'
description: 'Performs custom task'
inputs:
token:
description: 'GitHub token'
required: true
config:
description: 'Configuration file path'
required: false
default: 'config.yml'
outputs:
result:
description: 'Action result'
runs:
using: 'node20'
main: 'dist/index.js'直接在运行器上执行,启动速度快且具备跨平台兼容性。
结构:
my-action/
├── action.yml # 元数据与接口定义
├── index.js # 入口文件
├── package.json # 依赖配置
└── node_modules/ # 打包后的依赖核心要求:
- 使用处理输入/输出
@actions/core - 使用访问GitHub API
@actions/github - 打包所有依赖(使用@vercel/ncc)
- 支持Node.js LTS版本
示例action.yml:
yaml
name: 'My JavaScript Action'
description: 'Performs custom task'
inputs:
token:
description: 'GitHub token'
required: true
config:
description: 'Configuration file path'
required: false
default: 'config.yml'
outputs:
result:
description: 'Action result'
runs:
using: 'node20'
main: 'dist/index.js'Docker Container Actions
Docker容器Actions
Provide consistent execution environment with all dependencies packaged.
Structure:
my-action/
├── action.yml
├── Dockerfile
├── entrypoint.sh
└── src/Key Requirements:
- Use lightweight base images (Alpine when possible)
- Set proper file permissions
- Handle signals gracefully
- Output to STDOUT/STDERR correctly
Example Dockerfile:
dockerfile
FROM alpine:3.18
RUN apk add --no-cache bash curl jq
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]提供一致的执行环境,所有依赖均已打包。
结构:
my-action/
├── action.yml
├── Dockerfile
├── entrypoint.sh
└── src/核心要求:
- 使用轻量级基础镜像(尽可能使用Alpine)
- 设置正确的文件权限
- 优雅处理信号
- 正确输出至STDOUT/STDERR
示例Dockerfile:
dockerfile
FROM alpine:3.18
RUN apk add --no-cache bash curl jq
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]Composite Actions
Composite Actions
Combine multiple steps and actions into reusable units.
Structure:
yaml
name: 'Setup Environment'
description: 'Configure development environment'
inputs:
node-version:
description: 'Node.js version'
required: false
default: '20'
runs:
using: 'composite'
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
shell: bash
- run: npm run build
shell: bash将多个步骤和Action组合为可复用的单元。
结构示例:
yaml
name: 'Setup Environment'
description: 'Configure development environment'
inputs:
node-version:
description: 'Node.js version'
required: false
default: '20'
runs:
using: 'composite'
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
shell: bash
- run: npm run build
shell: bashAction Metadata (action.yml)
Action元数据(action.yml)
Required Fields
必填字段
yaml
name: 'Action Name' # Marketplace display name
description: 'What it does' # Clear, concise purpose
runs: # Execution configuration
using: 'node20' # or 'docker' or 'composite'yaml
name: 'Action Name' # Marketplace显示名称
description: 'What it does' # 清晰简洁的用途说明
runs: # 执行配置
using: 'node20' # 或'docker'或'composite'Optional Fields
可选字段
yaml
author: 'Your Name'
branding: # Marketplace icon/color
icon: 'activity'
color: 'blue'
inputs: # Define all inputs
input-name:
description: 'Purpose'
required: true
default: 'value'
outputs: # Define all outputs
output-name:
description: 'What it contains'yaml
author: 'Your Name'
branding: # Marketplace图标/颜色配置
icon: 'activity'
color: 'blue'
inputs: # 定义所有输入参数
input-name:
description: '用途说明'
required: true
default: 'value'
outputs: # 定义所有输出结果
output-name:
description: '输出内容说明'Inputs and Outputs
输入与输出
Reading Inputs
读取输入
JavaScript:
javascript
const core = require('@actions/core');
const token = core.getInput('token', { required: true });
const config = core.getInput('config') || 'default.yml';Shell:
bash
TOKEN="${{ inputs.token }}"
CONFIG="${{ inputs.config }}"JavaScript:
javascript
const core = require('@actions/core');
const token = core.getInput('token', { required: true });
const config = core.getInput('config') || 'default.yml';Shell:
bash
TOKEN="${{ inputs.token }}"
CONFIG="${{ inputs.config }}"Setting Outputs
设置输出
JavaScript:
javascript
core.setOutput('result', 'success');
core.setOutput('artifact-url', artifactUrl);Shell:
bash
echo "result=success" >> $GITHUB_OUTPUT
echo "artifact-url=$ARTIFACT_URL" >> $GITHUB_OUTPUTJavaScript:
javascript
core.setOutput('result', 'success');
core.setOutput('artifact-url', artifactUrl);Shell:
bash
echo "result=success" >> $GITHUB_OUTPUT
echo "artifact-url=$ARTIFACT_URL" >> $GITHUB_OUTPUTGitHub Actions Toolkit
GitHub Actions工具包
Essential npm packages for JavaScript actions:
JavaScript Action必备的npm包:
@actions/core
@actions/core
javascript
const core = require('@actions/core');
// Inputs/Outputs
const input = core.getInput('name');
core.setOutput('name', value);
// Logging
core.info('Information message');
core.warning('Warning message');
core.error('Error message');
core.debug('Debug message');
// Grouping
core.startGroup('Group name');
// ... operations
core.endGroup();
// Failure
core.setFailed('Action failed: reason');
// Secrets
core.setSecret('sensitive-value'); // Masks in logs
// Environment
core.exportVariable('VAR_NAME', 'value');javascript
const core = require('@actions/core');
// 输入/输出处理
const input = core.getInput('name');
core.setOutput('name', value);
// 日志输出
core.info('Information message');
core.warning('Warning message');
core.error('Error message');
core.debug('Debug message');
// 分组日志
core.startGroup('Group name');
// ... 操作步骤
core.endGroup();
// 标记失败
core.setFailed('Action failed: reason');
// 敏感信息处理
core.setSecret('sensitive-value'); // 在日志中自动脱敏
// 环境变量导出
core.exportVariable('VAR_NAME', 'value');@actions/github
@actions/github
javascript
const github = require('@actions/github');
// Context
const context = github.context;
console.log(context.repo); // { owner, repo }
console.log(context.sha); // Commit SHA
console.log(context.ref); // Branch/tag ref
console.log(context.actor); // Triggering user
console.log(context.payload); // Webhook payload
// Octokit client
const token = core.getInput('token');
const octokit = github.getOctokit(token);
// API operations
const { data: issues } = await octokit.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open'
});javascript
const github = require('@actions/github');
// 上下文信息
const context = github.context;
console.log(context.repo); // { owner, repo }
console.log(context.sha); // 提交SHA
console.log(context.ref); // 分支/标签引用
console.log(context.actor); // 触发操作的用户
console.log(context.payload); // Webhook负载
// Octokit客户端
const token = core.getInput('token');
const octokit = github.getOctokit(token);
// API操作示例
const { data: issues } = await octokit.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open'
});@actions/exec
@actions/exec
javascript
const exec = require('@actions/exec');
// Execute commands
await exec.exec('npm', ['install']);
// Capture output
let output = '';
await exec.exec('git', ['log', '--oneline'], {
listeners: {
stdout: (data) => { output += data.toString(); }
}
});javascript
const exec = require('@actions/exec');
// 执行命令
await exec.exec('npm', ['install']);
// 捕获命令输出
let output = '';
await exec.exec('git', ['log', '--oneline'], {
listeners: {
stdout: (data) => { output += data.toString(); }
}
});Security Best Practices
安全最佳实践
Input Validation
输入验证
Always validate and sanitize inputs:
javascript
const core = require('@actions/core');
function validateInput(input) {
// Check for command injection
if (/[;&|`$()]/.test(input)) {
throw new Error('Invalid characters in input');
}
return input;
}
const userInput = core.getInput('user-input');
const safeInput = validateInput(userInput);始终验证并清理输入:
javascript
const core = require('@actions/core');
function validateInput(input) {
// 检查是否存在命令注入风险
if (/[;&|`$()]/.test(input)) {
throw new Error('输入包含无效字符');
}
return input;
}
const userInput = core.getInput('user-input');
const safeInput = validateInput(userInput);Token Permissions
Token权限
Request minimal required permissions:
yaml
permissions:
contents: read # Read repository
pull-requests: write # Comment on PRs
issues: write # Create issues请求最小必要权限:
yaml
permissions:
contents: read # 读取仓库内容
pull-requests: write # 对PR进行评论
issues: write # 创建IssueSecret Handling
敏感信息处理
javascript
// Mask secrets in logs
core.setSecret(sensitiveValue);
// Never log tokens
core.debug(`Token: ${token}`); // ❌ WRONG
core.debug('Token received'); // ✅ CORRECT
// Secure token usage
const octokit = github.getOctokit(token);
// Token automatically included in requestsjavascript
// 在日志中脱敏敏感信息
core.setSecret(sensitiveValue);
// 切勿记录Token
core.debug(`Token: ${token}`); // ❌ 错误做法
core.debug('已获取Token'); // ✅ 正确做法
// 安全使用Token
const octokit = github.getOctokit(token);
// Token会自动包含在请求中Dependency Security
依赖安全
bash
undefinedbash
undefinedAudit dependencies
审计依赖包
npm audit
npm audit
Use specific versions
使用特定版本
npm install @actions/core@1.10.0
npm install @actions/core@1.10.0
Bundle dependencies
打包依赖
npm install -g @vercel/ncc
ncc build index.js -o dist
undefinednpm install -g @vercel/ncc
ncc build index.js -o dist
undefinedMarketplace Publishing
Marketplace发布
Prerequisites
前置条件
- Public repository
- action.yml in repository root
- README.md with usage examples
- LICENSE file
- Repository topics (optional)
- 公开仓库
- action.yml位于仓库根目录
- 包含README.md及使用示例
- 包含LICENSE文件
- 仓库主题(可选)
Publishing Process
发布流程
- Create release with semantic version tag:
bash
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0- Create GitHub Release from tag
- Check "Publish this Action to GitHub Marketplace"
- Select primary category
- Verify branding icon/color
- 创建带语义化版本标签的发布:
bash
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0- 基于标签创建GitHub Release
- 勾选“Publish this Action to GitHub Marketplace”
- 选择主分类
- 验证品牌图标/颜色配置
Version Management
版本管理
Use semantic versioning with major version tags:
bash
undefined使用语义化版本并创建主版本标签:
bash
undefinedRelease v1.2.3
发布v1.2.3版本
git tag -a v1.2.3 -m "Release v1.2.3"
git tag -fa v1 -m "Update v1 to v1.2.3"
git push origin v1.2.3 v1 --force
Users reference by major version:
```yaml
- uses: owner/action@v1 # Tracks latest v1.x.xgit tag -a v1.2.3 -m "Release v1.2.3"
git tag -fa v1 -m "将v1更新至v1.2.3"
git push origin v1.2.3 v1 --force
用户可通过主版本引用:
```yaml
- uses: owner/action@v1 # 自动跟踪最新v1.x.x版本Testing Actions Locally
本地测试Action
Use for local testing (see act skill):
actbash
undefined使用进行本地测试(参考act相关技能):
actbash
undefinedTest action in current directory
测试当前目录下的Action
act -j test
act -j test
Test with specific event
测试特定事件触发的流程
act push
act push
Test with secrets
携带敏感信息测试
act -s GITHUB_TOKEN=ghp_xxx
undefinedact -s GITHUB_TOKEN=ghp_xxx
undefinedCommon Patterns
常见模式
Matrix Testing Action
矩阵测试Action
yaml
undefinedyaml
undefinedaction.yml
action.yml
name: 'Matrix Test Runner'
description: 'Run tests across multiple configurations'
inputs:
matrix-config:
description: 'JSON matrix configuration'
required: true
runs:
using: 'composite'
steps:
- run: |
echo "Testing with config: ${{ inputs.matrix-config }}"
# Parse and execute tests
shell: bash
undefinedname: 'Matrix Test Runner'
description: 'Run tests across multiple configurations'
inputs:
matrix-config:
description: 'JSON matrix configuration'
required: true
runs:
using: 'composite'
steps:
- run: |
echo "Testing with config: ${{ inputs.matrix-config }}"
# 解析并执行测试
shell: bash
undefinedCache Management Action
缓存管理Action
javascript
const core = require('@actions/core');
const cache = require('@actions/cache');
async function run() {
const paths = [
'node_modules',
'.npm'
];
const key = `deps-${process.platform}-${hashFiles('package-lock.json')}`;
// Restore cache
const cacheKey = await cache.restoreCache(paths, key);
if (!cacheKey) {
core.info('Cache miss, installing dependencies');
await exec.exec('npm', ['ci']);
await cache.saveCache(paths, key);
} else {
core.info(`Cache hit: ${cacheKey}`);
}
}javascript
const core = require('@actions/core');
const cache = require('@actions/cache');
async function run() {
const paths = [
'node_modules',
'.npm'
];
const key = `deps-${process.platform}-${hashFiles('package-lock.json')}`;
// 恢复缓存
const cacheKey = await cache.restoreCache(paths, key);
if (!cacheKey) {
core.info('未命中缓存,开始安装依赖');
await exec.exec('npm', ['ci']);
await cache.saveCache(paths, key);
} else {
core.info(`命中缓存: ${cacheKey}`);
}
}Artifact Upload Action
制品上传Action
javascript
const artifact = require('@actions/artifact');
async function uploadArtifact() {
const artifactClient = artifact.create();
const files = [
'dist/bundle.js',
'dist/styles.css'
];
const rootDirectory = 'dist';
const options = {
continueOnError: false
};
const uploadResponse = await artifactClient.uploadArtifact(
'build-artifacts',
files,
rootDirectory,
options
);
core.setOutput('artifact-id', uploadResponse.artifactId);
}javascript
const artifact = require('@actions/artifact');
async function uploadArtifact() {
const artifactClient = artifact.create();
const files = [
'dist/bundle.js',
'dist/styles.css'
];
const rootDirectory = 'dist';
const options = {
continueOnError: false
};
const uploadResponse = await artifactClient.uploadArtifact(
'build-artifacts',
files,
rootDirectory,
options
);
core.setOutput('artifact-id', uploadResponse.artifactId);
}Troubleshooting
问题排查
Action Not Found
Action未找到
- Verify repository is public or accessible
- Check action.yml exists in repository root
- Confirm version tag exists
- 验证仓库是否公开或可访问
- 检查action.yml是否存在于仓库根目录
- 确认版本标签已创建
Permission Denied
权限拒绝
yaml
undefinedyaml
undefinedAdd required permissions to workflow
为工作流添加所需权限
permissions:
contents: write
pull-requests: write
undefinedpermissions:
contents: write
pull-requests: write
undefinedNode Modules Missing
Node Modules缺失
- Bundle dependencies with ncc
- Check dist/ folder is committed
- Verify node_modules excluded from .gitignore for dist/
- 使用ncc打包依赖
- 确认dist/文件夹已提交
- 验证.gitignore中是否排除了dist/下的node_modules
Docker Action Fails
Docker Action执行失败
- Check Dockerfile syntax
- Verify entrypoint has execute permissions
- Test container locally:
docker build -t test . && docker run test
- 检查Dockerfile语法
- 验证entrypoint文件具备执行权限
- 本地测试容器:
docker build -t test . && docker run test
Anti-Fabrication Requirements
防伪造要求
- Execute Read or Glob tools to verify action files exist before claiming structure
- Use Bash to test commands before documenting syntax
- Validate action.yml schema against actual files using tool analysis
- Execute actual API calls with @actions/github before documenting responses
- Test permission configurations in real workflows before recommending settings
- Never claim action capabilities without reading actual implementation code
- Report actual npm audit results when discussing security, not fabricated vulnerability counts
- 在声明文件结构前,使用Read或Glob工具验证Action文件是否存在
- 在记录命令语法前,使用Bash测试命令
- 使用工具分析验证action.yml schema与实际文件是否匹配
- 在记录API响应前,使用@actions/github执行实际API调用
- 在推荐权限配置前,在真实工作流中测试权限设置
- 未阅读实际实现代码前,切勿宣称Action具备某项功能
- 讨论安全问题时,报告实际的npm audit结果,而非伪造的漏洞数量