
Carbon 仓库 Issues Action 架构解析事件、插件、Token 与托管评论契约【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon本指南以 actions/issues/ARCHITECTURE.md 为核心骨架系统讲解 IBM Carbon Design System 仓库中 issues action 的整体架构从事件契约、插件生命周期、双 GitHub 客户端Carbon Automation 与 Bob Automation的 Token 路由到基于隐藏头部的托管评论管理。读完本文你将掌握如何理解该 action 的插件扩展方式、条件判定机制、权限边界设计与失败隔离策略并能沿着源码定位每一处关键实现。Overviewissues action 的职责与事件契约issues action 负责三类工作issue 元数据初始化、自动化评论管理以及初步 triage分流。它本质上是一个Docker action通过./src/run.js作为入口执行。该入口文件会从plugins目录 加载可用的插件并为给定的 workflow 事件运行它们。与 action 最相关的事件定义如下源码注释中明确给出on: issues: types: [opened, edited, labeled, unlabeled, typed]其中typed是 GitHub 将 issue 标记为正式 Issue Type如 Bug时触发的事件也是本项目 triage 流程中的关键事件。从 入口实现 可以看到完整的启动链路读取enabled输入若为false则直接退出记录eventName与action如issues/opened以required: true读取GITHUB_TOKEN输入并构建默认的 Carbon Automation Octokit 客户端若 payload 中没有issue例如workflow_call当作成功的 no-op 退出若 payload 是 Pull Request直接退出issue action 不处理 PR调用runPlugins(context, carbonOctokit)按注册顺序运行全部插件。插件抽象ActionPlugin 与 ActionPluginCondition文档将每次 triage 流程封装为一个plugin其接口形状如下interface ActionPlugin { name: string; conditions?: [ActionPluginCondition]; githubTokenInput?: string; run: (context: GitHubActionContext, octokit: Octokit) Promisevoid; } interface ActionPluginCondition { key: string; run: (context: GitHubActionContext, octokit: Octokit) Promisevoid; }每个插件可以通过conditions声明一组必须为真的条件只有全部条件通过才会运行。常见的条件集中在./src/conditions.js包括 issue opened、typed、labeled、unlabeled 等事件判定。条件的底层实现conditions.js 中events.issues对象把每个 webhook action 映射为一个带稳定key的条件对象export const events { issues: { opened: { key: issue_opened, run: action(opened) }, typed: { key: issue_typed, run: action(typed) }, labeled: { key: issue_labeled, run: action(labeled) }, unlabeled:{ key: issue_unlabeled,run: action(unlabeled) }, }, };action(name)返回一个谓词函数通过context.payload.action name判断事件or(...conditions)组合器会把子条件的 key 拼进组合 key如or(issue_opened, issue_typed)并在运行日志中保持可读性。插件运行器条件求值与 Token 路由run.js中的runPlugins实现了核心循环条件按声明顺序求值遇首个失败即停失败的key会以[triage] Skipping ...; failed condition...的形式写入日志明确说明插件被跳过的原因默认使用 Carbon Automation 客户端只有当插件显式声明githubTokenInput时运行器才会读取该输入并构建备用 Octokitgithub.getOctokit(pluginToken)从而将备用 App 身份的作用域压到最小失败隔离单个插件抛错不会中断循环而是记入pluginFailures后继续运行后续插件全部插件执行完毕后若存在失败统一抛出一个汇总错误使 workflow 变红但不丢弃已成功插件的日志。插件注册表与三个内置插件插件按注册顺序串行执行注册表见./src/plugins/index.jsexport const plugins [ initializeBugMetadata, // 先初始化字段与社区默认值 manageContributionComments, // 延续原先分散在四个 workflow 的评论行为 bobBugTriage, // 最慢且与字段无关放在最后 ];三个插件的条件与职责如下。1. Initialize bug metadata正式 Bug 的元数据初始化initialize-bug-metadata.js只响应or(opened, typed)条件且仅在issue.type?.name Bug正式 Issue Type而非用户可编辑的 label时运行。它幂等地完成三件事Severity 字段写入REST issue-fields API通过GET /repos/{owner}/{repo}/issues/{issue_number}/issue-field-values读取已有字段值用正则从 issue 表单的### Suggested Severity一节解析提交者建议的严重级别并按稳定数字映射1→Critical、2→High、3→Medium、4→Low见severityByNumber只填空字段已有 Severity 视为权威值绝不覆盖空字段才用POST .../issue-field-values写入建议值。文档中特别说明该 API 接受数组即使本次只写 Severity其余字段也不受影响。Project 39 元数据GraphQL通过一次PROJECT_STATE_QUERY同时加载项目 schema、issue 的项目成员关系与字段现值waitForProjectItem故意不发出 add-item 变更而是等待项目自身的 workflow automation 把 issue 加进 Project 39 后再做有限次MAX_PROJECT_LOOKUPS 5带线性退避第 n 次等待 n 秒的轮询只填充空的 Area默认Support与 Effort默认3且两个字段使用独立的单值/数值 mutation一个字段已有值不会阻塞另一个。Area 通过findSupportOption按名称尾部匹配Support不依赖选项前的 emoji 装饰若成员关系始终不可见或字段更新失败错误日志会同时指向项目 workflow 与 App 的 Organization Projects 权限。社区贡献元数据仅 Medium/Low为Medium/Low严重级的正式 Bug 补齐四个标签status: help wanted 、needs: community contribution、needs: code contribution、good first issue 仅在opened事件上通过manageComment以replace操作和隐藏头部!-- lower-severity-community-help --发布一条说明性评论。源码注释强调社区标签/评论不依赖 ProjectV2因此先于项目元数据应用避免权限或传播错误吞掉这些默认行为。2. Manage contribution comments四合一贡献评论manage-contribution-comments.js将原先分散在四个已退役 workflow 的评论规则合并为一个插件条件为or(opened, labeled, unlabeled)。其规则是数据驱动的见源码中的rules数组规则触发条件隐藏头部enhancement proposal opened携带type: enhancement 标签时 opened/labeled!-- contribution-proposal-open --accepted community proposal同时携带proposal: accepted与needs: community contribution!-- contribution-proposal-accepted --proposal not pursuing携带proposal: not pursuing!-- contribution-proposal-not-pursuing --contribution ready to be worked移除needs: code contribution或needs: design contribution时 unlabeled!-- contribution-ready-to-be-worked --isRelevantLabelEvent会校验labelwebhook 中的事件标签是否命中规则防止无关的后续标签变更重新触发旧消息。每条规则同样以replace操作发布靠隐藏头部保证 webhook 重跑时不产生重复评论。3. Generate preliminary Bob bug triage只读的初步分流bob-bug-triage.js是架构中最复杂的插件其条件为or(opened, typed)外加formal_bugissue.type?.name Bug并声明githubTokenInput: BOB_GITHUB_TOKEN。关键设计与文档逐条对应Token 边界Bob 子进程不接收任何 GitHub Token。插件的createBobEnvironment从进程环境显式允许列表CI、HOME、PATH、HTTP_PROXY等 16 个变量拷贝变量——注释明确说明action 输入会暴露为环境变量整体拷贝process.env会泄漏 GitHub Token推理凭证BOB_INFERENCE_API_KEYaction 输入先经core.setSecret注册为 Actions 掩码再映射为 Bob Shell 1.0.6 在--auth-method api-key下读取的BOBSHELL_API_KEY环境变量调用参数executeBob以 argv 方式传递提示词避免 shell 插值 issue 内容并携带--debug、--hide-intermediary-output、--output-format stream-json、自定义模式bug-triage结构化流式输出parseBobStreamLine把 NDJSON 流事件init、message、tool_use、tool_result、result转为精简日志——结构化模型消息、工具参数与工具结果被刻意丢弃日志只保留生命周期事件、工具名、字节计数、一分钟心跳、退出信息与净化后的 stderr 尾部BOB_STDERR_TAIL_LENGTH 8KiB安全约束12 分钟超时超时后 SIGTERM5 秒未退出再 SIGKILL、stdout 最终输出 1MiB 上限、redactBobDiagnostic对Bearer、api_key/authorization/token形状做二次脱敏输出校验validateBobTriage要求纯文本 1–600 字符、≤100 词、无标题/代码围栏/HTML 注释若为项目符号列表须 2–3 条若是散文须单段且 ≤3 句URL 标点不计入句数幂等调用推理前先hasExistingBobTriage检查隐藏头部!-- bob-preliminary-triage --typed事件不会对已在opened时评估过的 issue 重复推理这正是文档所述先检查头部、跳过已评估 issue的落地issue 上下文只含最小字段number、url、title、body、type、author写入临时目录.bob-triage/issue.jsonfinally中必定清理。双客户端 Token 路由与权限模型架构的核心约束是Carbon Automation 是默认 GitHub 客户端Bob 插件在 action 边界声明可选的BOB_GITHUB_TOKENGITHUB_TOKENCarbon Automation为必填输入用于除 Bob 评论之外的全部标准操作BOB_GITHUB_TOKENBob Automation为可选输入因为大多数 issue 事件不会触发 Bob插件运行器只在 Bob 的事件条件与formal_bug条件都通过后才要求该 Token——因此Bob 的托管 triage 评论是 Bob Automation 客户端唯一的输出BOB_INFERENCE_API_KEY为必填输入仅由 Bob 子进程消费。Carbon Automation 需要初始化 issue 字段与 Project 39 元数据因此其 GitHub App 安装需要Issues 与 Issue fields 写权限 Organization Projects 读与写权限workflow 不会收窄 Carbon Token 的权限它继承 App 安装时审批的权限。Project 39 的成员关系只属于项目自身 workflow automation插件绝不发出 add-item 变更——它只做有界重试等待成员可见然后仅填空的 Area 与 Effort。Managed comments隐藏头部与六种操作./src/manage-comment.js提供按隐藏头部幂等管理自动化评论的通用能力。隐藏 HTML 头部如!-- bob-preliminary-triage --提供稳定身份即使可见文本在后继运行中被替换、追加、删除或折叠。支持的操作集合源码中以Set显式声明拼错配置会立即报错而非误建评论操作行为APIreplace找不到则创建找到则更新内容内容一致则 no-opRESTissues.updateComment/issues.createCommentappend在现有头部内容之后追加一个分隔块RESTissues.updateCommentcreate跳过查找总是新建RESTissues.createCommentignore不发起任何 API 调用无delete找不到时为幂等 no-opnot-foundRESTissues.deleteCommentcollapse最小化评论已折叠则unchangedGraphQLminimizeCommentmutationclassifier 为OUTDATED实现细节值得注意formatComment要求创建/更新类操作必须有非空 body并把头部与内容以空行拼接listComments使用octokit.paginate加载全部评论per_page: 100因为长命 issue 中旧托管评论可能超出默认分页大小findComment按头部前缀匹配最新一条同时保留精确 body 回退可收养隐藏头部引入前由旧 workflow 创建的旧评论避免过渡期重复manage-comment-test.js 中有专门用例验证replace对 legacy exact-match 评论升级头部append保留既有头部避免重复嵌套。并发控制与失败可见性文档强调两点并发/失败契约concurrency group 队列化workflow 为同一 issue 的全部事件排进同一个 concurrency 组而非允许较新的 pending 投递替换较旧的——保证opened、typed、labeled等事件按序处理避免丢失关键状态迁移Bob Token 创建的失败可见性Bob Token 创建只限于符合条件的 Bug 事件失败不会拖垮 Carbon-backed 插件而符合条件的 Bob 插件会记录缺失专用 Token并让 workflow 保持失败可见runPlugins汇总抛错。部署与运行时契约action.yml 声明了 4 个输入GITHUB_TOKEN必填Carbon Automation、BOB_GITHUB_TOKEN可选Bob Automation、BOB_INFERENCE_API_KEY必填Bob Shell 推理密钥、enabled可选开关runs.using: dockerDockerfile 基于node:24-slim构建期从对象存储下载Bob Shell 1.0.6并校验固定 SHA-2566ec51abe...再全局安装启动后校验bob --version防止上游替换悄悄改变 triage 可执行文件运行时npm install --omitdevENTRYPOINT 指向src/run.jspackage.json 依赖仅两个actions/core^3.0.0与actions/github9.1.1。对应测试*-test.js覆盖了插件条件、Token 路由、评论操作、Bob 输出校验与环境净化等契约例如 bob-bug-triage-test.js 断言Bob 是唯一使用备用 GitHub Token 的注册插件、typed 事件在 opened 已评论时跳过推理可作为理解插件生命周期的可执行文档。小结issues action 的整体架构可以归纳为四条主线事件驱动opened/typed/labeled/unlabeled 统一由条件谓词归一、插件隔离条件失败跳过、运行失败不中断、汇总失败可见、最小权限双客户端 Token 只在边界路由、Bob 子进程零 GitHub Token、环境变量允许列表、幂等评论隐藏头部 replace/append 等六种操作。这四条主线共同保证了长周期、高并发的开源仓库 triage 流程既稳定可审计又不泄漏凭证与推理细节。【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考