GitHub Actions 动作Action #

动作(Action)是GitHub Actions中的可重用代码单元,执行特定任务。本节深入探讨Action的类型、使用方式和创建方法。

Action概述 #

什么是Action? #

Action是可重用的代码单元,可以:

  • 执行特定任务(如检出代码、设置环境)
  • 封装复杂逻辑
  • 跨工作流共享和复用
  • 发布到Marketplace供他人使用

Action类型 #

GitHub Actions支持三种类型的Action:

类型 描述 执行速度
JavaScript Action 使用Node.js编写 最快
Docker Action 使用Docker容器 较慢
Composite Action 组合多个步骤 中等

使用Action #

基本语法 #

yaml
steps:
  - uses: owner/repo@version

版本指定 #

yaml
steps:
  # 使用具体版本(推荐)
  - uses: actions/checkout@v4

  # 使用SHA(最安全)
  - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9

  # 使用分支(不推荐用于生产)
  - uses: actions/checkout@main

传递参数 #

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

  - uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'
      registry-url: 'https://registry.npmjs.org'

使用环境变量 #

yaml
steps:
  - uses: actions/setup-node@v4
    with:
      node-version: '20'
    env:
      NODE_ENV: production

常用Action #

代码检出 #

yaml
steps:
  - uses: actions/checkout@v4

完整配置:

yaml
steps:
  - uses: actions/checkout@v4
    with:
      repository: owner/repo        # 仓库名
      ref: main                     # 分支或标签
      token: ${{ secrets.GITHUB_TOKEN }}  # 访问令牌
      ssh-key: ${{ secrets.SSH_KEY }}     # SSH密钥
      ssh-known-hosts: ''           # 已知主机
      ssh-strict: true              # 严格SSH检查
      persist-credentials: true     # 保存凭证
      path: ./src                   # 检出路径
      clean: true                   # 清理工作区
      fetch-depth: 1                # 获取深度
      lfs: false                    # 是否获取LFS
      submodules: false             # 是否获取子模块

设置语言环境 #

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

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

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

# Java
- uses: actions/setup-java@v4
  with:
    distribution: 'temurin'
    java-version: '17'
    cache: 'maven'

# Ruby
- uses: ruby/setup-ruby@v1
  with:
    ruby-version: '3.2'
    bundler-cache: true

缓存 #

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

制品管理 #

yaml
# 上传
- uses: actions/upload-artifact@v4
  with:
    name: my-artifact
    path: dist/
    retention-days: 5

# 下载
- uses: actions/download-artifact@v4
  with:
    name: my-artifact
    path: ./downloaded

GitHub Pages部署 #

yaml
- uses: peaceiris/actions-gh-pages@v3
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    publish_dir: ./dist
    publish_branch: gh-pages
    cname: example.com

Docker操作 #

yaml
# 登录
- uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}

# 构建
- uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: ghcr.io/${{ github.repository }}:latest

JavaScript Action #

目录结构 #

text
my-action/
├── action.yml
├── index.js
├── package.json
└── node_modules/

action.yml #

yaml
name: 'My Action'
description: 理解GitHub Actions动作的概念、类型和使用方式。
author: 'Your Name'

inputs:
  my-input:
    description: 'Input description'
    required: true
    default: 'default value'

outputs:
  my-output:
    description: 'Output description'

runs:
  using: 'node20'
  main: 'dist/index.js'

branding:
  icon: 'check-circle'
  color: 'green'

index.js #

javascript
const core = require('@actions/core');
const github = require('@actions/github');

try {
  const myInput = core.getInput('my-input');
  console.log(`Input: ${myInput}`);
  
  const myOutput = 'output value';
  core.setOutput('my-output', myOutput);
  
  console.log(`Event: ${github.context.eventName}`);
  console.log(`Repo: ${github.context.repo.owner}/${github.context.repo.repo}`);
} catch (error) {
  core.setFailed(error.message);
}

package.json #

json
{
  "name": "my-action",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "@actions/core": "^1.10.1",
    "@actions/github": "^6.0.0"
  }
}

使用工具包 #

javascript
const core = require('@actions/core');
const github = require('@actions/github');
const exec = require('@actions/exec');
const io = require('@actions/io');
const toolCache = require('@actions/tool-cache');

// 输入输出
const input = core.getInput('input', { required: true });
core.setOutput('output', 'value');
core.setSecret('secret-value');

