fix(scripts): read a skins PR in both skin directory layouts

Skin contributions moved to the dsh-skins repository, where a skin lives at
`skins/<id>/`, but `pr-review.mjs` still matched only the pre-split
`packages/skins/skin-center/skins/<id>/`. `--repo` can point at either
repository, so the change detection and the preview check now accept both
layouts; a dsh-skins PR gets the copyright and preview reminders again.

Verified: pr-review.test.mjs covers the satellite layout for both checks.
This commit is contained in:
EDDYCRAZY-CC
2026-09-24 09:27:15 +08:00
parent 196fe4320d
commit fd504852ea
2 changed files with 24 additions and 7 deletions
+9 -5
View File
@@ -306,14 +306,18 @@ export function checkLockfile(changes) {
}))
}
/** 皮肤变更识别:返回 { isSkin, skinIds }。仅源码类变更触发(README/preview/文档不算)。
v2 布局(issue #506):皮肤事实源是 skin-center 包内的资产目录。 */
/** 皮肤目录前缀:dsh-skins 卫星仓是 skins/<id>/,本仓拆分前是
packages/skins/skin-center/skins/<id>/;--repo 可指向两者,故两种布局都认。 */
const SKIN_DIR_PREFIXES = ['skins/', 'packages/skins/skin-center/skins/']
const SKIN_DIR_RE = new RegExp(`^(?:${SKIN_DIR_PREFIXES.join('|')})([^/]+)/`)
/** 皮肤变更识别:返回 { isSkin, skinIds }。仅源码类变更触发(README/preview/文档不算)。 */
export function checkSkinChanges(changes) {
const ids = new Set()
const SKIP_RE = /(README(\.zh)?\.md|README\.i18n\.yaml|preview\/|^docs\/)/i
for (const c of changes) {
if (SKIP_RE.test(c.path)) continue
const m = c.path.match(/^packages\/skins\/skin-center\/skins\/([^/]+)\//)
const m = c.path.match(SKIN_DIR_RE)
if (m) ids.add(m[1])
}
return { isSkin: ids.size > 0, skinIds: [...ids] }
@@ -337,11 +341,11 @@ export function checkSkinPreviews(changes, skinIds) {
const findings = []
for (const id of skinIds) {
const isNew = changes.some((c) => c.status === `A` &&
c.path.startsWith(`packages/skins/skin-center/skins/` + id + `/`))
SKIN_DIR_PREFIXES.some((prefix) => c.path.startsWith(prefix + id + `/`)))
if (!isNew) continue
for (const mode of [`light`, `dark`]) {
const hasPreview = changes.some((c) =>
c.path === `packages/skins/skin-center/skins/` + id + `/preview/` + mode + `.jpg`)
SKIN_DIR_PREFIXES.some((prefix) => c.path === prefix + id + `/preview/` + mode + `.jpg`))
if (!hasPreview) {
findings.push({ severity: `warn`, rule: `preview`, message: `新皮肤 ` + id + ` 未提供 ` + mode + ` 预览图:请运行 node scripts/capture-previews ` + id + ` 并提交 preview/` + mode + `.jpg` })
}
+15 -2
View File
@@ -357,7 +357,7 @@ test(`提交信息检查`, () => {
// ---------------------------------------------------------------- 皮肤识别与版权
test(`皮肤变更识别:源码类命中,README 与 skin-center 排除`, () => {
test(`皮肤变更识别:源码类命中,README 与 skin-center 排除,卫星仓 skins/<id>/ 同样命中`, () => {
const f1 = checkSkinChanges([
{ status: `A`, path: `packages/skins/skin-center/skins/xp/skin.css` },
{ status: `A`, path: `packages/skins/skin-center/skins/xp/skin.json` },
@@ -371,6 +371,11 @@ test(`皮肤变更识别:源码类命中,README 与 skin-center 排除`, ()
assert.deepEqual(f2, { isSkin: false, skinIds: [] })
const f3 = checkSkinChanges([{ status: `M`, path: `packages/skins/skin-center/src/routes.ts` }])
assert.equal(f3.isSkin, false)
const f4 = checkSkinChanges([
{ status: `A`, path: `skins/xp/skin.css` },
{ status: `M`, path: `skins/xp/preview/light.jpg` },
])
assert.deepEqual(f4, { isSkin: true, skinIds: [`xp`] })
})
test(`版权提醒:外部贡献者皮肤 PR 未声明时 warn,已声明或仓库所有者豁免`, () => {
@@ -384,7 +389,7 @@ test(`版权提醒:外部贡献者皮肤 PR 未声明时 warn,已声明或
assert.equal(checkCopyright(pr, false, `owner`).length, 0)
assert.equal(checkCopyright(pr, true, `someone`).length, 0)
})
test(`市场预览:新皮肤缺 preview/{light,dark}.jpg 时警告,齐图或存量皮肤豁免`, () => {
test(`市场预览:新皮肤缺 preview/{light,dark}.jpg 时警告,齐图、卫星仓布局或存量皮肤豁免`, () => {
const base = [
{ status: `A`, path: `packages/skins/skin-center/skins/xp/skin.css` },
]
@@ -399,6 +404,14 @@ test(`市场预览:新皮肤缺 preview/{light,dark}.jpg 时警告,齐图或
assert.equal(checkSkinPreviews(complete, [`xp`]).length, 0)
const modified = [{ status: `M`, path: `packages/skins/skin-center/skins/xp/skin.css` }]
assert.equal(checkSkinPreviews(modified, [`xp`]).length, 0)
const satellite = [{ status: `A`, path: `skins/xp/skin.css` }]
assert.equal(checkSkinPreviews(satellite, [`xp`]).length, 2)
const satelliteComplete = [
{ status: `A`, path: `skins/xp/skin.css` },
{ status: `A`, path: `skins/xp/preview/light.jpg` },
{ status: `A`, path: `skins/xp/preview/dark.jpg` },
]
assert.equal(checkSkinPreviews(satelliteComplete, [`xp`]).length, 0)
})
test(`视觉指标判定:过曝与对比度不足警告`, () => {
const f1 = judgeVisualMetrics([