diablo2-web/scripts/create-gitea-vendor-milesto...

279 lines
20 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Creates the "M15 · 原版商人 NPC 与交易经济系统 (1.13c Ground Truth)" Milestone and its 6 atomic Issues
* in the Gitea repository https://git.projectdiablo2.cn/troytt/diablo2-web
*/
const BASE_URL = 'https://git.projectdiablo2.cn/api/v1/repos/troytt/diablo2-web'
const TOKEN = '94c84cc3bd2eab804346cb889650c843d0cda244'
async function giteaFetch<T>(path: string, method = 'GET', body?: unknown): Promise<T> {
const res = await fetch(`${BASE_URL}${path}`, {
method,
headers: {
Authorization: `token ${TOKEN}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
})
if (!res.ok) {
const txt = await res.text()
throw new Error(`Gitea API ${method} ${path} failed (${res.status}): ${txt}`)
}
return (await res.json()) as T
}
interface MilestoneResp {
id: number
title: string
state: string
}
interface IssueResp {
id: number
number: number
title: string
html_url: string
}
async function main() {
const existingMilestones = await giteaFetch<MilestoneResp[]>('/milestones?state=all&limit=50')
console.log('Existing milestones:', existingMilestones.map(m => `#${m.id}: ${m.title} (${m.state})`))
const targetTitle = '[M19] 原版商人 NPC 与交易经济系统 (1.13c Ground Truth)'
let milestone = existingMilestones.find(
m => m.id === 13 || m.title === targetTitle || m.title.includes('原版商人 NPC 与交易经济系统'),
)
const milestoneDesc = `实装暗黑破坏神 II:毁灭之王 v1.13c 原版城镇商人(Vendor NPC)库存生成、物品交易/收购/修理/赌博定价引擎与四分页商店 UI。
### 核心 Ground Truth 权威对标 (\`D2MOO\` + 官方 MPQ 数据表)
1. **商人全局物品缓存 (\`SUnitProxy.cpp\`)**:
- \`SUNITPROXY_InitializeNpcControl\` / \`SUNITPROXY_FillGlobalItemCache\` / \`SUNITPROXY_FillIGlobaltemCacheRecordForNpc\`
- 严格映射 17 位商人 ID (\`nNpcId = 0..16\`:阿卡拉、基德、恰西、法拉、雷山德、卓格南、赫拉铁力 \`Hralti*\`、阿尔科、奥玛斯、艾尔吉斯、艾席拉、凯恩、海尔布、贾梅拉、马拉、拉苏克、安亚/尼拉塞克),分离常驻商品 \`pPermCache\` (\`PermStoreItem = 1\`) 与动态随机库存 \`pItemCache\`。
2. **按商人 ID、游戏难度与角色等级动态生成出售物品 (\`SUnitNpc.cpp\`)**:
- \`D2GAME_NPC_FillStoreInventory_6FCC7100\` & \`D2GAME_NPC_GenerateStoreItem_6FCC6A60\`
- 商店物品等级公式:\`ilvl = max(1, min(99, cLvl + 5))\`,普通难度受 Act 1..5 幕数上限 \`[12, 20, 28, 36, 45]\` 钳制,噩梦/地狱难度无幕数上限。
- \`ilvl < 25\` 时滚动普通/劣质/超强底材;\`ilvl >= 25\` 时非固定库存 100% 升级为魔法品质 (\`ITEMQUAL_MAGIC\`) 且保底下限提升 (\`nMinItems = (rand & 1) + 2\`)。
- \`cLvl > 25\` 时在噩梦/地狱难度严格执行扩展级 (\`UberCode\`) / 精华级 (\`UltraCode\`) 升级骰子以及 \`NightmareUpgrade\` / \`HellUpgrade\` 药水替换。
3. **1.13c 交易价格与收购价格计算引擎 (\`Items.cpp\`)**:
- \`ITEMS_CalculateTransactionCost (0x6FD9B1C0)\` 及辅助函数 \`0x6FD9AB90\` / \`0x6FD9ACE0\` / \`0x6FD9CB50\`。
- 精确计算购买价 (\`BUY\`)、商人收购价 (\`SELL\`)、修理费 (\`REPAIR\`) 与赌博价 (\`GAMBLE\`):涵盖防御比例缩放、Staffmods 单技能高额加价(售价 \`/1024\` vs 收购价 \`/4096\`)、词缀与 \`ItemStatCost.txt\` 逐点属性加价、镶嵌物半价累加、无形/职业专属收购价 \`/4\` 惩罚、\`Npc.txt\` 汇率与任务折扣、各难度最高收购上限(普通 \`5k/10k/15k/20k/25k\`、噩梦 \`30k\`、地狱 \`35k\`)及减价属性 (\`STAT_ITEM_REDUCEDPRICES\`)。
4. **城镇 NPC 交互菜单与四分页商店 UI**:
- 原版风格 NPC 交互菜单(交谈 / 交易 / 赌博 / 修理 / 鉴定),左侧 10×10 四分页商店面板(护甲 / 武器 I / 武器 II / 杂物)与右侧玩家背包联动交易。`
if (!milestone) {
milestone = await giteaFetch<MilestoneResp>('/milestones', 'POST', {
title: targetTitle,
description: milestoneDesc,
state: 'open',
})
console.log(`Created Milestone #${milestone.id}: ${milestone.title}`)
} else {
milestone = await giteaFetch<MilestoneResp>(`/milestones/${milestone.id}`, 'PATCH', {
title: targetTitle,
description: milestoneDesc,
state: 'open',
})
console.log(`Updated Milestone #${milestone.id}: ${milestone.title}`)
}
const issuesToCreate = [
{
key: 'P1',
title: '[M19-P1] 烘焙 1.13c 商人经济与库存权威数据表 (Npc.txt / Vendor Columns / Gamble.txt / Books.txt / Stat & Skill Costs)',
body: `## 背景与目标
为 1.13c 商人库存生成器与价格计算引擎提供零网络、100% 忠实于官方 MPQ 数据表的底层数据契约。
## 1.13c Ground Truth 对标 (\`ItemsTbls.cpp\` / \`MonsterTbls.cpp\`)
1. **17 位商人配置列 (\`Weapons.txt\` / \`Armor.txt\` / \`Misc.txt\`)**:
- 提取 \`nNpcId = 0..16\` 的 \`Min\`, \`Max\`, \`MagicMin\`, \`MagicMax\`, \`MagicLvl\`(注意 \`nNpcId = 6\` 赫拉铁力在原版表中的列名拼写为 \`HraltiMin\` / \`HraltiMax\` / \`HraltiMagicMin\` / \`HraltiMagicMax\` / \`HraltiMagicLvl\`)。
- 提取 \`PermStoreItem\`、\`multibuy\`、\`NightmareUpgrade\`、\`HellUpgrade\`、\`cost\`、\`gamble cost\`、\`bitfield1\`。
2. **\`Npc.txt\` 商人经济表 (\`src/game/npc-table.ts\`)**:
- 解析 \`npc\`, \`buy mult\`, \`sell mult\`, \`rep mult\`, \`questflag A/B/C\`, \`questbuymult A/B/C\`, \`questsellmult A/B/C\`, \`questrepmult A/B/C\`, \`max buy\`, \`max buy (N)\`, \`max buy (H)\`。
- 建立 \`MonsterId (hcIdx)\` $\\leftrightarrow$ \`VendorNpcId (0..16)\` 及 NPC 服务能力矩阵(Trade / Gamble / Repair / Heal / Identify)。
3. **\`ItemTypes.txt\` / \`ItemStatCost.txt\` / \`Skills.txt\` / \`Gamble.txt\` / \`Books.txt\` / \`LowQualityItems.txt\`**:
- \`ItemTypes.txt\`:解析 \`StorePage\` (\`armr\` / \`weap\` / \`misc\`)、\`StaffMods\` 与 \`Class\`(用于职业专属物品收购价 \`/4\` 折算)。
- \`ItemStatCost.txt\`:解析 \`ID\`, \`Stat\`, \`Encode\`, \`Multiply\`, \`Add\`, \`ValShift\`。
- \`Skills.txt\`:解析 \`Id\`, \`skill\`, \`charclass\`, \`cost mult\`, \`cost add\`。
- 烘焙 \`Gamble.txt\`(赌博底材代码池)与 \`Books.txt\`(回城/辨识书卷轴价格与充能成本)。
## 验收标准
- [ ] \`canonical-drop-data.ts\` 与 \`embedded-drop-tables.ts\` 零网络同步导出上述全部权威表结构。
- [ ] 单元测试验证全部 17 位商人的列解析(含 \`Hralti*\`)及 \`Npc.txt\` 三难度 \`max buy\` 上限(普通 \`5000~25000\`,噩梦 \`30000\`,地狱 \`35000\`)准确无误。`,
},
{
key: 'P2',
title: '[M19-P2] 实装 1.13c 商人库存生成引擎 (按商人 ID、游戏难度与角色等级生成出售物品)',
body: `## 背景与目标
严格按照 \`D2Game.dll\` 反编译源码实装商人库存生成引擎 (\`src/game/vendor-generator.ts\`),根据**商人 ID (\`nNpcId\`)**、**游戏难度 (\`Normal/Nightmare/Hell\`)** 与**角色等级 (\`cLvl\`)** 生成四分页出售物品。
## 1.13c Ground Truth 对标 (\`SUnitProxy.cpp\` & \`SUnitNpc.cpp\`)
1. **全局缓存构建 (\`SUNITPROXY_FillIGlobaltemCacheRecordForNpc\`)**:
- 按 \`Weapons.txt\` $\\rightarrow$ \`Armor.txt\` $\\rightarrow$ \`Misc.txt\` 顺序扫描 \`nSpawnable != 0\` 且 \`(nVendorMax > 0 || nVendorMagicMax > 0)\` 的物品。
- \`PermStoreItem != 0\` 归入 \`pPermCache\`;其余归入 \`pItemCache\`。
2. **商店物品等级 \`ilvl\` 计算 (\`D2GAME_NPC_FillStoreInventory_6FCC7100\`)**:
- \`nItemLevel = Math.max(1, Math.min(99, nPlayerLevel + 5))\`。
- 普通难度 (\`nDifficulty == 0\`) 按幕数 \`nAct = 0..4\` 强制上限 \`npcLevels[5] = [12, 20, 28, 36, 45]\`;噩梦与地狱难度无幕数上限。
3. **非固定商品生成 (\`pItemCache\`)**:
- 跳过 \`base.level > nItemLevel\` 的底材。
- **当且仅当 \`nItemLevel < 25\` 且 \`nMax > 0\` 时**生成普通/劣质/超强底材:
- \`nNormalItems = nMin + rand(nMax - nMin + 1)\`。
- 品质掷骰 \`rand(100)\`:\`ilvl < 5\` 时 \`> 90\` 为劣质 (\`ITEMQUAL_INFERIOR\`);\`5 <= ilvl < 10\` 时 \`> 85\` 为超强 (\`ITEMQUAL_SUPERIOR\`);\`10 <= ilvl < 25\` 时 \`>= 75\` 为超强;其余为普通白色 (\`ITEMQUAL_NORMAL\`)。
- **魔法商品生成 (\`nMagicMax > 0\` 且 \`bitfield1 & 1\`)**:
- \`nMinItems = (nItemLevel >= 25) ? ((rand(2)) + 2) : 1\`。
- \`nRange = nMinItems + nMagicMax - nMagicMin\`,生成 \`ITEMQUAL_MAGIC\` 并调用词缀生成器赋予前后缀(若词缀骰子未出词缀则自动重掷确保有效魔法词缀)与法杖/手杖/权杖 Staffmods。
4. **噩梦/地狱难度底材升级与药水替换 (\`D2GAME_NPC_GenerateStoreItem_6FCC6A60\`)**:
- 当 \`nPlayerLevel > 25\` 时:
- 噩梦难度:\`rand(100000) < (nItemLevel << 6) + 4000\` 升级为 \`UberCode\`(若 \`Uber.level <= nItemLevel\`),否则应用 \`NightmareUpgrade\`。
- 地狱难度:\`nRand = rand(100000)\`,资料片 \`< 16 * nItemLevel + 1000\` 升级为 \`UltraCode\`,否则 \`< (nItemLevel << 7) + 5000\` 升级为 \`UberCode\`;随后应用 \`HellUpgrade\`。
5. **常驻商品 (\`pPermCache\`) 与四分页 10×10 网格排布**:
- 常驻物品标记 \`bPermStore = true\`,箭袋 (\`aqv\`/\`cqv\`) 设为满数量 \`maxstack\`。
- 按 \`StorePage\` (\`armr -> Tab 0\`, \`weap -> Tab 1\` 溢出至 \`Tab 2\`, \`misc -> Tab 3\`) 自动进行 2D 网格碰撞排布。
## 验收标准
- [ ] 完整实现 \`src/game/vendor-generator.ts\`。
- [ ] 覆盖 Act 1~5 全部 17 位商人在普通/噩梦/地狱及不同等级下的库存生成单元测试。`,
},
{
key: 'P3',
title: '[M19-P3] 实装 1.13c 物品交易与收购价格计算引擎 (ITEMS_CalculateTransactionCost 0x6FD9B1C0)',
body: `## 背景与目标
100% 还原 \`D2Common.dll\` 中的 \`ITEMS_CalculateTransactionCost (0x6FD9B1C0)\` 及其 3 个子函数,精确计算任意物品的**商人售价 (玩家购买价 \`BUY\`)**、**商人收购价 (玩家出售价 \`SELL\`)**、**铁匠修理费 (\`REPAIR\`)** 与**赌博价 (\`GAMBLE\`)**。
## 1.13c Ground Truth 对标 (\`Items.cpp:1709-2495\`)
1. **特殊物品短路与基础成本 (\`BaseCost\`)**:
- 初始装备 (\`IFLAG_STARTITEM\`) 恒返回 \`1\` 金币。
- 防具按当前防御值比例缩放:\`nAC * dwCost / dwMaxAc\`。
- 箭袋按堆叠缩放:\`qty * dwCost / 1024\`;书册 (\`Books.txt\`) 按书页数量累加:\`BaseCost + qty * CostPerCharge\`。
- 初始累加器:\`nSellCost = BaseCost\`, \`nBuyCost = Math.trunc(BaseCost / 2)\`, \`nRepCost = BaseCost\`。
2. **Staffmods 单技能高额加价 (\`ITEMS_CalculateAdditionalCostsForItemSkill 0x6FD9CB50\`)**:
- 对非全职业固定技能底材 (\`ItemTypes.StaffMods != 7\`),遍历物品上的单技能 (\`STAT_ITEM_SINGLESKILL\`):
- \`nSellCost\` / \`nRepCost\` 增加 \`(2 * slvl - 1) * (SkillCostAdd + Math.trunc(BaseCost * SkillCostMult / 1024))\`。
- \`nBuyCost\`(收购价)增加 \`(2 * slvl - 1) * (SkillCostAdd + Math.trunc(BaseCost * SkillCostMult / 4096))\`(严格 1/4 比例)。
3. **品质、词缀与属性逐点加价 (\`IFLAG_IDENTIFIED\`)**:
- **Magic / Rare / Crafted**:累加前后缀 \`dwAdd + BaseCost * dwMultiply / 1024\`(收购价 \`/2048\`)并调用 \`ITEMS_CalculateAdditionalCostsForBonusStats (0x6FD9ACE0)\` 按 \`ItemStatCost.txt\` 的 \`Multiply\` 与 \`Add\` 逐点累加(若出现负向词缀导致低于 \`BaseCost\`,严格触发保底回退 \`nSellCost = BaseCost, nBuyCost = BaseCost / 2\`)。
- **Unique / Set**:按 \`UniqueItems.txt\` / \`SetItems.txt\` 的 \`cost mult\` 与 \`cost add\` 加成并累加属性成本。
- **Superior**:累加超强属性加成;**Inferior**:扣减 \`BaseCost / 2\`。
4. **镶嵌物、无形与职业专属惩罚**:
- 遍历孔内已镶嵌物品,三者均加上 \`Math.trunc(Filler.dwCost / 2)\`。
- **无形惩罚 (\`IFLAG_ETHEREAL\`)**:收购价 \`nBuyCost = Math.trunc(nBuyCost / 4)\`(破损无形归 0)。
- **职业专属物品惩罚 (\`ItemTypes.Class < 7\`)**:收购价 \`nBuyCost = Math.trunc(nBuyCost / 4)\`。
5. **\`Npc.txt\` 汇率、任务折扣、难度最高收购上限 (\`max buy\`) 与减价属性**:
- 应用 \`Npc.txt\` 的 \`sell mult\` / \`buy mult\` / \`rep mult\` (\`/ 1024\`) 及已完成任务的 \`quest*mult\` (\`/ 1024\`)。
- **难度收购封顶**:当 \`transactionType === 'sell'\` 时,\`nBuyCost = Math.min(nBuyCost, NpcTxt.maxBuy[difficulty])\`(普通 Act 1..5 为 \`5000 / 10000 / 15000 / 20000 / 25000\`,噩梦 \`30000\`,地狱 \`35000\`)。
- **减价属性 (\`STAT_ITEM_REDUCEDPRICES\`)**:仅对 \`BUY\`、\`REPAIR\`、\`GAMBLE\` 生效(不对 \`SELL\` 生效)。
## 验收标准
- [ ] 完整实现 \`src/game/item-cost.ts\`。
- [ ] 全面的单元测试覆盖全部品质、Staffmods、无形/职业专属惩罚、任务折扣与三难度收购上限。`,
},
{
key: 'P4',
title: '[M19-P4] 实装 1.13c 城镇 NPC 交互系统与服务逻辑 (交谈 / 交易 / 赌博 / 治疗 / 修理 / 凯恩鉴定)',
body: `## 背景与目标
基于 \`SUnitNpc.cpp\` 实装全 5 幕城镇 NPC 的完整服务会话与业务逻辑 (\`src/game/vendor-service.ts\`)。
## 1.13c Ground Truth 对标 (\`SUnitNpc.cpp\`)
1. **购买与批量购买 (\`sub_6FCC88B0\`)**:
- 校验玩家金币与背包空间;扣除金币。
- 常驻物品 (\`bPermStore = true\`) 购买后克隆新实例放入玩家背包/腰带,原商店格物品保留;非常驻物品购买后从商店网格移除。
- **Shift + 右键批量购买 (\`bShiftBuy\`)**:
- 药水:自动买满玩家腰带对应列空槽。
- 回城卷轴 (\`tsc\`) / 辨识卷轴 (\`isc\`):自动补满玩家背包中的回城之书 (\`tbk\`) / 辨识之书 (\`ibk\`) 至 20 张上限。
- 钥匙 (\`key\`):自动补满当前钥匙堆叠至 12 把上限。
2. **出售与商店回购 (\`D2GAME_STORES_SellItem_6FCC7680\`)**:
- 禁止出售任务物品或不可出售物品(如赫拉迪克方块等)。
- 计算收购价并增加玩家金币(遵守角色背包金币携带上限 \`getInventoryGoldLimit(cLvl)\`)。
- 若该物品在商店对应分页 (10×10) 有空位且非消耗杂物,放入商店对应分页供玩家原价买回。
3. **铁匠修理 (\`D2GAME_NPC_Repair_6FCC95B0\`)**:
- 支持单件修理与“全身装备一键修理”(修复已穿戴装备的耐久度与聚气技能充能,跳过无形装备)。
4. **医疗与凯恩鉴定 (\`D2GAME_NPC_Heal_6FCCB220\` & \`D2GAME_NPC_IdentifyAllItems_6FCC9C90\`)**:
- 与阿卡拉、法拉、奥玛斯、贾梅拉、马拉交谈时自动回满生命、法力、体力并清除中毒/冰冻/诅咒状态。
- 凯恩支持一键鉴定玩家背包中所有未鉴定物品。
5. **赌博系统 (\`D2GAME_STORES_FillGamble_6FCCA9F0\`)**:
- 基德、艾尔吉斯、阿尔科、贾梅拉、安亚/尼拉塞克支持赌博面板,购买前显示未鉴定基底与一口价赌博费,购买入包瞬间按 1.13c 概率揭晓品质(Magic 89.85%、Rare 10%、Set 0.1%、Unique 0.05%)与扩展/精华底材升级。
## 验收标准
- [ ] 实现 \`src/game/vendor-service.ts\` 并通过全部交易事务单元测试。`,
},
{
key: 'P5',
title: '[M19-P5] 实装原版四分页商人面板 UI 与买卖交互 (Panel\\NPCInv.dc6 + Buy/Sell/Repair/Gamble)',
body: `## 背景与目标
打通城镇 NPC 点击菜单、左侧四分页商店面板 (\`Panel\\NPCInv.dc6\`)、右侧玩家背包联动与悬浮价格 Tooltip。
## 核心实装内容
1. **城镇 NPC 交互弹窗菜单 (\`src/scene/act-scene.ts\` & \`src/ui/world-panels.ts\`)**:
- 当玩家走近并点击城镇 NPC 时,除了触发治疗与头顶/面板问候外,弹出原版暗黑风格选项菜单:
- 交易型 NPC:\`交谈\` / \`交易\` (或 \`交易/修理\`) / \`赌博\` (若支持) / \`取消\`
- 凯恩:\`交谈\` / \`鉴定物品\` / \`取消\`
2. **左侧四分页商店面板 (\`src/ui/world-panels.ts\`)**:
- 替换 \`drawLeftDockPanel\` 中的 \`'vendor'\` 占位符,使用 \`vendor-bg.png\` 与 \`buysellbtn.png\` 渲染:
- 顶部 4 个分页标签:\`护甲\` / \`武器 I\` / \`武器 II\` / \`杂物\`。
- 中部 10×10 物品网格(每格 29×29 px),绘制商店物品图标、染色、堆叠角标、鼠标悬停高亮。
- 底部功能按钮栏:购买/出售、单件修理锤、全身修理(显示总修理费)、赌博刷新按钮(赌博模式)与关闭按钮。
3. **左右双栏联动与 Tooltip 价格展示 (\`src/ui/hud-manager.ts\` & \`src/ui/inventory.ts\`)**:
- 打开左侧 \`vendor\` 面板时自动打开右侧玩家背包 (\`rightOpen.inventory = true\`)。
- 悬停商店物品时:Tooltip 显示原版属性 + **\`购买价格: X 金币\`**(金币不足时标红)。
- 悬停玩家背包/装备物品时:Tooltip 显示 **\`出售价格: X 金币\`**(修理光标激活时显示 **\`修理费用: X 金币\`**)。
- 支持右键快捷购买/出售、Shift+右键批量买满药水/卷轴、左键拖拽买卖。
## 验收标准
- [ ] 左侧商店面板与右侧背包面板严丝合缝并排显示,所有买卖/修理/赌博操作流畅闭环。`,
},
{
key: 'P6',
title: '[M19-P6] 全量 17 商人 × 3 难度差分测试与浏览器 E2E 闭环审计',
body: `## 背景与目标
对 M19 商人 NPC 与交易经济系统进行全谱系自动化验证与浏览器 E2E 闭环审计。
## 核心验证项
1. **17 商人 × 3 难度 × 多角色等级自动化差分审计**:
- 验证 Act 1~5 共 17 位商人 ID 在 \`Normal / Nightmare / Hell\` 与 \`cLvl = 1, 12, 20, 25, 30, 60, 90\` 下的库存生成合法性(无越界等级物品、\`ilvl >= 25\` 零白装、常驻药水/卷轴/箭袋齐全)。
- 验证各类物品(普通、超强、劣质、魔法、亮金、暗金、套装、带 +3 技能 Staffmods 手杖/法杖、无形、职业专属)的售价与收购价严格符合 \`0x6FD9B1C0\` 公式及 \`Npc.txt\` 难度封顶。
2. **Playwright 浏览器端到端验证**:
- 启动本地开发服并在无头浏览器中实测点击城镇商人 NPC、打开交互菜单、切换四分页商店、购买药水/装备、出售背包物品、铁匠修理及凯恩鉴定全流程,确保 Console / PageError 为 0。
## 验收标准
- [ ] 新增单元测试与 E2E 验证全部 100% 绿灯通过。`,
},
]
const existingIssues = await giteaFetch<IssueResp[]>(`/issues?state=all&milestones=${milestone.id}&limit=50`)
const createdUrls: string[] = []
for (const item of issuesToCreate) {
const found = existingIssues.find(
i => i.title === item.title || i.title.includes(`-${item.key}]`),
)
if (found) {
const updated = await giteaFetch<IssueResp>(`/issues/${found.number}`, 'PATCH', {
title: item.title,
body: item.body,
})
console.log(`Updated Issue #${updated.number}: ${updated.title} -> ${updated.html_url}`)
createdUrls.push(`#${updated.number} ${updated.title}: ${updated.html_url}`)
continue
}
const created = await giteaFetch<IssueResp>('/issues', 'POST', {
title: item.title,
body: item.body,
milestone: milestone.id,
})
console.log(`Created Issue #${created.number}: ${created.title} -> ${created.html_url}`)
createdUrls.push(`#${created.number} ${created.title}: ${created.html_url}`)
}
console.log('\n=== SUMMARY ===')
console.log(`Milestone #${milestone.id}: ${milestone.title} (https://git.projectdiablo2.cn/troytt/diablo2-web/milestone/${milestone.id})`)
for (const line of createdUrls) {
console.log(`- ${line}`)
}
}
main().catch(err => {
console.error(err)
process.exit(1)
})