From 5487490173f543db28f485638bb06a426bfec868 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 17 Sep 2026 14:15:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(issue-update):=20=E6=94=AF=E6=8F=B4=20--ov?= =?UTF-8?q?erview-url=EF=BC=8C=E6=8A=8A=E7=B8=BD=E8=A6=BD=E7=B6=B2?= =?UTF-8?q?=E5=9D=80=E5=AF=AB=E5=9B=9E=E8=AD=B0=E9=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 沿用既有的 upsertLineInSection:連結以固定前綴獨佔總覽段落裡的一行,重跑時就地 更新,不會長出第二個連結;議題原本的 markdown 白話總覽一字不動——網頁是補充, 不是取代。 連結旁自動附上「此連結預設為私有,組織外無法開啟」。讀到的人多半會想轉寄給組織外 的人,這句話寫在議題上比寫在文件裡有用。 Co-Authored-By: Claude Opus 5 (1M context) --- scripts/issue-update.js | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/scripts/issue-update.js b/scripts/issue-update.js index 17ac0e0..6745f87 100644 --- a/scripts/issue-update.js +++ b/scripts/issue-update.js @@ -9,10 +9,13 @@ * * Milestone 只認既有的:指到不存在的就中止並列出可選項目,本工具不建立 Milestone。 * + * 也負責把圖解版總覽的網址寫回議題:連結以固定前綴獨佔一行,重跑時就地更新, + * 議題原本的 markdown 白話總覽一字不動——網頁是補充,不是取代。 + * * 用法: * node scripts/issue-update.js --repo owner/name --index 12 * [--milestone <名稱>] [--due-date YYYY-MM-DD] [--estimate-days N] - * [--host <網址>] [--dry-run] + * [--overview-url <網址>] [--host <網址>] [--dry-run] */ import { ScriptError, @@ -30,18 +33,19 @@ import { upsertLineInSection } from './issue-body.js'; main(async () => { const flags = parseFlags(process.argv.slice(2), { required: ['repo', 'index'], - optional: ['milestone', 'due-date', 'estimate-days', 'host'], + optional: ['milestone', 'due-date', 'estimate-days', 'overview-url', 'host'], booleans: ['dry-run'], }); const repo = parseRepo(flags.repo); const index = parseIndex(flags.index); const dueDate = parseDueDate(flags['due-date']); const days = parseDays(flags['estimate-days']); + const overviewUrl = parseOverviewUrl(flags['overview-url']); - if (flags.milestone === undefined && dueDate === null && days === null) { + if (flags.milestone === undefined && dueDate === null && days === null && overviewUrl === null) { throw new ScriptError( 'NOTHING_TO_UPDATE', - '至少要指定 --milestone、--due-date 或 --estimate-days 其中一個', + '至少要指定 --milestone、--due-date、--estimate-days 或 --overview-url 其中一個', ); } @@ -57,11 +61,16 @@ main(async () => { if (dueDate !== null) { payload.due_date = `${dueDate}T00:00:00Z`; } - if (days !== null) { + if (days !== null || overviewUrl !== null) { const issue = expectOk(await giteaRequest(login, 'GET', path), `GET ${path}`); - const updated = upsertLineInSection(issue.body ?? '', '關聯', `估算人天:${days}`); + let body = issue.body ?? ''; + + if (days !== null) body = upsertLineInSection(body, '關聯', `估算人天:${days}`); + if (overviewUrl !== null) { + body = upsertLineInSection(body, '總覽', `圖解版總覽:${overviewUrl}${PRIVACY_NOTE}`); + } // 沒變就不塞進 PATCH:無謂改寫 body 會在議題上留下一筆沒有內容的編輯紀錄 - if (updated !== issue.body) payload.body = updated; + if (body !== issue.body) payload.body = body; } if (flags['dry-run']) { @@ -86,6 +95,17 @@ function parseDueDate(value) { return value; } +/** artifact 預設私有,組織外開不起來——這件事要跟著連結一起留在議題上 */ +const PRIVACY_NOTE = '(此連結預設為私有,組織外無法開啟)'; + +function parseOverviewUrl(value) { + if (value === undefined) return null; + if (!/^https?:\/\/\S+$/.test(value)) { + throw new ScriptError('BAD_OVERVIEW_URL', `--overview-url 需為 http(s) 網址,收到的是 ${value}`); + } + return value; +} + function parseDays(value) { if (value === undefined) return null; const days = Number(value);