authoring-github-workflows
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAuthoring GitHub Actions Workflows Safely
安全编写GitHub Actions工作流
GitHub Actions workflow files are YAML, but valid YAML is not the same as a valid workflow. A workflow can parse cleanly with (or a casual review) yet still be rejected by GitHub Actions at load time — producing the opaque failure "This run likely failed because of a workflow file issue" with zero jobs started. This skill teaches the YAML-vs-Actions traps (the -as-comment trap above all), how to quote expression scalars correctly, and how to validate with before merge.
yaml.safe_load#actionlintScope: syntactic vs. semantic. This skill is about the syntactic and structural correctness of workflow YAML — quoting, parsing, and-level validity that determines whether GitHub Actions will load and run a file at all. It is not about what a workflow should do or how an agentic workflow should behave. For semantic and functional guidance (designing workflow logic, agentic-workflow patterns, gh-aw authoring), useactionlint. The two are complementary: get the behavior right with the agent, get the YAML right with this skill..github/agents/agentic-workflows.agent.md
GitHub Actions工作流文件采用YAML格式,但有效的YAML不等于有效的工作流。某个工作流可能通过解析(或通过常规审核),但在加载时仍会被GitHub Actions拒绝——显示模糊的失败提示*"此运行可能因工作流文件问题而失败"*,且无任何作业启动。本技能将讲解YAML与Actions之间的陷阱(尤其是作为注释的陷阱)、如何正确为表达式标量添加引号,以及如何在合并前使用进行验证。
yaml.safe_load#actionlint范围:语法 vs 语义。本技能聚焦工作流YAML的语法和结构正确性——引号使用、解析以及层面的有效性,这些决定了GitHub Actions是否会加载并运行文件。它不涉及工作流应实现的功能或智能工作流的行为逻辑。若需语义和功能指导(工作流逻辑设计、智能工作流模式、gh-aw编写),请使用actionlint。两者相辅相成:借助智能代理实现正确行为,借助本技能确保YAML格式正确。.github/agents/agentic-workflows.agent.md
When to Use
适用场景
- Editing, adding, or reviewing any file under .
.github/workflows/ - Writing a ,
run-name,name,if,env, orwithvalue that embeds arunexpression.${{ }} - A workflow run failed with "This run likely failed because of a workflow file issue" and no jobs ran.
- Eval/CI on suddenly breaks for every run after a workflow edit merged, even though the change "looked fine."
main - Deciding whether a YAML scalar needs quoting.
- 编辑、添加或审核目录下的任何文件。
.github/workflows/ - 编写嵌入表达式的
${{ }}、run-name、name、if、env或with值。run - 工作流运行失败,提示*"此运行可能因工作流文件问题而失败"*且无作业执行。
- 合并工作流编辑后,分支的Eval/CI突然每次运行都失败,尽管更改看起来"没问题"。
main - 判断YAML标量是否需要加引号。
When Not to Use
不适用场景
- Authoring non-Actions YAML (app config, Kubernetes, Compose, Azure Pipelines, GitLab CI).
- Pure shell/script logic inside an already-valid block (that is a scripting task, not a workflow-syntax task).
run:
- 编写非Actions相关的YAML(应用配置、Kubernetes、Compose、Azure Pipelines、GitLab CI)。
- 已验证有效的块内的纯Shell/脚本逻辑(这属于脚本任务,而非工作流语法任务)。
run:
The #1 Trap: #
inside an unquoted expression becomes a YAML comment
#头号陷阱:未加引号的表达式中的#
会成为YAML注释
#In YAML, a space followed by starts a comment. In an unquoted (plain) scalar, everything from that space-then- to end-of-line is silently discarded:
##yaml
undefined在YAML中,空格后跟会开始一段注释。在未加引号的(普通)标量中,从空格加到行尾的所有内容会被静默丢弃:
##yaml
undefinedBAD — the run-name is silently truncated at " #"
错误示例 —— run-name会在" #"处被静默截断
run-name: ${{ inputs.pr_number != '' && format('Evaluate PR #{0} @ {1}', inputs.pr_number, inputs.head_sha) || '' }}
YAML parses this as `run-name: ${{ inputs.pr_number != '' && format('Evaluate PR` — an **unterminated `${{` expression**. `yaml.safe_load` succeeds (it just sees a truncated string with a trailing comment), so the bug passes naive validation, but GitHub Actions rejects the malformed expression and refuses to start any run.
```yamlrun-name: ${{ inputs.pr_number != '' && format('Evaluate PR #{0} @ {1}', inputs.pr_number, inputs.head_sha) || '' }}
YAML会将其解析为`run-name: ${{ inputs.pr_number != '' && format('Evaluate PR` —— 一个**未终止的`${{`表达式**。`yaml.safe_load`会成功解析(它只会看到一个带尾随注释的截断字符串),因此该bug会通过简单验证,但GitHub Actions会拒绝这个格式错误的表达式,且不会启动任何运行。
```yamlGOOD — wrap the whole value in double quotes so '#' stays inside the scalar
正确示例 —— 将整个值用双引号包裹,使'#'保留在标量内
run-name: "${{ inputs.pr_number != '' && format('Evaluate PR #{0} @ {1}', inputs.pr_number, inputs.head_sha) || '' }}"
The inner expression already uses single quotes, so double-quoting the scalar is safe. This is exactly the bug that broke `dotnet/skills` evaluation on `main` (PR #746 → fixed by quoting).run-name: "${{ inputs.pr_number != '' && format('Evaluate PR #{0} @ {1}', inputs.pr_number, inputs.head_sha) || '' }}"
内部表达式已使用单引号,因此用双引号包裹标量是安全的。这正是导致`dotnet/skills`在`main`分支上的评估失败的bug(PR #746 → 通过添加引号修复)。Other characters that force quoting in a plain scalar
其他会强制普通标量加引号的字符
| Character / pattern | Why it breaks | Fix |
|---|---|---|
space then | Starts a YAML comment; truncates the value | Quote the whole value |
Leading | YAML anchors/aliases/tags/block scalars | Quote the value |
Leading | Parsed as flow mapping/sequence (a bare | Quote the value |
| Parsed as a nested mapping key | Quote the value |
| Leading/trailing spaces that matter | Plain scalars strip them | Quote the value |
Values that are | YAML type coercion | Quote the value |
Rule of thumb: if a , , , , or value contains a expression and any literal , , or leading special character, wrap the entire scalar in double quotes.
namerun-nameifenvwith${{ }}#:| 字符/模式 | 导致问题的原因 | 修复方案 |
|---|---|---|
空格加 | 启动YAML注释;截断值 | 为整个值添加引号 |
以 | YAML锚点/别名/标签/块标量 | 为值添加引号 |
以 | 被解析为流映射/序列(裸 | 为值添加引号 |
值内包含 | 被解析为嵌套映射键 | 为值添加引号 |
| 首尾空格有实际意义 | 普通标量会自动去除首尾空格 | 为值添加引号 |
值为 | YAML类型转换 | 为值添加引号 |
经验法则:如果、、、或的值包含表达式且包含文字、或特殊开头字符,请将整个标量用双引号包裹。
namerun-nameifenvwith${{ }}#:Workflow
操作流程
Step 1: Identify the changed/authored workflow files
步骤1:识别已更改/编写的工作流文件
bash
git diff --name-only origin/main... -- .github/workflows/For each file, scan every line that contains together with a , a colon-space, or a leading special character.
${{#bash
git diff --name-only origin/main... -- .github/workflows/对于每个文件,扫描所有包含且同时包含、冒号加空格或特殊开头字符的行。
${{ }}#Step 2: Quote risky expression scalars
步骤2:为存在风险的表达式标量添加引号
Wrap the full value in double quotes when the value embeds an expression and contains a or other special character (see the table above). Prefer double quotes when the inner expression uses single quotes, and vice-versa. Do not escape the braces — quoting the scalar is enough.
#${{ }}当值嵌入表达式且包含或其他特殊字符时(见上表),将完整值用双引号包裹。如果内部表达式使用单引号,优先使用双引号作为外层包裹,反之亦然。不要转义括号——为标量添加引号即可。
#${{ }}Step 3: Validate with actionlint (authoritative)
步骤3:使用actionlint验证(权威工具)
actionlintbash
ACTIONLINT_VERSION=1.7.7
ACTIONLINT_SHA256=023070a287cd8cccd71515fedc843f1985bf96c436b7effaecce67290e7e0757
curl -fsSLo actionlint.tar.gz \
"https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"actionlintbash
ACTIONLINT_VERSION=1.7.7
ACTIONLINT_SHA256=023070a287cd8cccd71515fedc843f1985bf96c436b7effaecce67290e7e0757
curl -fsSLo actionlint.tar.gz \
"https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"Verify the download against the pinned checksum before extracting/executing it:
在解压/执行前,对照固定校验和验证下载文件:
echo "${ACTIONLINT_SHA256} actionlint.tar.gz" | sha256sum -c -
tar -xzf actionlint.tar.gz actionlint
echo "${ACTIONLINT_SHA256} actionlint.tar.gz" | sha256sum -c -
tar -xzf actionlint.tar.gz actionlint
Focus on workflow/expression correctness; silence shell/py style noise:
聚焦工作流/表达式正确性;屏蔽Shell/Python风格的无关警告:
./actionlint -shellcheck= -pyflakes= -color .github/workflows/*.yml
On Windows PowerShell, use the `actionlint_<ver>_windows_amd64.zip` asset and `Expand-Archive`.
The truncated-expression bug surfaces as:
got unexpected EOF while lexing end of string literal, expecting ''' [expression]
A clean exit code `0` means the workflows are structurally valid../actionlint -shellcheck= -pyflakes= -color .github/workflows/*.yml
在Windows PowerShell中,使用`actionlint_<ver>_windows_amd64.zip`资源包和`Expand-Archive`命令。
截断表达式bug会显示为:
got unexpected EOF while lexing end of string literal, expecting ''' [expression]
返回干净的退出码`0`表示工作流结构有效。Step 4: Confirm a YAML-only check is not enough
步骤4:确认仅YAML检查并不足够
Do not rely on , , or "it parses" as proof. They accept the truncated-comment form. Only (or pushing and watching GitHub Actions parse it) validates the Actions layer.
yaml.safe_loadyamllintactionlint不要依赖、或"能解析"作为验证依据。它们会接受带截断注释的格式。只有(或推送后观察GitHub Actions的解析情况)能验证Actions层面的有效性。
yaml.safe_loadyamllintactionlintStep 5: Keep the CI gate green
步骤5:保持CI检查通过
This repository runs automatically (see ) on any PR that touches . Ensure your change passes that check before requesting review. If you add a new workflow, the gate covers it automatically.
actionlint.github/workflows/actionlint.yml.github/workflows/本仓库会自动对任何修改的PR运行(见)。在请求审核前,确保你的更改通过该检查。如果添加新工作流,该检查会自动覆盖它。
.github/workflows/actionlint.github/workflows/actionlint.ymlValidation
验证清单
- Every value containing
${{ }}, a colon-space, or a leading special character is wrapped in quotes.# - exits
actionlint -shellcheck= -pyflakes= .github/workflows/*.yml.0 - No workflow run reports "This run likely failed because of a workflow file issue".
- The CI check is green on the PR.
actionlint
- 所有包含、冒号加空格或特殊开头字符的
#值都已添加引号。${{ }} - 返回退出码
actionlint -shellcheck= -pyflakes= .github/workflows/*.yml。0 - 无工作流运行报告*"此运行可能因工作流文件问题而失败"*。
- PR上的actionlint CI检查显示通过。
Common Pitfalls
常见陷阱
| Pitfall | Solution |
|---|---|
Unquoted | Wrap the whole value in double quotes |
Trusting | Run |
Escaping | Don't — quote the scalar instead; escaping breaks the expression |
| Using single quotes around a value that contains single quotes | Use double quotes for the outer scalar |
Adding | Run with |
| Assuming a green YAML lint means the workflow will run | Push and confirm jobs actually start, or rely on the actionlint gate |
| 陷阱 | 解决方案 |
|---|---|
未加引号的 | 将整个值用双引号包裹 |
依赖 | 运行 |
通过转义 | 不要这么做——改为为标量添加引号;转义会破坏表达式 |
| 用单引号包裹包含单引号的值 | 为外层标量使用双引号 |
| 启用shellcheck的情况下添加actionlint,被大量现有Shell风格警告淹没 | 使用 |
| 认为YAML检查通过就意味着工作流能正常运行 | 推送并确认作业实际启动,或依赖actionlint检查 |
References
参考资料
- actionlint — static checker for GitHub Actions workflows.
- GitHub Actions: workflow syntax
- YAML 1.2 spec — comments
- Repository skill-authoring guide:
.agents/skills/create-skill/SKILL.md
- actionlint —— GitHub Actions工作流的静态检查工具。
- GitHub Actions:工作流语法
- YAML 1.2 规范 —— 注释
- 仓库技能编写指南:
.agents/skills/create-skill/SKILL.md