feat(wp-list): 列出一顆需求議題底下的工作包
歸屬判準沿用工作包抽取那一套(關聯段落的「需求議題:#N」),不另發明一套; PR 的描述也有那一行,所以先擋掉 PR。清單逐頁讀完,讀不完寧可報錯—— 使用者會從缺了幾顆的清單裡挑,而且看不出缺的是哪幾顆。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* 列出一顆需求議題底下的工作包。
|
||||
*
|
||||
* 使用者手上常常只有需求議題的編號——留言發在那裡、討論也在那裡——但真正要動手的
|
||||
* 單位是工作包。這一支把「哪幾顆工作包掛在這顆需求底下」答出來,讓他從清單裡挑一顆,
|
||||
* 而不是自己去 Gitea 網頁上翻。
|
||||
*
|
||||
* **判準沿用工作包抽取那一套**:關聯段落裡的 `需求議題:#<編號>`(見 wp-extract 的
|
||||
* `需求議題` 欄位,解析同樣走 issue-body 的 referencedIndex)。不另發明判準——標籤、
|
||||
* 標題前綴、相依關係都各有各的用途,拿它們當歸屬會與抽取契約分岔。
|
||||
*
|
||||
* **PR 不算工作包。** 每個 PR 都是議題,而 pr-create 產出的 PR 描述本來就有
|
||||
* 「需求議題:#N」那一行,只看 body 會把 PR 混進清單裡。
|
||||
*
|
||||
* 清單逐頁讀完,讀不完寧可報錯:半份清單會讓使用者從缺了幾顆的清單裡挑,
|
||||
* 而且他看不出來缺的是哪幾顆。
|
||||
*
|
||||
* 用法:
|
||||
* node scripts/wp-list.js --repo owner/name --requirement 7 [--host <網址>] [--dry-run]
|
||||
*/
|
||||
import {
|
||||
main,
|
||||
pages,
|
||||
parseFlags,
|
||||
parseIndex,
|
||||
parseRepo,
|
||||
preflight,
|
||||
resolveLogin,
|
||||
} from './lib.js';
|
||||
import { parseSections, referencedIndex } from './issue-body.js';
|
||||
|
||||
main(async () => {
|
||||
const flags = parseFlags(process.argv.slice(2), {
|
||||
required: ['repo', 'requirement'],
|
||||
optional: ['host'],
|
||||
booleans: ['dry-run'],
|
||||
});
|
||||
const repo = parseRepo(flags.repo);
|
||||
const requirement = parseIndex(flags.requirement, '--requirement');
|
||||
const issuesPath = `/repos/${repo}/issues`;
|
||||
|
||||
if (flags['dry-run']) {
|
||||
return {
|
||||
dryRun: true,
|
||||
repo,
|
||||
需求議題: requirement,
|
||||
requests: [{ method: 'GET', path: issuesPath }],
|
||||
note: '議題清單逐頁讀完,頁數取決於 repo 的議題總數,事前無法列舉。',
|
||||
};
|
||||
}
|
||||
|
||||
const login = resolveLogin({ host: flags.host });
|
||||
await preflight(login, repo);
|
||||
|
||||
const 工作包 = [];
|
||||
for await (const issues of pages(login, issuesPath, {
|
||||
query: { state: 'all' },
|
||||
limitCode: 'WORK_PACKAGE_LIMIT',
|
||||
limitHint: `翻不完 ${repo} 的議題,列不出 #${requirement} 底下的完整工作包清單;請直接在 Gitea 上確認`,
|
||||
})) {
|
||||
for (const issue of issues) {
|
||||
if (!belongsTo(issue, requirement)) continue;
|
||||
工作包.push({
|
||||
index: issue.number,
|
||||
title: issue.title,
|
||||
url: issue.html_url,
|
||||
state: issue.state,
|
||||
assignee: issue.assignee?.login ?? null,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 依編號排序:Gitea 的回傳順序會隨排序設定而變,清單的順序卻是使用者挑選的依據
|
||||
工作包.sort((a, b) => a.index - b.index);
|
||||
|
||||
return { repo, 需求議題: requirement, 工作包, 數量: 工作包.length };
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 這顆議題是不是掛在指定需求底下的工作包。
|
||||
* PR 先擋掉——它的描述也有「需求議題:#N」那一行,但它不是工作包。
|
||||
*/
|
||||
function belongsTo(issue, requirement) {
|
||||
if (issue.pull_request != null) return false;
|
||||
return referencedIndex(parseSections(issue.body), '關聯', '需求議題') === requirement;
|
||||
}
|
||||
Reference in New Issue
Block a user