refactor(lib): 讀檔與列留言收進 lib,並讓已整併只認自己打的 +1
「讀一個 --xxx-file 或直接失敗」原本在四支腳本各寫一份,錯誤碼還有三種拼法 (BODY_FILE_NOT_FOUND/BODY_FILE_MISSING/CONTENT_FILE_NOT_FOUND)。同一種情況要有同一個 碼,呼叫端才分辨得出是哪一步壞了。留言分頁的那段咒語也是第三份,一併收成 listIssueComments。 countUnmergedComments 原本接受任何人的 +1,而讀留言那邊只認自己的——兩端對「已整併」的 定義不一致。後果是隊友對決策留言按個讚,未處理留言數就掉到 0,analyze 與 feat 再也不提示, 那則決策永遠不會被收進描述。統一成只認自己打的:別人按讚是「我同意」,不是「已經收進去了」。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+61
-14
@@ -663,6 +663,28 @@ function checkTimeTracker(info) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 讀一個由 flag 指定的文字檔。
|
||||
*
|
||||
* 「讀一個 --xxx-file 或直接失敗」原本在四支腳本裡各寫一份,錯誤碼還有三種拼法。
|
||||
* 同一種情況要有同一個碼,呼叫端才分辨得出到底是哪一步壞了。
|
||||
*
|
||||
* @param {string} path 檔案路徑
|
||||
* @param {string} flag 出現在錯誤訊息裡的 flag 名,例如 '--body-file'
|
||||
* @param {{allowEmpty?: boolean}} options 內容可不可以是空的;預設不可以
|
||||
* @returns {string}
|
||||
*/
|
||||
export function readTextFile(path, flag, { allowEmpty = false } = {}) {
|
||||
if (!existsSync(path)) {
|
||||
throw new ScriptError('FILE_NOT_FOUND', `找不到 ${flag} 指定的檔案 ${path}`);
|
||||
}
|
||||
const content = readFileSync(path, 'utf8');
|
||||
if (!allowEmpty && content.trim() === '') {
|
||||
throw new ScriptError('FILE_EMPTY', `${flag} 指定的檔案 ${path} 是空的`);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
// ── 議題讀取:兩支抽取腳本共用 ────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -697,32 +719,57 @@ export const UNMERGED_COMMENT_NOTE =
|
||||
* 數出尚未被整併回描述的留言則數。
|
||||
*
|
||||
* 抽取契約只讀 body 不讀留言,這個數字是下游判斷「手上的描述是不是過期了」的唯一依據。
|
||||
* 已整併的留言會被打上 `+1` reaction(由 sdlc-sync 負責標記),而 Gitea 的留言物件
|
||||
* 不含 reaction,所以只能逐則再查一次。留言多時請求數會跟著長,但這個數字要準
|
||||
* ——它決定下游會不會拿著過期的描述做事,所以留言也要逐頁讀完,讀不完寧可報錯。
|
||||
* 已整併的留言會被打上 `+1` reaction(由 sdlc-sync 負責標記)。留言多時請求數會跟著長,
|
||||
* 但這個數字要準——它決定下游會不會拿著過期的描述做事,所以留言也要逐頁讀完,
|
||||
* 讀不完寧可報錯。
|
||||
*
|
||||
* @param {{base: string, token: string}} login
|
||||
* @param {string} repo owner/name
|
||||
* @param {number} index
|
||||
* @param {string} me 目前登入帳號:只有自己打的 `+1` 才算整併過
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
export async function countUnmergedComments(login, repo, index) {
|
||||
const commentsPath = `/repos/${repo}/issues/${index}/comments`;
|
||||
export async function countUnmergedComments(login, repo, index, me) {
|
||||
let unmerged = 0;
|
||||
|
||||
for await (const comments of pages(login, commentsPath, {
|
||||
limitCode: 'COMMENT_LIMIT',
|
||||
limitHint: `${commentsPath} 的留言太多,數不完未整併的則數`,
|
||||
})) {
|
||||
for (const comment of comments) {
|
||||
const path = `/repos/${repo}/issues/comments/${comment.id}/reactions`;
|
||||
const reactions = expectOk(await giteaRequest(login, 'GET', path), `GET ${path}`) ?? [];
|
||||
if (!reactions.some((reaction) => reaction.content === '+1')) unmerged += 1;
|
||||
}
|
||||
for await (const comment of listIssueComments(login, repo, index)) {
|
||||
if (!(await mergedByMe(login, repo, comment.id, me))) unmerged += 1;
|
||||
}
|
||||
return unmerged;
|
||||
}
|
||||
|
||||
/**
|
||||
* 逐頁走過一顆議題(或 PR)的一般留言。
|
||||
* 三支腳本都要做這件事:數未整併的則數、列出留言內容、核對 --merged 的 id。
|
||||
* @returns {AsyncGenerator<object>} 一則一則交出去
|
||||
*/
|
||||
export async function* listIssueComments(login, repo, index) {
|
||||
const path = `/repos/${repo}/issues/${index}/comments`;
|
||||
|
||||
for await (const comments of pages(login, path, {
|
||||
limitCode: 'COMMENT_LIMIT',
|
||||
limitHint: `${path} 的留言太多,讀不完整份清單`,
|
||||
})) {
|
||||
for (const comment of comments) yield comment;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 這一則是不是「我」標記過已整併。
|
||||
*
|
||||
* Gitea 的留言物件不含 reaction,只能逐則再查一次。認的是自己打的 `+1`:
|
||||
* 別人按讚是「我同意」,當成已整併會讓那一則的決策永遠不被收進描述——
|
||||
* 而那正是 /sdlc-sync 要解決的事。
|
||||
*
|
||||
* @param {string} me 目前登入帳號;preflight 的回傳帶得出來
|
||||
*/
|
||||
export async function mergedByMe(login, repo, id, me) {
|
||||
const path = `/repos/${repo}/issues/comments/${id}/reactions`;
|
||||
const reactions = expectOk(await giteaRequest(login, 'GET', path), `GET ${path}`) ?? [];
|
||||
|
||||
return reactions.some((reaction) => reaction.content === '+1' && reaction.user?.login === me);
|
||||
}
|
||||
|
||||
// ── 碼錶 ───────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user