// 环境变量
core.exportVariable('MY_VAR', 'value');

// 路径
core.addPath('/path/to/bin');

// 调试
core.debug('Debug message');
core.warning('Warning message');
core.error('Error message');

// 组输出
core.startGroup('Group name');
console.log('Inside group');
core.endGroup();

// 掩码
core.setSecret('secret-value');

// 执行命令
await exec.exec('node', ['--version']);

// 文件操作
await io.cp('source', 'dest');
await io.mv('source', 'dest');
await io.rmRF('path');

// 下载工具
const toolPath = await toolCache.downloadTool('https://example.com/tool');

Docker Action #

目录结构 #

text
my-docker-action/
├── action.yml
├── Dockerfile
└── entrypoint.sh

action.yml #

yaml
name: 'My Docker Action'
description: 理解GitHub Actions动作的概念、类型和使用方式。
author: 'Your Name'

inputs:
  my-input:
    description: 'Input description'
    required: true
    default: 'default'

outputs:
  my-output:
    description: 'Output description'

runs:
  using: 'docker'
  image: 'Dockerfile'
  args:
    - ${{ inputs.my-input }}
  env:
    MY_ENV: value

branding:
  icon: 'box'
  color: 'blue'

Dockerfile #

dockerfile
FROM alpine:3.18

RUN apk add --no-cache bash

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh #

bash
#!/bin/bash

set -e

# 获取输入
INPUT="${1}"
echo "Input: $INPUT"

# 设置输出
echo "my-output=value" >> $GITHUB_OUTPUT

# 设置环境变量
echo "MY_VAR=value" >> $GITHUB_ENV

# 执行任务
echo "Hello from Docker Action"

Composite Action #

目录结构 #

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

action.yml #

yaml
name: 'My Composite Action'
description: 理解GitHub Actions动作的概念、类型和使用方式。

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

使用Composite Action #

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

本地Action #

目录结构 #

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

使用本地Action #

yaml
steps:
  - uses: ./.github/actions/my-action
    with:
      param: value

发布到Marketplace #

准备发布 #

  1. 确保action.yml完整
  2. 添加README.md
  3. 添加LICENSE
  4. 创建Git标签

发布步骤 #

bash
# 创建标签
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0

# 在GitHub上发布
# 进入仓库 → Releases → Draft a new release

版本管理 #

bash
# 主版本标签
git tag v1
git tag v1.0
git tag v1.0.0

# 更新主版本标签
git tag -f v1
git push origin v1 --force

Action最佳实践 #

1. 使用具体版本 #

yaml
# 推荐
- uses: actions/checkout@v4

# 最安全
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9

# 不推荐
- uses: actions/checkout@main

2. 验证Action来源 #

yaml
# 使用官方Action
- uses: actions/checkout@v4

# 使用知名组织Action
- uses: docker/login-action@v3

# 审查第三方Action
- uses: third-party/action@v1

3. 使用缓存加速 #

yaml
- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'

4. 处理敏感信息 #

yaml
- uses: my-action@v1
  with:
    token: ${{ secrets.MY_TOKEN }}
  env:
    API_KEY: ${{ secrets.API_KEY }}

完整示例 #

创建一个简单的JavaScript Action #

yaml
# action.yml
name: 'Hello World'
description: 理解GitHub Actions动作的概念、类型和使用方式。
inputs:
  who-to-greet:
    description: 'Who to greet'
    required: true
    default: 'World'
outputs:
  time:
    description: 'The time we greeted'
runs:
  using: 'node20'
  main: 'dist/index.js'
javascript
// index.js
const core = require('@actions/core');

const whoToGreet = core.getInput('who-to-greet');
console.log(`Hello ${whoToGreet}!`);

const time = new Date().toTimeString();
core.setOutput('time', time);

使用自定义Action #

yaml
jobs:
  hello:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: ./.github/actions/hello
        id: hello
        with:
          who-to-greet: 'GitHub Actions'
      
      - run: echo "Time was ${{ steps.hello.outputs.time }}"

下一步学习 #

小结 #

  • Action是可重用的代码单元
  • 支持JavaScript、Docker和Composite三种类型
  • 使用具体版本确保稳定性
  • 可以创建本地Action或发布到Marketplace
  • 使用工具包简化开发
  • 遵循最佳实践确保安全性和可维护性
最后更新:2026-03-28