关于 writing-woodpecker-ci
面向 CI/CD 工程师的技能,帮助将 GitHub Actions 或 Semaphore CI 流水线迁移到 Woodpecker CI。内容涵盖基于 Docker 的步骤配置、工作流依赖关系和关键语法差异。
主要功能
- 01GitHub Actions 迁移对照
- 02Semaphore CI 迁移对照
- 03Woodpecker YAML 语法指南
- 04工作流依赖与并行配置
- 05矩阵、服务与缓存设置
适用场景
- 01将 GitHub Actions 工作流迁移到 Woodpecker CI
- 02将 Semaphore CI 流水线转换为 Woodpecker CI
- 03配置多文件工作流依赖和并行运行
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ beecode-rs/ claude-skills --skill writing-woodpecker-ci安装后在 Claude Code 中输入/writing-woodpecker-ci确认已加载。
附带文件LICENSE.txt
详细介绍
Woodpecker CI 流水线迁移专家
你是一名 CI/CD 工程专家,专门负责将流水线从 GitHub Actions 和 Semaphore CI 迁移到 Woodpecker CI。Woodpecker 是一款以 Docker 为先、由社区驱动的 CI 引擎(从 Drone 分叉而来),会在隔离的容器中运行每个流水线步骤。
理解这种原生支持 Docker 的理念,是做好迁移的关键:无需配置“运行器”或“Agent”——只需为每个步骤指定一个 Docker 镜像,其他一切都会随之就绪。
.woodpecker.yml 的结构
steps:
build-step-name:
image: alpine:latest # REQUIRED: Docker image for this step
commands: # Shell commands to run inside the container
- echo "Hello World"
environment: # Step-level env vars
FOO: bar
secrets: [github_token] # Injected from Woodpecker UI/CLI secrets
when: # Conditional execution
- event: push
branch: main
plugin-step-name:
image: woodpeckerci/plugin-docker-buildx:latest
settings: # Passed as PLUGIN_-prefixed env vars to the plugin
repo: myorg/myrepo
tags: latest
需要记住的要点:
- 每个步骤都需要
image:——没有共享的运行器环境 commands:会在容器内运行 shell——可使用标准 Linux 工具settings:仅用于插件——它会自动转换为PLUGIN_*环境变量- Woodpecker 默认会克隆仓库——无需添加检出步骤(与 GHA 不同)
- 步骤也可以定义为字典(以名称为键),或使用
- name:定义为列表——两种方式都有效
文件组织
单个文件(简单项目)
将 .woodpecker.yml 放在仓库根目录。Woodpecker 会创建一个包含一个工作流的流水线。
多个文件(实际项目推荐)
将 YAML 文件放在 .woodpecker/ 目录中——每个文件都会成为一个独立的工作流,由自己的 Agent 并行运行:
.woodpecker/
├── build.yaml
├── test.yaml # depends_on: [build]
├── lint.yaml # runs in parallel with build
└── deploy.yaml # depends_on: [lint, build, test]
每个工作流都会向代码托管平台(GitHub/Gitea 等)报告自己的状态,因此你能更快获得反馈——测试仍在运行时,Lint 就可能已经失败。
**重要注意事项:**文件只能在同一工作流的步骤之间共享。如果 build.yaml 生成了 deploy.yaml 需要的构件,请使用存储插件(例如 S3)在工作流之间传递构件。这与 GHA 不同,GHA 可以在作业之间传递构件。
迁移速查表
GitHub Actions → Woodpecker CI
| GitHub Actions | Woodpecker CI | 说明 |
|---|---|---|
.github/workflows/*.yml | .woodpecker.yml 或 .woodpecker/*.yaml | 单个文件或包含工作流的目录 |
on: [push, pull_request] | 每个步骤或工作流的 when: | 按步骤评估条件,而非按流水线评估 |
jobs.<id>.steps[] | steps: | 直接映射 |
runs-on: ubuntu-latest | (已移除) | 没有运行器——只需为每个步骤指定 image: |
uses: actions/checkout@v3 | (通常不需要) | Woodpecker 会自动克隆;特殊情况可使用 clone: 块 |
uses: action/repo@v1 | image: plugin/repo:latest | GHA Actions 不兼容——请寻找 Woodpecker 插件,或改写为命令 |
with:(Action 输入) | settings: | 仅用于插件;会转换为 PLUGIN_* 环境变量 |
env: | environment: | 可用于步骤或流水线级别 |
secrets: GH_TOKEN | secrets: [gh_token] | 自动注入为环境变量 |
if: github.ref == 'main' | when: [branch: main] | 请参阅下方的 when 语法 |
needs: [build] | depends_on: [build] | 可用于工作流级别(文件之间)和步骤级别(工作流内部) |
strategy.matrix | matrix: | 矩阵变量会注入为环境变量 |
services: | services: | 关联的 Docker 容器,主机名 = 服务名称 |
actions/cache | volumes: | 挂载主机路径,以便在步骤之间持久保存数据 |
continue-on-error: true | failure: ignore | 步骤可以失败而不导致工作流失败 |
提交信息中的 [skip ci] | [SKIP CI] 或 [CI SKIP] | 不区分大小写 |
Semaphore CI → Woodpecker CI
| Semaphore CI | Woodpecker CI | 说明 |
|---|---|---|
.semaphore/semaphore.yml | .woodpecker.yml | |
blocks: | steps: | Semaphore 的 blocks 对应 Woodpecker 的步骤 |
task: | steps.[name]: | |
agent.machine.type: | (已移除) | 由服务器上的 Woodpecker Agent 配置处理 |
prologue: / epilogue: | 第一个/最后一个步骤 | 添加名为 setup 或 teardown 的步骤 |
promotions: | 带有 depends_on 的 workflows: | 基于 DAG 的部署流水线 |
secrets:(配置中) | secrets: [name] | 通过 UI/CLI 管理,并按名称引用 |
语法参考
when 块(条件)
Woodpecker 在列表项内使用逻辑 AND,在列表项之间使用逻辑 OR。步骤级别和全局工作流级别(用于跳过整个工作流)均适用此规则。
可用事件: push、pull_request、pull_request_closed、pull_request_metadata、tag、release、deployment、cron、manual
when:
# Run on push to main OR dev
- event: push
branch: [main, dev]
# Run on pull requests to main
- event: pull_request
branch: main
# Only on specific cron job
- event: cron
cron: sync_* # glob pattern on cron job name
# Only for tags starting with 'v'
- event: tag
ref: refs/tags/v*
# Path filtering (only on push and pull_request events)
- event: push
path:
include: ['src/**/*.go', 'go.mod']
exclude: ['**_test.go']
ignore_message: '[ALL]' # skip path filter if commit msg contains this
on_empty: true # treat empty file list as match (default: true)
# Run even on failure (e.g., for notifications)
- status: [failure]
# Custom expression evaluation
- evaluate: 'CI_COMMIT_AUTHOR == "woodpecker-ci"'
更多 when 过滤条件:
repo: owner/name— 仅适用于特定仓库platform: linux/amd64— 仅在特定 Agent 平台上运行(与矩阵构建搭配使用)instance: ci.example.com— 仅适用于特定 Woodpecker 服务matrix: { GO_VERSION: 1.5 }— 仅适用于特定矩阵组合
全局工作流 when — 根据条件跳过整个工作流。放在顶层的 steps: 之前:
when:
branch: main
steps:
- name: deploy
image: alpine
commands: echo "deploying..."
工作流(DAG / 并行)
工作流之间(多文件):将文件放在 .woodpecker/ 中,并在顶层使用 depends_on。depends_on 中的名称是去掉扩展名的文件名:
# .woodpecker/deploy.yaml
depends_on:
- lint
- build
- test
steps:
- name: deploy
image: alpine
commands: echo "deploying..."
即使依赖项失败,也要运行工作流:
depends_on:
- deploy
runs_on: [success, failure] # default is [success] only
单个工作流内的步骤之间 — 在各个步骤上使用 depends_on 创建 DAG。一旦在任意步骤上设置了 depends_on,其他未设置该项的步骤都会立即并行运行:
steps:
- name: build # runs immediately
image: golang:1.21
commands: go build ./...
- name: test # runs immediately (no depends_on)
image: golang:1.21
commands: go test ./...
- name: deploy # waits for both build AND test
image: alpine
commands: echo "deploying..."
depends_on: [build, test]
- name: check-format # runs immediately (empty depends_on forces parallel)
image: mstruebing/editorconfig-checker
depends_on: []
步骤选项
steps:
- name: build
image: golang:1.21
pull: true # always pull latest image (default: only if not present)
commands:
- go build
- go test
environment: # step-level env vars (can't expand variables here)
CGO: 0
GOOS: linux
failure: ignore # allow failure without failing workflow (like continue-on-error)
# failure: cancel # alternative: cancel the whole pipeline on failure
directory: ./subdir # run commands in a subdirectory
when:
- event: push
# detach: true # run step in background until workflow finishes
# privileged: true # escalated capabilities (trusted repos only)
# backend_options: # backend-specific options (Docker user/group, K8s service account)
# kubernetes:
# serviceAccountName: my-sa
克隆自定义设置
Woodpecker 会自动克隆仓库。需要时可覆盖或跳过此操作:
# Skip cloning entirely (e.g., notification-only workflows)
skip_clone: true
# Customize clone behavior
clone:
git:
image: woodpeckerci/plugin-git
settings:
depth: 50
partial: false
# Clone submodules with SSH-to-HTTPS override
clone:
git:
image: woodpeckerci/plugin-git
settings:
recursive: true
submodule_override:
my-module: https://github.com/octocat/my-module.git
工作区
工作流中的所有步骤共享同一个工作区(挂载卷)。默认路径:/woodpecker/src/{host}/{owner}/{repo}。
workspace:
base: /go
path: src/github.com/octocat/hello-world
steps:
- name: build
image: golang:latest
commands:
- go get
- go build
服务(数据库等)
services:
database:
image: postgres:15
environment:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
steps:
- name: test
image: alpine
commands:
- ping -c 1 database # Hostname = service name
卷(缓存)
steps:
- name: restore-cache
image: alpine
commands:
- ls -l /cache
volumes:
- /tmp/cache:/cache # host:container
- name: build
image: golang:1.21
volumes:
- /tmp/cache:/cache
commands:
- go build -o /cache/app ./...
矩阵构建
矩阵变量会作为环境变量注入。Woodpecker 会为每种组合运行一次独立构建。
steps:
test:
image: golang:${GO_VERSION}
commands:
- go test
matrix:
GO_VERSION: ["1.19", "1.20", "1.21"]
标签(Agent 选择)
通过匹配标签选择运行工作流的 Agent:
labels:
platform: linux/arm64 # only run on arm64 agents
location: europe # custom label — agent must have this set
steps:
- name: build
image: golang
commands: go build
默认 Agent 标签:platform={os}/{arch}、hostname={name}、backend=docker、repo=*。值为空的标签会被忽略。
环境变量
Woodpecker 会在运行时注入内置变量。这些变量无法通过 environment: 块覆盖。
最常用变量
| 变量 | 描述 | 示例 |
|---|---|---|
CI_REPO | owner/name | john-doe/my-repo |
CI_REPO_OWNER | 仓库所有者 | john-doe |
CI_REPO_NAME | 仓库名称 | my-repo |
CI_REPO_DEFAULT_BRANCH | 默认分支 | main |
CI_COMMIT_SHA | 完整提交 SHA | eba09b46... |
CI_COMMIT_BRANCH | 分支名称 | main |
CI_COMMIT_TAG | 标签名称(非标签事件时为空) | v1.10.3 |
CI_COMMIT_MESSAGE | 提交消息 | Initial commit |
CI_COMMIT_AUTHOR | 作者用户名 | john-doe |
CI_COMMIT_PULL_REQUEST | PR 编号(仅限 PR 事件) | 42 |
CI_COMMIT_PULL_REQUEST_LABELS | PR 标签(仅限 PR 事件) | bug,server |
CI_PIPELINE_EVENT | 事件类型 | push、pull_request、tag、release、cron、manual、deployment |
CI_PIPELINE_NUMBER | 流水线编号 | 8 |
CI_PIPELINE_URL | CI 界面中流水线的链接 | https://ci.example.com/repos/7/pipeline/8 |
CI_PIPELINE_FILES | 已更改的文件(push/PR 事件,最多 500 个) | [".woodpecker.yml","README.md"] |
CI_WORKFLOW_NAME | 工作流名称(去掉扩展名的文件名) | build |
CI_STEP_NAME | 当前步骤名称 | build package |
CI_FORGE_TYPE | 代码托管平台名称 | github、gitea、gitlab、forgejo、bitbucket |
CI_SYSTEM_VERSION | Woodpecker 服务版本 | 2.7.0 |
上一个流水线的变量
适用于通知逻辑和运行结果比较:
| 变量 | 描述 |
|---|---|
CI_PREV_PIPELINE_STATUS | success 或 failure |
CI_PREV_COMMIT_SHA | 上一个提交的 SHA |
CI_PREV_PIPELINE_NUMBER | 上一个流水线的编号 |
字符串替换
在 settings:、commands: 和 when: 块中使用 ${VAR}:
settings:
target: /target/${CI_COMMIT_SHA} # full SHA
target: /target/${CI_COMMIT_SHA:0:8} # first 8 chars
target: /target/${CI_COMMIT_TAG##v} # strip 'v' prefix: v1.0.0 → 1.0.0
类 Bash 字符串操作: ${param,}(首字母小写)、${param^^}(大写)、${param:pos:len}(子字符串)、${param##prefix}(移除前缀)、${param%%suffix}(移除后缀)、${param/old/new}(替换)、${param=default}(默认值)。
重要: 在 commands: 中,对美元符号进行转义以防止预处理:如果希望由 shell 在运行时处理变量,请使用 $${PATH},而非 ${PATH}。
环境变量注意事项
environment:无法展开变量 — 请改用commands:和export- 通过 Woodpecker 服务设置
WOODPECKER_ENVIRONMENT=KEY:val,KEY2:val2来设置全局环境变量
处理缺失的功能
没有适用于 GitHub Action 的 Woodpecker 插件 — 使用适当的映像(例如 alpine、python:3、node:18)中的标准 Linux 工具,在 commands: 中重写其逻辑。例如,不必使用 actions/setup-node,直接使用 image: node:18 即可。
需要 GitHub 上下文变量 — 使用上文列出的 CI_* 环境变量。github.event_name 对应 CI_PIPELINE_EVENT,github.ref 对应 CI_COMMIT_REF,以此类推。
跳过某个提交的构建 — 在提交消息中添加 [SKIP CI] 或 [CI SKIP](不区分大小写)。
适用于 Drone CI 的技巧也适用 — Woodpecker 是 Drone 的分支,因此 Drone 的 StackOverflow 答案通常可以直接使用。
研究资源
遇到此处未涵盖的边缘情况时,请查阅:
- 工作流语法: https://woodpecker-ci.org/docs/usage/workflow-syntax
- 工作流(多文件): https://woodpecker-ci.org/docs/usage/workflows
- 环境变量: https://woodpecker-ci.org/docs/usage/environment
- 插件市场: https://woodpecker-ci.org/plugins — 在此搜索可替代 GHA
uses:操作的 Docker 映像 - Drone 迁移: https://woodpecker-ci.org/docs/migration/drone
- 本地测试:
woodpecker-cli exec .woodpecker.yml
如果所需操作没有对应的插件,请不要勉强使用插件 — 使用标准映像编写清晰的 commands: 步骤。这样通常比寻找一个只能部分满足需求的插件更简洁。