diff --git a/apps/docs/content/docs/autopilots.mdx b/apps/docs/content/docs/autopilots.mdx index fb3d1e26a..633ca7c22 100644 --- a/apps/docs/content/docs/autopilots.mdx +++ b/apps/docs/content/docs/autopilots.mdx @@ -125,25 +125,79 @@ Examples: #### Where the event name and action come from -Multica derives `event` and `action` from the inbound request in this -order — the first match wins: +Multica derives the `event` name and `action` from the inbound request +in this order — **the first match wins**. -1. **Body envelope** — if the body is a JSON object with an `event` - string field, that value is the event name. An optional - `eventPayload` object then provides `action` / `state` / - `conclusion` / `status` candidates. -2. **Headers** — `X-GitHub-Event: ` combined with body - `action`; `X-Gitlab-Event: `; `X-Event-Type: ` (passed - through verbatim). -3. **Body fallback** — top-level string `event` / `type` / `action`. -4. **Default** — `webhook.received` if nothing above matches. +**1. Body envelope.** If the body is a JSON object with a string +`event` field, that value is the event name directly. An optional +`eventPayload` object then supplies action candidates from its +`action` / `state` / `conclusion` / `status` fields. -Action candidates come from the event-name suffix (`provider.event.`) -plus the body string fields `action`, `state`, `conclusion`, and -`status`. **Non-string values don't qualify** — `{"action": true}` does -not produce an action candidate. Trim values before saving; entries -like `" workflow_run "` with surrounding whitespace are stored -verbatim and will never match. +```bash +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'Content-Type: application/json' \ + -d '{"event":"trigger","eventPayload":{"action":"true"}}' +# inferred: event = trigger, action candidate = true +``` + +**2. Headers.** When no body envelope is present, Multica reads the +following well-known provider headers: + +- `X-GitHub-Event: ` — combined with the top-level body + `action` field (when present) to form `github..`. +- `X-Gitlab-Event: ` — becomes `gitlab.`. +- `X-Event-Type: ` — passed through verbatim. + +```bash +# GitHub-style: header gives the event name, body gives the action. +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'X-GitHub-Event: workflow_run' \ + -H 'Content-Type: application/json' \ + -d '{"action":"completed"}' +# inferred: event = github.workflow_run.completed +# → matches a filter row of workflow_run / completed + +# Generic event-type header — no body fields needed. +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'X-Event-Type: trigger.true' \ + -H 'Content-Type: application/json' \ + -d '{}' +# inferred: event = trigger.true → matches trigger / true +``` + +**3. Body fallback.** If neither a body envelope nor a known header is +present, Multica falls back to top-level body string fields in this +order: `event` → `type` → `action`. + +```bash +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'Content-Type: application/json' \ + -d '{"type":"trigger","action":"true"}' +# inferred: event = trigger (from `type`), action candidate = true +``` + +**4. Default.** If nothing above matches, the event is +`webhook.received` and there are no action candidates. + +**Action candidates, in full.** Once the event is determined, Multica +considers every value below as a possible action match: + +- The event-name suffix, when the event has the form + `provider.event.` (e.g. `github.workflow_run.completed` → + `completed`). +- The body fields `action`, `state`, `conclusion`, and `status` — + **only when they are JSON strings**. A boolean (`{"action": true}`) + or a number does not qualify, so a filter expecting + `event=trigger, action=true` will never match a body of + `{"trigger": true}` because `true` is a bool, not a string. + +**Common gotcha.** A filter row like `Event name: trigger` / +`Actions: true` does **not** mean "fire when the body has +`trigger: true`" — Event filters match the *inferred event and +action*, not arbitrary body fields. Send `trigger.true` via +`X-Event-Type` (or use the body envelope shown above) to hit it. +Surrounding whitespace in saved filter rows (`" workflow_run "`) is +stored verbatim and will never match — trim before saving. #### Quick test diff --git a/apps/docs/content/docs/autopilots.zh.mdx b/apps/docs/content/docs/autopilots.zh.mdx index 001a91db6..84e96d5b3 100644 --- a/apps/docs/content/docs/autopilots.zh.mdx +++ b/apps/docs/content/docs/autopilots.zh.mdx @@ -120,21 +120,73 @@ curl -X POST "$MULTICA_WEBHOOK_URL" \ #### 事件名和 action 从哪来 -Multica 按下面的顺序从入站请求里推断 `event` 和 `action`,**先命中先用**: +Multica 按下面的顺序从入站请求里推断 `event` 和 `action`,**先命中先用**。 -1. **Body envelope** —— 如果 body 是一个 JSON 对象、并且带 - `event: "<字符串>"` 字段,就用它。可选的 `eventPayload` 对象再 - 提供 `action` / `state` / `conclusion` / `status` 候选。 -2. **请求头** —— `X-GitHub-Event: ` 配合 body `action`; - `X-Gitlab-Event: `;`X-Event-Type: `(原样使用)。 -3. **Body 兜底** —— 顶层字符串 `event` / `type` / `action`。 -4. **默认值** —— 以上都没命中时取 `webhook.received`。 +**1. Body envelope。** 如果 body 是一个 JSON 对象、且带字符串字段 +`event`,就直接用它作为事件名。可选的 `eventPayload` 对象再 +从自己的 `action` / `state` / `conclusion` / `status` 字段里提供 +action 候选。 -action 候选来自事件名后缀(`provider.event.`)以及 body 里 -`action`、`state`、`conclusion`、`status` 这四个字符串字段。 -**非字符串值不算候选**——`{"action": true}` 不会被识别为 action。 -保存前请先 trim 掉首尾空格;`" workflow_run "` 这种带空白的值 -会被原样保存,但永远命中不了。 +```bash +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'Content-Type: application/json' \ + -d '{"event":"trigger","eventPayload":{"action":"true"}}' +# 推断结果:event = trigger,action 候选 = true +``` + +**2. 请求头。** 没有 body envelope 时按以下头部识别: + +- `X-GitHub-Event: ` —— 结合 body 顶层的 `action` 字段 + (如果有),拼成 `github..`。 +- `X-Gitlab-Event: ` —— 拼成 `gitlab.`。 +- `X-Event-Type: ` —— 原样使用。 + +```bash +# GitHub 风格:事件名来自 header,action 来自 body。 +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'X-GitHub-Event: workflow_run' \ + -H 'Content-Type: application/json' \ + -d '{"action":"completed"}' +# 推断结果:event = github.workflow_run.completed +# → 命中 workflow_run / completed 的过滤规则 + +# 通用 event-type 头部 —— 不需要任何 body 字段。 +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'X-Event-Type: trigger.true' \ + -H 'Content-Type: application/json' \ + -d '{}' +# 推断结果:event = trigger.true → 命中 trigger / true +``` + +**3. Body 兜底。** Body envelope 和上面的 header 都没有时, +从 body 顶层字符串字段里依次找:`event` → `type` → `action`。 + +```bash +curl -X POST "$MULTICA_WEBHOOK_URL" \ + -H 'Content-Type: application/json' \ + -d '{"type":"trigger","action":"true"}' +# 推断结果:event = trigger(取自 `type`),action 候选 = true +``` + +**4. 默认值。** 以上都没命中时,事件名取 `webhook.received`, +没有 action 候选。 + +**action 候选的完整清单。** 事件名确定后,下面这些值都会被列为 +可能的 action: + +- 事件名后缀,当事件形如 `provider.event.` 时 + (例如 `github.workflow_run.completed` → `completed`)。 +- body 里 `action`、`state`、`conclusion`、`status` 这四个字段—— + **必须是 JSON 字符串**。布尔(`{"action": true}`)或数字都不算 + 候选,所以 `event=trigger, action=true` 的过滤规则**永远命中不了** + `{"trigger": true}` 这种 body,因为 `true` 是 bool 不是字符串。 + +**常见误区。** 一条 `Event name: trigger` / `Actions: true` 的规则 +**不是**「body 里出现 `trigger: true` 就放行」的意思——事件过滤匹配的是 +**推断出来的事件和 action**,不是任意 body 字段。要命中它,请用 +`X-Event-Type` 头发送 `trigger.true`,或者用上面的 body envelope。 +保存时带空格的值(例如 `" workflow_run "`)会被原样保存,但永远命中 +不了——保存前请先 trim。 #### 快速验证