diff --git a/apps/docs/content/docs/environment-variables.mdx b/apps/docs/content/docs/environment-variables.mdx index c5dab262a..fa9087c38 100644 --- a/apps/docs/content/docs/environment-variables.mdx +++ b/apps/docs/content/docs/environment-variables.mdx @@ -141,6 +141,22 @@ For a full explanation of how each parameter affects daemon behavior, see [Daemo **Leaving `FRONTEND_ORIGIN` unset creates two silent failures**: (1) invite email links point at `https://app.multica.ai` (the hosted domain), and clicking them doesn't bring users back to your self-hosted instance; (2) WebSocket Origin checks fall back to `localhost:3000 / 5173 / 5174`, so every WebSocket connection in a production deployment is rejected and the frontend appears to "lose real-time updates." +## GitHub integration + +The [GitHub PR ↔ issue integration](/github-integration) needs two variables. Set both to enable Connect GitHub in Settings and accept incoming webhooks. + +| Variable | Default | Description | +|---|---|---| +| `GITHUB_APP_SLUG` | empty | The slug of your GitHub App (the tail of `https://github.com/apps/`). Drives the Settings → Integrations install button URL | +| `GITHUB_WEBHOOK_SECRET` | empty | The Webhook secret you set on the GitHub App. Used for HMAC-SHA256 verification of every `pull_request` / `installation` delivery, and as the HMAC key for the setup-callback state token | + +**Behavior when either is unset:** + +- `Connect GitHub` in Settings → Integrations is **disabled** and shows a "not configured" hint to admins. +- The `/api/webhooks/github` endpoint returns **`503 github webhooks not configured`** — Multica refuses to process events with no secret rather than treating every signature as valid. + +**Note:** `GITHUB_WEBHOOK_SECRET` is reused as the signing key for the install-flow state token, so operators only need to manage one secret. It is **not** the GitHub App's *Client* secret — Client secrets are OAuth-related and not used by this integration. See [GitHub integration → Self-host setup](/github-integration#self-host-setup) for the full walkthrough. + ## Usage analytics By default, the server reports to Multica's official PostHog instance. To opt out, set `ANALYTICS_DISABLED=true`. @@ -154,5 +170,6 @@ By default, the server reports to Multica's official PostHog instance. To opt ou ## Next - [Sign-in and signup configuration](/auth-setup) — how to actually configure the auth-related variables above and where the traps are +- [GitHub integration](/github-integration) — how to set up the GitHub App that backs `GITHUB_APP_SLUG` / `GITHUB_WEBHOOK_SECRET` - [Troubleshooting](/troubleshooting) — symptoms and fixes for common misconfigurations - [Daemon and runtimes](/daemon-runtimes) — what the `MULTICA_DAEMON_*` parameters actually do diff --git a/apps/docs/content/docs/environment-variables.zh.mdx b/apps/docs/content/docs/environment-variables.zh.mdx index 44139e143..3c43e36b8 100644 --- a/apps/docs/content/docs/environment-variables.zh.mdx +++ b/apps/docs/content/docs/environment-variables.zh.mdx @@ -141,6 +141,22 @@ Multica 存储用户上传的附件(评论里的图片、文件等)。**优 **`FRONTEND_ORIGIN` 不设就有两个静默失败**:(1)邀请邮件里的链接指向 `https://app.multica.ai`(托管版的域名),用户点了跳不回你的 self-host 实例;(2)WebSocket 连接的 Origin 校验回落到 `localhost:3000 / 5173 / 5174`,生产部署的 WebSocket 全部被拒,前端看起来「实时更新不工作」。 +## GitHub 集成 + +[GitHub PR ↔ issue 集成](/github-integration) 依赖两个环境变量。两个都配上才会启用 Settings 里的 Connect GitHub 并接受 webhook。 + +| 环境变量 | 默认值 | 说明 | +|---|---|---| +| `GITHUB_APP_SLUG` | 空 | 你的 GitHub App slug(`https://github.com/apps/` 的尾部)。Settings → Integrations 里安装按钮的跳转 URL 用它拼 | +| `GITHUB_WEBHOOK_SECRET` | 空 | 你在 GitHub App 上设置的 Webhook secret。每条 `pull_request` / `installation` delivery 都用它做 HMAC-SHA256 校验;同一个值也用作 setup 回调里 state token 的签名密钥 | + +**任一变量未设时:** + +- Settings → Integrations 里 `Connect GitHub` 按钮 **disable**,对 admin 显示「not configured」提示 +- `/api/webhooks/github` 直接返回 **`503 github webhooks not configured`**——secret 没配置时 Multica 拒绝处理任何 webhook 事件,而不是把所有签名当 valid + +**注意:** `GITHUB_WEBHOOK_SECRET` 同时被复用为 install 流程里 state token 的签名密钥,所以运维只需要维护一个 secret。它**不是** GitHub App 的 *Client* secret——Client secret 是 OAuth 用的,和本集成无关。完整配置流程见 [GitHub 集成 → Self-Host 配置](/github-integration#self-host-配置)。 + ## 用量统计 默认上报到 Multica 官方 PostHog 实例。不想上报就把 `ANALYTICS_DISABLED=true`。 @@ -154,5 +170,6 @@ Multica 存储用户上传的附件(评论里的图片、文件等)。**优 ## 下一步 - [登录与注册配置](/auth-setup) —— 上面 auth 相关的那几个环境变量怎么真的配、陷阱在哪 +- [GitHub 集成](/github-integration) —— `GITHUB_APP_SLUG` / `GITHUB_WEBHOOK_SECRET` 背后的 GitHub App 怎么建 - [故障排查](/troubleshooting) —— 配错了常见的症状和修复 - [守护进程与运行时](/daemon-runtimes) —— `MULTICA_DAEMON_*` 参数的行为含义 diff --git a/apps/docs/content/docs/github-integration.mdx b/apps/docs/content/docs/github-integration.mdx new file mode 100644 index 000000000..d6dc24a5d --- /dev/null +++ b/apps/docs/content/docs/github-integration.mdx @@ -0,0 +1,183 @@ +--- +title: GitHub integration +description: Connect a GitHub App once, then PRs whose branch, title, or body reference an issue identifier auto-attach to that issue — and merging the PR moves the issue to Done. +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +Connect a GitHub account or organization once in **Settings → Integrations**. After that, any pull request whose branch name, title, or body contains an issue identifier (for example `MUL-123`) is **auto-linked** to that [issue](/issues), appears under **Pull requests** in the issue sidebar, and — when the PR is merged — moves the issue to **Done**. + +There is no per-issue setup. The whole flow is identifier-driven. + +## What the integration does + +| Surface | Behavior | +|---|---| +| **Settings → Integrations** | Workspace admins see a GitHub card with a **Connect GitHub** button. Clicking it opens GitHub's App install page; after install you bounce back to Settings. | +| **Issue sidebar → Pull requests** | Every PR auto-linked to this issue, with title, repo, state (`Open` / `Draft` / `Merged` / `Closed`), and author. Click a row to jump to the PR on GitHub. | +| **Webhook (background)** | On every `pull_request` event, Multica upserts the PR row, scans the PR for issue identifiers, and (re)builds the link rows. Idempotent — replaying a delivery is a no-op. | +| **Auto-status on merge** | When a PR transitions to `merged`, every linked issue not already `Done` or `Cancelled` is moved to `Done`. The status change is timeline-logged with source `github_pr_merged`. | + +Only the PR itself is mirrored. Commits, branch refs without an open PR, and CI check states are **not** modeled. The integration is intentionally narrow. + +## How identifiers are matched + +The webhook extracts identifiers from three fields, in this order: **PR head branch**, **PR title**, **PR body**. The matcher is: + +- Case-insensitive — `mul-123`, `MUL-123`, `Mul-123` all match. +- Bounded — a `\b` on the left and a digit anchor on the right keep it from grabbing version numbers like `v1.2-3` or email-style strings. +- Workspace-scoped — only matches the workspace's own [issue prefix](/workspaces). `FOO-1` in a workspace whose prefix is `MUL` is ignored, even if the integer matches another issue. +- Deduplicated — listing `MUL-1, MUL-1` in the body links the issue once. + +You can reference **multiple issues** in one PR. `Closes MUL-1, MUL-2` links the PR to both, and merging it advances both to `Done`. + +## The auto-merge-to-Done rule + +When a PR's `merged` field flips to `true`, every linked issue is evaluated: + +| Issue current status | Result | +|---|---| +| `done` | No change (already terminal). | +| `cancelled` | **No change** — cancelled means the user explicitly abandoned the work; the integration does not override that signal. | +| Anything else (`todo`, `in_progress`, `in_review`, `blocked`, `backlog`) | Moved to `done`. | + +Closing a PR **without** merging it only updates the PR card's state to `Closed`. The linked issues stay where they were — the user is the one who decides what closing-without-merge means. + + +The action is attributed to the `system` actor on the timeline. Subscribers of the issue receive an inbox notification for the status change, the same way they would if a human had moved it. + + +## What's not auto-linked + +- **Identifiers in commit messages** — only branch / title / body are scanned. A commit titled `MUL-123: fix login` does not auto-link unless the same string also appears in the PR title or body. +- **Identifiers in PR comments** — only the PR's own metadata is scanned; later GitHub comments are ignored. +- **PRs in repos the App isn't installed on** — without the App, Multica never receives the webhook. +- **Manually linking a PR to an issue** — there is no UI for this yet. If your team's convention puts identifiers in a place Multica isn't reading, add them to the PR title or body. + +## Disconnecting + +In **Settings → Integrations** there is no installation list — you manage existing installations from GitHub directly: + +- **From GitHub** — uninstall the Multica GitHub App at `https://github.com/settings/installations` (personal) or `https://github.com/organizations//settings/installations` (org). Multica receives the `installation.deleted` webhook and drops the row in real time; any open Settings tab updates without a refresh. +- **Disconnect from inside Multica is admin-only** — the Settings card is hidden for non-admins. + +After disconnect, mirrored PR rows stay in the database so historical issue sidebars still show what was linked, but no new webhook events from that installation will be accepted. + +## Permissions and visibility + +- **Connect / disconnect** require workspace **owner or admin**. Members see the card description but no Connect button. +- The **Pull requests** sidebar on an issue is visible to anyone who can read the issue — same permissions as the rest of issue detail. +- The GitHub App requests **read-only** access to pull requests and metadata. Multica never pushes commits, comments, or status checks back to GitHub. + +## Self-host setup + +If you're running Multica on Multica Cloud, the integration is already configured — skip this section. + +For self-host, you create one GitHub App, point it at your server, and set two environment variables. The whole flow is below. + +### 1. Create a GitHub App + +Go to one of: + +- Personal account → `https://github.com/settings/apps/new` +- Organization → `https://github.com/organizations//settings/apps/new` + +Fill in: + +| Field | Value | +|---|---| +| **GitHub App name** | Anything recognizable, e.g. `Multica` or `Multica (staging)`. | +| **Homepage URL** | Your Multica frontend, e.g. `https://multica.example.com`. | +| **Callback URL** | Leave blank — Multica doesn't use OAuth user identity. | +| **Setup URL** | `https:///api/github/setup`. **Check "Redirect on update"**. | +| **Webhook → Active** | Enabled. | +| **Webhook URL** | `https:///api/webhooks/github`. | +| **Webhook secret** | Generate a long random string (e.g. `openssl rand -hex 32`). You'll paste the same value into Multica's env in step 2. | +| **Permissions → Repository → Pull requests** | **Read-only**. | +| **Permissions → Repository → Metadata** | Read-only (mandatory). | +| **Subscribe to events** | Tick **Pull request**. | +| **Where can this GitHub App be installed?** | Your choice. `Only on this account` is fine for single-org setups. | + +After **Create GitHub App**, note two things from the App's detail page: + +- The **public link** at the top — its tail is the slug. `https://github.com/apps/multica-acme` → slug = `multica-acme`. +- The **webhook secret** you just generated (you can't read it back from GitHub later — save it now). + + +**Webhook secret ≠ Client secret.** The App settings page has both fields stacked together. The **Webhook secret** is what signs `pull_request` payloads — that's the one Multica needs. The **Client secret** is for OAuth and is not used by this integration. Mixing them up produces a confusing `401 invalid signature` on every webhook delivery. + + +### 2. Set environment variables + +On the API server: + +```env +GITHUB_APP_SLUG=multica-acme +GITHUB_WEBHOOK_SECRET= +``` + +Both variables are required. If either is missing: + +- `Connect GitHub` in Settings is **disabled** and shows a "not configured" hint. +- The `/api/webhooks/github` endpoint returns **`503 github webhooks not configured`** — Multica refuses to process events with no secret, rather than silently treating every signature as valid. + +`FRONTEND_ORIGIN` must also be set (it already is for any production self-host); the setup callback bounces the user back to `/settings` after install. + +Restart the API after setting the env vars. + +### 3. Run migrations + +The integration ships its tables in migration `079_github_integration`. If you're upgrading an older deployment: + +```bash +make migrate-up +``` + +Three tables get created: `github_installation`, `github_pull_request`, `issue_pull_request`. They cascade-delete with their workspace, so removing a workspace cleans them up automatically. + +### 4. Connect from the UI + +In Multica: + +1. Open **Settings → Integrations** as an owner or admin. +2. Click **Connect GitHub**. GitHub opens in a new tab. +3. Pick the repositories to grant access to and **Install**. +4. GitHub redirects back to `/api/github/setup`, which records the installation and bounces you to `/settings?github_connected=1`. + +After that, open any PR whose branch / title / body contains an issue identifier — within a few seconds the Pull requests block appears on that issue's detail page. + +### 5. Verify with a curl probe + +If GitHub's **Recent Deliveries** page reports `401 invalid signature` after install, the two sides have different secrets. The fastest way to find out which side is wrong is to bypass GitHub: + +```bash +SECRET="" +BODY='{"zen":"test"}' +SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}') +curl -i -X POST https:///api/webhooks/github \ + -H "X-Hub-Signature-256: sha256=$SIG" \ + -H "X-GitHub-Event: ping" \ + -H "Content-Type: application/json" \ + -d "$BODY" +``` + +| HTTP status | Meaning | Fix | +|---|---|---| +| `200` `{"ok":"pong"}` | Server's loaded secret matches your `$SECRET`. The mismatch is on GitHub. | Edit the App → Webhook secret → **paste the same value** → **Save changes** (clicking out of the field without Save keeps the old secret). Redeliver. | +| `401 invalid signature` | Server's loaded secret is **not** what you think it is. | Confirm the env var landed in the running process (e.g. `kubectl exec` → `echo -n "$GITHUB_WEBHOOK_SECRET" | wc -c`). Re-deploy. | +| `503 github webhooks not configured` | `GITHUB_WEBHOOK_SECRET` is empty in the process. | Set the env var, restart the API. | + +## Limitations + +A few rough edges to be aware of today: + +- **No manual link UI yet** — the only way to link a PR is to have the identifier in its branch, title, or body. +- **No CI / check state** — only the PR itself is mirrored. Build status, review comments, and reviewers are not surfaced in Multica. +- **No workspace-level config** for the merge → Done rule — it's a fixed default (`merged → done`, unless `cancelled`). Workspace-customizable mappings are a future addition. +- **Multi-PR-to-one-issue is conservative on merge** — if two PRs both reference `MUL-123` and the first one merges, the issue is moved to `Done` immediately. A follow-up change to wait for all linked PRs to resolve before advancing is in progress. + +## Next + +- [Issues](/issues) — the issue identifiers (`MUL-123`) referenced from PRs +- [Workspaces](/workspaces) — where the workspace-specific issue prefix is set +- [Environment variables](/environment-variables) — full env reference, including the GitHub variables above diff --git a/apps/docs/content/docs/github-integration.zh.mdx b/apps/docs/content/docs/github-integration.zh.mdx new file mode 100644 index 000000000..19f38e80c --- /dev/null +++ b/apps/docs/content/docs/github-integration.zh.mdx @@ -0,0 +1,183 @@ +--- +title: GitHub 集成 +description: 一次性连接 GitHub App,之后 PR 的分支名、标题或正文里写了 issue 编号(例如 MUL-123),就会自动挂到那个 issue 上——PR 合并时 issue 自动转 Done。 +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +在 **Settings → Integrations** 里一次性连一个 GitHub 账号或组织。之后任何 PR 只要分支名、标题或正文里出现 issue 编号(例如 `MUL-123`),就会**自动关联**到那个 [issue](/issues),出现在 issue 详情页右侧的 **Pull requests** 区块里——PR 合并时,issue 自动转 **Done**。 + +没有 per-issue 的配置,整个流程是「编号驱动」的。 + +## 集成做了什么 + +| 出现位置 | 行为 | +|---|---| +| **Settings → Integrations** | 工作区 owner / admin 看到一个 GitHub 卡片,里面有 **Connect GitHub** 按钮。点击会打开 GitHub 的 App 安装页;装好后跳回 Settings。 | +| **Issue 详情侧栏 → Pull requests** | 列出所有自动关联到该 issue 的 PR,含标题、仓库、状态(`Open` / `Draft` / `Merged` / `Closed`)和作者。点一行跳到 GitHub。 | +| **Webhook(后台)** | 每次 `pull_request` 事件触发:upsert PR 行 → 扫描里面的 issue 编号 →(重新)建立 link。幂等——重投 delivery 不会产生重复记录。 | +| **Merge 自动改 status** | PR 转 `merged` 时,所有已关联且状态不是 `Done` / `Cancelled` 的 issue 会被推到 `Done`。时间线里以 source 为 `github_pr_merged` 记录。 | + +只镜像 PR 本身。Commit、没开 PR 的分支、CI 检查状态都**不**入库——集成有意保持窄边界。 + +## 编号是怎么匹配的 + +Webhook 从三个字段抽取编号,顺序是:**PR head 分支** → **PR 标题** → **PR 正文**。匹配规则: + +- 大小写不敏感——`mul-123`、`MUL-123`、`Mul-123` 都能匹配 +- 有边界——左侧 `\b`、右侧只接数字,避免误抓 `v1.2-3`、email 地址等 +- 限定到本工作区——只匹配本工作区的 [issue prefix](/workspaces)。前缀是 `MUL` 的工作区里,PR 出现 `FOO-1` 不会匹配,即使数字撞另一个 issue 也不会 +- 自动去重——`Closes MUL-1, MUL-1` 只关联一次 + +一个 PR 里**可以同时引用多个 issue**。比如 `Closes MUL-1, MUL-2`:PR 同时关联两个 issue,合并时两个 issue 都会转 `Done`。 + +## Merge 自动转 Done 的规则 + +PR 的 `merged` 字段翻成 `true` 时,逐个评估关联的 issue: + +| Issue 当前状态 | 结果 | +|---|---| +| `done` | 不变(已经是终态)| +| `cancelled` | **不变**——cancelled 是用户明确放弃工作的信号,集成不覆盖 | +| 其他(`todo` / `in_progress` / `in_review` / `blocked` / `backlog`)| 转成 `done` | + +PR **关闭但没合并**——只更新 PR 卡片的状态为 `Closed`,issue 状态不变。"关闭但不合并"语义因团队而异,Multica 不替用户做决定。 + + +状态变更的 actor 是 `system`。订阅了该 issue 的成员会收到 inbox 通知,和成员手动改状态时一致。 + + +## 哪些情况不会自动关联 + +- **Commit message 里的编号**——只扫 PR 的分支 / 标题 / 正文。一个 commit message 写 `MUL-123: fix login` 不会触发关联,除非同样的字符串也出现在 PR 标题或正文里 +- **PR 评论里的编号**——只扫 PR 自己的元数据,后续的 GitHub comment 不读 +- **App 没安装的仓库里的 PR**——没 App,Multica 收不到 webhook +- **手动把 PR 关联到 issue**——暂时没有这个 UI。如果你们的约定把编号放到 Multica 不扫的地方,请改放到 PR 标题或正文里 + +## 断开连接 + +**Settings → Integrations** 里没有 installation 列表——现有 installation 直接到 GitHub 上管理: + +- **从 GitHub 卸载** —— 个人在 `https://github.com/settings/installations`、组织在 `https://github.com/organizations//settings/installations` 卸载 Multica App。Multica 收到 `installation.deleted` webhook 后立刻删行;任何已打开的 Settings tab 实时更新,不用刷新 +- **Multica 这边的断开是 admin only** —— 卡片对非 admin 不显示连接操作 + +断开之后,已经镜像的 PR 行保留在数据库里——历史 issue 侧栏仍能显示当时关联的 PR,但来自这个 installation 的新 webhook 事件不再被接受。 + +## 权限和可见性 + +- **Connect / Disconnect** 需要工作区 **owner 或 admin**。普通成员能看到卡片描述但看不到 Connect 按钮 +- **Pull requests** 侧栏对所有能看到该 issue 的成员可见——和 issue 详情页其他部分权限一致 +- GitHub App 申请的是 PR 和 Metadata 的 **只读** 权限。Multica 从不向 GitHub 推 commit、评论或 status check + +## Self-Host 配置 + +如果你在 Multica Cloud 上,集成已经配好——跳过本节。 + +Self-Host 需要:建一个 GitHub App、指向你的 server、设两个环境变量。完整流程如下。 + +### 1. 创建一个 GitHub App + +到下面其中一个页面: + +- 个人账号 → `https://github.com/settings/apps/new` +- 组织 → `https://github.com/organizations//settings/apps/new` + +按下表填写: + +| 字段 | 值 | +|---|---| +| **GitHub App name** | 任何能辨识的名字,例如 `Multica` 或 `Multica (staging)` | +| **Homepage URL** | 你的 Multica 前端,例如 `https://multica.example.com` | +| **Callback URL** | 留空——本集成不使用 OAuth 用户身份 | +| **Setup URL** | `https:///api/github/setup`。**勾选 "Redirect on update"** | +| **Webhook → Active** | 启用 | +| **Webhook URL** | `https:///api/webhooks/github` | +| **Webhook secret** | 生成一个长随机字符串(例如 `openssl rand -hex 32`)。这个值会同样填到 step 2 的 env 里 | +| **Permissions → Repository → Pull requests** | **Read-only** | +| **Permissions → Repository → Metadata** | Read-only(必填)| +| **Subscribe to events** | 勾选 **Pull request** | +| **Where can this GitHub App be installed?** | 自选。单组织部署建议选 `Only on this account` | + +点 **Create GitHub App** 之后,从详情页记下两件事: + +- 顶部 **public link** 的尾部即 slug。`https://github.com/apps/multica-acme` → slug = `multica-acme` +- 你刚生成的 **webhook secret**(GitHub 之后不会再让你读取这个值——现在就保存好) + + +**Webhook secret ≠ Client secret。** App 设置页里两个字段紧挨着。**Webhook secret** 用于签 `pull_request` payload,这才是 Multica 需要的那个;**Client secret** 是 OAuth 用的,和本集成无关。混淆这两个会得到「每条 webhook 都 `401 invalid signature`」的诡异症状。 + + +### 2. 配置环境变量 + +API server 上: + +```env +GITHUB_APP_SLUG=multica-acme +GITHUB_WEBHOOK_SECRET=<你刚生成的 webhook secret> +``` + +两个都必填。任何一个缺失: + +- Settings 里 `Connect GitHub` 按钮会被 **disable**,并显示「not configured」提示 +- `/api/webhooks/github` 直接返回 **`503 github webhooks not configured`**——Multica 在 secret 没配置时拒绝处理事件,不会出现「没 secret 也接受 webhook」的安全坑 + +`FRONTEND_ORIGIN` 也必须设置(任何生产 self-host 都已经设了)——setup 回调结束后用它把用户跳回 `/settings`。 + +设完 env 重启 API。 + +### 3. 执行 migration + +集成的表在 migration `079_github_integration` 里。如果是升级既有部署: + +```bash +make migrate-up +``` + +会创建三张表:`github_installation`、`github_pull_request`、`issue_pull_request`。三张表都 cascade 跟随 workspace——删工作区会自动清理。 + +### 4. 在 UI 里连接 + +到 Multica: + +1. 以 owner 或 admin 身份打开 **Settings → Integrations** +2. 点 **Connect GitHub**,GitHub 在新 tab 打开 +3. 选择要授权的仓库,点 **Install** +4. GitHub 跳回 `/api/github/setup`,落库后再跳到 `/settings?github_connected=1` + +之后在任意一个仓库开一个分支 / 标题 / 正文带本工作区 issue 编号的 PR——几秒内对应 issue 的详情页上就能看到 Pull requests 区块。 + +### 5. 用 curl 自检 + +如果 GitHub 的 **Recent Deliveries** 里第一次 PR 事件就报 `401 invalid signature`,说明两边的 secret 不一致。绕过 GitHub 直接测 server 是最快的定位方法: + +```bash +SECRET="<你填给 GITHUB_WEBHOOK_SECRET 的值>" +BODY='{"zen":"test"}' +SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}') +curl -i -X POST https:///api/webhooks/github \ + -H "X-Hub-Signature-256: sha256=$SIG" \ + -H "X-GitHub-Event: ping" \ + -H "Content-Type: application/json" \ + -d "$BODY" +``` + +| HTTP 状态 | 含义 | 修法 | +|---|---|---| +| `200` `{"ok":"pong"}` | server 加载的 secret 和你 `$SECRET` 一致——GitHub 那边的 secret 才是错的 | 编辑 App → Webhook secret 字段**粘相同的值** → **必须点 Save changes**(不点 Save 等于没改)→ Redeliver | +| `401 invalid signature` | server 加载的 secret **不是**你以为的那个 | 进容器确认 env 实际生效(例如 `kubectl exec` → `echo -n "$GITHUB_WEBHOOK_SECRET" \| wc -c`),重新部署 | +| `503 github webhooks not configured` | `GITHUB_WEBHOOK_SECRET` 在进程里是空的 | 配上 env,重启 API | + +## 已知限制 + +目前还没做的几个边界: + +- **手动 link UI 暂未提供**——关联 PR 的唯一方法是把 issue 编号写到 PR 分支 / 标题 / 正文 +- **不读 CI / check 状态**——只镜像 PR 本身,构建状态、reviewer 评论、reviewer 列表都没接进 Multica +- **没有工作区级别的 merge → status 映射配置**——默认固定是 `merged → done`(cancelled 除外)。可配置映射是后续迭代 +- **同 issue 多 PR 时,merge 行为偏激进**——两个 PR 都引用 `MUL-123` 时,第一个 merge 就把 issue 转 Done。"等所有关联 PR 都解决再推进 issue 状态"的优化已经在做了 + +## 下一步 + +- [Issues](/issues) —— PR 引用的 issue 编号(`MUL-123`)的来源 +- [工作区](/workspaces) —— 工作区 issue prefix 的设置位置 +- [环境变量](/environment-variables) —— 完整 env 清单,包含上面提到的 GitHub 变量 diff --git a/apps/docs/content/docs/meta.json b/apps/docs/content/docs/meta.json index 7a05fd19d..bf4fef2e4 100644 --- a/apps/docs/content/docs/meta.json +++ b/apps/docs/content/docs/meta.json @@ -27,6 +27,8 @@ "autopilots", "---Inbox---", "inbox", + "---Integrations---", + "github-integration", "---Self-hosting & ops---", "environment-variables", "auth-setup", diff --git a/apps/docs/content/docs/meta.zh.json b/apps/docs/content/docs/meta.zh.json index ae54761a1..688d302b5 100644 --- a/apps/docs/content/docs/meta.zh.json +++ b/apps/docs/content/docs/meta.zh.json @@ -26,6 +26,8 @@ "autopilots", "---收件箱---", "inbox", + "---集成---", + "github-integration", "---自部署运维---", "environment-variables", "auth-setup", diff --git a/apps/docs/content/docs/self-host-quickstart.mdx b/apps/docs/content/docs/self-host-quickstart.mdx index 12811bf45..6206ea10f 100644 --- a/apps/docs/content/docs/self-host-quickstart.mdx +++ b/apps/docs/content/docs/self-host-quickstart.mdx @@ -115,5 +115,6 @@ Same flow as Cloud — see [Cloud quickstart → Steps 5-6](/cloud-quickstart#5- - [Environment variables](/environment-variables) — full env reference - [Auth setup](/auth-setup) — Resend / OAuth / signup allowlist in detail +- [GitHub integration](/github-integration) — connect a GitHub App so PRs auto-link to issues and merging closes them - [Troubleshooting](/troubleshooting) — start here when things go wrong - [Desktop app](/desktop-app) — optional Desktop setup via `~/.multica/desktop.json`; the web frontend + CLI remains the quickest self-host path diff --git a/apps/docs/content/docs/self-host-quickstart.zh.mdx b/apps/docs/content/docs/self-host-quickstart.zh.mdx index c1a9dee06..3e7231acd 100644 --- a/apps/docs/content/docs/self-host-quickstart.zh.mdx +++ b/apps/docs/content/docs/self-host-quickstart.zh.mdx @@ -114,5 +114,6 @@ multica setup self-host - [环境变量](/environment-variables) —— 完整 env 清单 - [登录与注册配置](/auth-setup) —— Resend / OAuth / 注册白名单详细配置 +- [GitHub 集成](/github-integration) —— 连一个 GitHub App,让 PR 自动关联 issue、merge 时自动转 Done - [故障排查](/troubleshooting) —— 遇到问题先来这里 - [桌面应用](/desktop-app) —— 可以通过 `~/.multica/desktop.json` 连接 Desktop;Web 前端 + CLI 仍然是最快的自部署路径