🐛 fix(vscode): 看板实时响应工单指派事件
Gitea 的 issue_assign 事件 X-Gitea-Event 值为 issues、action 为 assigned/unassigned,coordinator 此前只处理 opened/reopened/edited, 指派事件被丢弃。现复用 decideIssueAppend 门禁:指派给我 → issue/append 实时上卡(已在板上则原位刷新),与我无关 → issue/remove 撤卡。
This commit is contained in:
@@ -409,6 +409,11 @@ class WebhookCoordinator {
|
|||||||
else if (event.action === 'edited') {
|
else if (event.action === 'edited') {
|
||||||
await this.handleIssueEdited(event)
|
await this.handleIssueEdited(event)
|
||||||
}
|
}
|
||||||
|
else if (event.action === 'assigned' || event.action === 'unassigned') {
|
||||||
|
// Gitea 的 issue_assign 事件 X-Gitea-Event 也是 'issues',靠
|
||||||
|
// action 区分,不会走到独立的事件分支。
|
||||||
|
await this.handleIssueAssigned(event)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
logger.add({
|
logger.add({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
@@ -671,6 +676,95 @@ class WebhookCoordinator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* issue assigned/unassigned:指派关系变化后,受影响机器的 'mine' 看板
|
||||||
|
* 要实时上卡/撤卡,不能等下次手动刷新。
|
||||||
|
*/
|
||||||
|
private async handleIssueAssigned(event: IssueWebhookEvent): Promise<void> {
|
||||||
|
if (!this.ctx)
|
||||||
|
return
|
||||||
|
// 没面板就没什么可更新,下次打开看板的批量加载会兜底。
|
||||||
|
if (!this.activePanel)
|
||||||
|
return
|
||||||
|
|
||||||
|
const ws = workspace.workspaceFolders?.[0]?.uri.fsPath
|
||||||
|
if (!ws) {
|
||||||
|
logger.add({
|
||||||
|
level: 'warn',
|
||||||
|
source: 'webhook',
|
||||||
|
message: 'issue assigned 事件忽略:未打开工作区',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const remote = await detectRepo(ws)
|
||||||
|
if (!remote) {
|
||||||
|
logger.add({
|
||||||
|
level: 'warn',
|
||||||
|
source: 'webhook',
|
||||||
|
message: 'issue assigned 事件忽略:工作区未关联 gitea',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const token = await getToken(this.ctx, remote.host)
|
||||||
|
if (!token) {
|
||||||
|
logger.add({
|
||||||
|
level: 'warn',
|
||||||
|
source: 'webhook',
|
||||||
|
message: 'issue assigned 事件忽略:未配置 token',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 与 handleIssueOpened 同一套 'mine' 可见性门禁:指派给我 → 上卡,
|
||||||
|
// 与我无关(含被取消指派)→ 撤卡。身份/payload 只在 'mine' 时解析,
|
||||||
|
// 省一次身份请求。
|
||||||
|
const scope = this.ctx.workspaceState.get<KanbanScope>(KANBAN_SCOPE_KEY) ?? 'mine'
|
||||||
|
let poster: string | undefined
|
||||||
|
let assignees: string[] = []
|
||||||
|
let me: string | undefined
|
||||||
|
if (scope === 'mine') {
|
||||||
|
const raw = event.raw as { issue?: { user?: { login?: string } | null, assignees?: Array<{ login?: string } | null> | null } | null } | null
|
||||||
|
poster = raw?.issue?.user?.login
|
||||||
|
assignees = (raw?.issue?.assignees ?? []).flatMap(a => (a?.login ? [a.login] : []))
|
||||||
|
me = await loginForToken(remote.host, token)
|
||||||
|
}
|
||||||
|
if (!decideIssueAppend({ scope, pendingCreatedLocally: false, poster, assignees, me })) {
|
||||||
|
logger.add({
|
||||||
|
level: 'info',
|
||||||
|
source: 'webhook',
|
||||||
|
message: `issue #${event.issueNumber} ${event.action === 'unassigned' ? '取消指派' : '指派'}后与我无关,scope=mine 撤卡`,
|
||||||
|
details: `poster=${poster ?? '<未知>'} assignees=[${assignees.join(',')}] me=${me ?? '<未知>'}`,
|
||||||
|
})
|
||||||
|
// 卡本来不在板上时前端 remove 是无害 no-op。
|
||||||
|
this.activePanel.postMessage({ type: 'issue/remove', issueNumber: event.issueNumber })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const loaded = await loadSingleIssue({
|
||||||
|
host: remote.host,
|
||||||
|
owner: remote.owner,
|
||||||
|
repo: remote.repo,
|
||||||
|
token,
|
||||||
|
workspaceRoot: ws,
|
||||||
|
issueNumber: event.issueNumber,
|
||||||
|
})
|
||||||
|
const issue = loaded ? (await annotateReviewSessionFileExists(overlayLocalIssueState(this.ctx, [loaded], ws)))[0] : null
|
||||||
|
// 前端对 issue/append 按 number 去重原位替换:已在板上的卡刷新
|
||||||
|
// assignee,不在板上的新增——指派给我的工单借此实时上卡。
|
||||||
|
if (issue)
|
||||||
|
this.activePanel.postMessage({ type: 'issue/append', issue })
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : String(err)
|
||||||
|
logger.add({
|
||||||
|
level: 'warn',
|
||||||
|
source: 'webhook',
|
||||||
|
message: 'loadSingleIssue 失败(issue assigned)',
|
||||||
|
details: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Issue `edited` payload: cc updates the issue body with `<!-- spx:spec=... -->`
|
* Issue `edited` payload: cc updates the issue body with `<!-- spx:spec=... -->`
|
||||||
* / `<!-- spx:plan=... -->` annotation lines as it discovers spec/plan files.
|
* / `<!-- spx:plan=... -->` annotation lines as it discovers spec/plan files.
|
||||||
|
|||||||
Reference in New Issue
Block a user