✨ feat(vscode): 工单状态评论改写成隐藏格式,Gitea 和 YouTrack 共用一套读写
This commit is contained in:
1 parent
fa7b32d205
commit
38ca193434
17 files changed
+588
-660
No files matched your search
@@ -0,0 +1,91 @@
|
||||
import type { Issue, IssueColumn } from '../gitea/types'
|
||||
|
||||
const COLUMNS: readonly IssueColumn[] = ['todo', 'in-progress', 'review', 'done']
|
||||
|
||||
/** 非空字符串才算有值:状态里写空串表示把字段清掉。 */
|
||||
const STRING_FIELDS = [
|
||||
'sessionId',
|
||||
'implementSessionId',
|
||||
'reviewSessionId',
|
||||
'testSessionId',
|
||||
'prototypeSessionId',
|
||||
'profilePath',
|
||||
'brainstormProfilePath',
|
||||
'testProfilePath',
|
||||
'prototypeProfilePath',
|
||||
'pr',
|
||||
'prMergedAt',
|
||||
'branch',
|
||||
'worktreePath',
|
||||
'color',
|
||||
'handoffBundleKey',
|
||||
'handoffFrom',
|
||||
'handoffRequestFrom',
|
||||
'handoffRequestError',
|
||||
] as const
|
||||
|
||||
const BOOLEAN_FIELDS = ['prMerged', 'autoReview', 'reviewPassed'] as const
|
||||
|
||||
/** 状态里能直接放到卡片上的字段;读不出合法值的字段不出现。 */
|
||||
export type IssueStateFields = Partial<Pick<Issue, CardStateField>>
|
||||
|
||||
type CardStateField = 'column' | 'specFile' | 'planFile' | 'prototypeFile' | 'prDiffFile' | 'implementStatus' | typeof STRING_FIELDS[number] | typeof BOOLEAN_FIELDS[number]
|
||||
|
||||
/**
|
||||
* 过滤 specFile / planFile 里的垃圾值:真实路径必须含 `/` 且以 `.md` 结尾。
|
||||
*
|
||||
* `...`、`…` 是 cc 在头脑风暴阶段往工单正文里写的占位说明,旧版 webhook 曾把它们当路径存进状态,读出时在这里清掉。
|
||||
*/
|
||||
export function isValidSpxFilePath(v: unknown): v is string {
|
||||
return typeof v === 'string'
|
||||
&& v.length > 0
|
||||
&& v.includes('/')
|
||||
&& v.endsWith('.md')
|
||||
&& v !== '...'
|
||||
&& v !== '…'
|
||||
}
|
||||
|
||||
/** prototypeFile 指向 Figma 插件的 manifest.json,规则同 [isValidSpxFilePath],只是后缀换成 `.json`。 */
|
||||
function isValidPrototypeFilePath(v: unknown): v is string {
|
||||
return typeof v === 'string'
|
||||
&& v.length > 0
|
||||
&& v.includes('/')
|
||||
&& v.endsWith('.json')
|
||||
&& v !== '...'
|
||||
&& v !== '…'
|
||||
}
|
||||
|
||||
function isValidPrDiffFilePath(v: unknown): v is string {
|
||||
return typeof v === 'string' && /^docs\/pr-diff\/\S+\.md$/.test(v)
|
||||
}
|
||||
|
||||
function isIssueColumn(v: unknown): v is IssueColumn {
|
||||
return typeof v === 'string' && (COLUMNS as readonly string[]).includes(v)
|
||||
}
|
||||
|
||||
/** 把一份工单状态翻成卡片字段,只留合法的值,代码托管仓库和 YouTrack 的卡片都按它读。 */
|
||||
export function issueStateFields(state: Record<string, unknown>): IssueStateFields {
|
||||
const out: Record<string, unknown> = {}
|
||||
if (isIssueColumn(state.column))
|
||||
out.column = state.column
|
||||
for (const field of STRING_FIELDS) {
|
||||
const v = state[field]
|
||||
if (typeof v === 'string' && v.length > 0)
|
||||
out[field] = v
|
||||
}
|
||||
for (const field of BOOLEAN_FIELDS) {
|
||||
if (typeof state[field] === 'boolean')
|
||||
out[field] = state[field]
|
||||
}
|
||||
if (isValidSpxFilePath(state.specFile))
|
||||
out.specFile = state.specFile
|
||||
if (isValidSpxFilePath(state.planFile))
|
||||
out.planFile = state.planFile
|
||||
if (isValidPrototypeFilePath(state.prototypeFile))
|
||||
out.prototypeFile = state.prototypeFile
|
||||
if (isValidPrDiffFilePath(state.prDiffFile))
|
||||
out.prDiffFile = state.prDiffFile
|
||||
if (state.implementStatus === 'running' || state.implementStatus === 'done' || state.implementStatus === 'failed')
|
||||
out.implementStatus = state.implementStatus
|
||||
return out as IssueStateFields
|
||||
}
|
||||
Reference in new issue
Block a user