refactor(lib): 停錶與議題工時清單下沉到 lib
停錶原本只長在 pr-create 裡,而規劃與分析接下來也要停自己的錶(議題 #57)。 那段容錯邏輯——「錶沒在跑」的狀態碼隨站台版本而異,認的是狀態碼在 409/500 這一組**且**訊息說的是碼錶——各寫一份遲早會在某一邊漏掉一種狀態碼,而它漏掉的 症狀正是「事情做完了卻回報失敗」。 順手把簽章改成與同伴一致的 (login, repo, index):fetchIssue、listIssueTimes、 stopwatchOnIssue 都這樣收,只有它收一條手組的路徑字串。 新增 listIssueTimes 供補登判斷「這顆議題上已經有工時了嗎」。它在議題讀得到卻 404 時報 TIME_TRACKER_OFF,與四層前置檢查第四層說同一句話——試跑不跑前置檢查, 那句話得由它自己說,否則試跑看到的是一句看不懂的 404。 議題 #57 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1007,6 +1007,67 @@ export function stopwatchOnIssue(watches, repo, index) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 「這顆議題上沒有碼錶在跑」的回法不只一種:看過 500,也看過 409。
|
||||
* 狀態碼隨站台版本而異,所以認的是「狀態碼在這一組裡 **且** 訊息說的是碼錶」——
|
||||
* 只看訊息會把真的伺服器錯誤一起吞掉,只看狀態碼會把別的衝突也當成沒錶。
|
||||
*/
|
||||
const NO_STOPWATCH_STATUS = [409, 500];
|
||||
|
||||
/**
|
||||
* 停錶。停在指定議題上,只停那一顆——端點本身就是議題範圍的,
|
||||
* 停錶不會波及別顆議題上的錶,那正是領取鎖那條規則要守住的事。
|
||||
*
|
||||
* 錶沒在跑不算失敗:停錶多半排在別的事情做完之後(開完 PR、回報完),
|
||||
* 把「本來就沒在跑」報成失敗,只會讓人以為前面那件事沒做成而重跑一次。
|
||||
*
|
||||
* @param {{base: string, token: string}} login
|
||||
* @param {string} repo owner/name
|
||||
* @param {number} index
|
||||
* @returns {Promise<boolean>} 這次真的停了一支錶才是 true
|
||||
*/
|
||||
export async function stopStopwatch(login, repo, index) {
|
||||
const path = `/repos/${repo}/issues/${index}/stopwatch/stop`;
|
||||
const response = await giteaRequest(login, 'POST', path, { body: {} });
|
||||
if (response.status >= 200 && response.status < 300) return true;
|
||||
|
||||
if (
|
||||
NO_STOPWATCH_STATUS.includes(response.status) &&
|
||||
/stopwatch/i.test(response.body?.message ?? '')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
expectOk(response, `POST ${path}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 這顆議題上已經記到的工時。
|
||||
*
|
||||
* 清單的範圍隨權限而異:不是 repo admin 時 Gitea 只回自己的那幾筆,是 admin 時連別人的
|
||||
* 一起回。呼叫端(補登)問的是「這顆議題上已經有工時了嗎」,**兩種範圍都答得了那一問**:
|
||||
* 剛建好的議題上一筆都不該有,有了就代表這個流程跑過一次。範圍寬一點只會讓它偏向不補,
|
||||
* 而那是安全的方向——工時記重複比記不到更難在報表上被發現。
|
||||
* @param {{base: string, token: string}} login
|
||||
* @param {string} repo owner/name
|
||||
* @param {number} index
|
||||
* @returns {Promise<object[]>}
|
||||
*/
|
||||
export async function listIssueTimes(login, repo, index) {
|
||||
const path = `/repos/${repo}/issues/${index}/times`;
|
||||
const response = await giteaRequest(login, 'GET', path);
|
||||
|
||||
// 議題本身讀得到卻在這裡 404,代表的是 repo 的時間追蹤關著。訊息與前置檢查第四層
|
||||
// 對齊:同一件事在試跑與實跑上要說同一句話,否則試跑看到的是一句看不懂的 404
|
||||
if (response.status === 404) {
|
||||
throw new ScriptError(
|
||||
'TIME_TRACKER_OFF',
|
||||
'repo 尚未開啟時間追蹤,工時記不進去;請到 Settings → Advanced Settings → Enable Time Tracker 開啟',
|
||||
);
|
||||
}
|
||||
return expectOk(response, `GET ${path}`) ?? [];
|
||||
}
|
||||
|
||||
// ── 標籤 ───────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user