跳至內容

PR 對話

Pull request 本來就是討論程式碼的地方。PR 對話把它變成 Control Center 工作區上的一個介面,就像聊天橋接把 Slack 變成介面一樣:在 PR 上 @提及伺服器的 GitHub App 機械人、在它的審查討論串內 回覆,或加上 ai-review 標籤,工作就會在 PR 的審查空間中進行——歸屬方式 和護欄都與在應用程式內輸入的任何內容相同。評論同樣受成員身分限制;標籤則 不受限,因為它沒有作者。機械人的答覆會回到 GitHub,就在問題所提出的同一條 渠道上。

三個決定塑造了這項功能,而每一個都是聊天橋接為聊天作過、再為程式碼託管 平台重述的同一個決定:連線往哪個方向走、來自外部的評論由甚麼授權, 以及對話每一方歸屬於誰。

GitHub 為應用程式提供的唯一推送渠道是 webhook,而 webhook 需要一個入站 URL——這正是這個介面刻意從不要求的東西。因此探索靠一輪掃描:每隔約 一分鐘,每個應用程式安裝各自執行一次別名搜尋,向 GitHub 查詢提及機械人 (或其短 slug)的 PR,以及帶有審查標籤的開啟中 PR;已有審查空間的 PR 會 讀取其評論討論串,然後所有內容都以評論 id 與上次掃描所見的逐項比對。

設計上的幾個後果值得點名:

  • 延遲是一個掃描週期,而不是一個事件。 👀 確認會在大約一分鐘內出現。 沒有急事會靠它。
  • 每則評論恰好一次。 評論 id 在 GitHub 上是唯一的;每則評論在判定為 符合資格的那一刻就會被記錄,先於任何對它的處理。當機可能令某則評論的 處理遺失,但絕不會令它重複觸發。
  • 離線期間的內容會補上,而不是重播。 已見集合會被持久保存,因此重新 啟動後會處理停機期間到達的內容。唯一的例外是史上第一次掃描:沒有記憶 可比對,所有未處理的項目都會靜靜記錄下來——在這部伺服器存在之前就為 二十個 PR 加上標籤的操作者,回來時不應該見到二十個正在執行的審查。
  • 標籤是一個狀態,而不是一個事件。 搜尋報告的是標籤的_存在_,所以 一個已加標籤的 PR 只會觸發一次,僅此一次。移除標籤後再次加上,掃描並 不會察覺;要重跑就得靠提及。

搜尋會為每個安裝帳戶、以該擁有者自己的用戶端執行一次,因為安裝權杖只看 得到自己那次安裝的程式庫——單一個伺服器層級的憑證,會靜靜漏掉應用程式 其他安裝下的每個 PR。

一則 PR 評論送達時,所帶的幾乎只有作者的登入名稱——一個未經認證的外部 身分,直到被證實為止。機械人會以工作區成員及其已連接 GitHub 帳戶的反向 索引來解析它;該索引會按 TTL 重建,因為伺服器執行期間有人會登入、有人會 受邀。

預設拒絕的做法像一道梯級,而每一級都會在被拒絕的那條討論串內作答:

  • 未知的登入名稱——未連結,或由不是這個工作區成員的人連結——會被要求 登入並確認自己確實屬於此處
  • 唯讀成員(viewer 或 guest)會被告知其角色無法啟動工作

兩種未知登入的情況共用同一個回覆:反向索引只會傳回_這個_工作區的成員, 所以未連結的帳戶與已連結的非成員是同一種落空。它們都不會繼續。評論永遠 不會歸屬於沒有發出它的人,陌生人的話語也永遠不會進入他看不見的工作區。

ai-review 標籤沒有作者可解析,所以不會爬這道梯。加上它,就會在已經連結 該程式庫的工作區中啟動審查。

對話的每一方都帶著不同的身分,而這個差異正是功能所在:

  • 在 GitHub 上,機械人就是伺服器。 橋接所發佈的每則評論、表情反應和 回覆,都使用應用程式的安裝權杖。沒有任何人在用戶端點擊過任何東西, 所以不會借用個人帳戶——這條規則同樣令 webhook 和輪詢不倚賴人的憑證。
  • 在空間內,問題屬於你。 訊息會歸屬於作者所解析到的成員,代理執行 也代表該成員進行:提交會把該成員列為共同作者,空間的自主調節與動作 護欄也完全如同對待應用程式內輸入的訊息一樣套用。執行期間對程式碼託管 平台的寫入,仍然以應用程式身分發出——與上一點的規則相同——而不是用 該成員的個人權杖。

把審查結果發佈回 GitHub 仍然是由人在 Control Center 所作的決定。提及可以 _啟動_一次審查;發佈則只能由人來做。

任何由機械人帳戶撰寫的內容,都會在任何關卡執行之前被捨棄——包括我們自己 的機械人,以及所有帶 [bot] 後綴的帳戶,這樣其他應用程式的審查機械人也 無法喚醒我們的。沒有這道防護,機械人自己的答覆會以新評論的形式到達,令 它永遠重複觸發。

[bot] 後綴也是短格式存在的原因。GitHub 把應用程式帳戶的登入名稱固定為 <slug>[bot],不為它提供自動完成,也永遠不會把 @slug 解析到該應用 程式——所以接受只有 slug 的寫法是_我們的_比對器所作的決定,而要發現它,需要一條 直接搜尋評論文字的路徑,而不是 GitHub 的提及索引。這個代價會被明說, 而不是被含糊帶過:一個與應用程式 slug 相同的人類使用者,每次以短格式提及 自己時,都會同時向機械人發話。應用程式名稱夠獨特的話,這種衝突只是假設。

  • 不自動發佈。 審查結果會落在審查空間;發佈到 GitHub 是另一個由人 執行的動作
  • 不做模糊身分。 作者只會解析到恰好一個成員,否則被拒絕——沒有猜測式 的歸屬
  • 不用 GitHub App webhook。 這個介面從不註冊 webhook,所以沒有為 PR 評論而暴露的入站 URL。其他產品 webhook(管線、工單同步)屬於另一項 選用設定。