Files
ArtPlayer/refactor/scripts/rollback-inventory.mjs
T

79 lines
6.0 KiB
JavaScript
Raw 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.
import assert from 'node:assert/strict'
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { ensureArchive, readMember } from './releases.mjs'
const root = fileURLToPath(new URL('../../', import.meta.url))
assert(['--write', '--check'].includes(process.argv[2]) && process.argv.length === 3, 'Use --write or --check')
const read = file => JSON.parse(fs.readFileSync(path.join(root, file), 'utf8'))
const ledger = read('refactor/release-ledger.json')
const rows = []
for (const pkg of ledger.packages) {
const baseline = read(pkg.history.file)
const release = pkg.history.selector?.split('.').reduce((value, key) => value?.[key], baseline)
const current = read(`packages/${pkg.name}/package.json`)
const row = { name: pkg.name, targetVersion: pkg.targetVersion, distribution: pkg.distribution, history: pkg.history, currentDependencies: current.dependencies || {}, currentPeers: current.peerDependencies || {}, currentOptionalDependencies: current.optionalDependencies || {} }
if (pkg.distribution === 'site') {
const recovery = read('refactor/baselines/pages-recovery-validation.json')
assert.equal(recovery.localRestorationPassed, true)
assert.equal(recovery.remoteRestorationVerified, false)
rows.push({ ...row, restore: 'Preserve the canonical old Pages ZIP and its Git-blob report; local recovery verified, remote deployment restoration still requires its own gate. npm rollback does not apply.', status: 'local-restore-verified-remote-gate-open', evidence: 'refactor/baselines/pages-recovery-validation.json', localRecovery: { commit: recovery.archive.commit, archiveSha256: recovery.archive.sha256, files: recovery.files.count } })
continue
}
if (pkg.distribution === 'recovered-npm') {
assert(release, 'Missing recovered history')
rows.push({ ...row, restore: 'No intact historical npm tarball. Preserve a complete pre-upgrade application/artifact snapshot and verify it before any candidate deployment.', status: 'complete-rollback-artifact-required', evidence: pkg.history.file })
continue
}
assert(release?.integrity && release.sha256 && release.files, `Missing frozen rollback archive: ${pkg.name}`)
const archive = await ensureArchive(release)
const manifest = JSON.parse(readMember(archive, 'package/package.json'))
assert.equal(manifest.name, release.name)
assert.equal(manifest.version, release.version)
rows.push({
...row,
previous: { name: release.name, version: release.version, tarball: release.tarball, integrity: release.integrity, sha256: release.sha256, memberCount: Object.keys(release.files).length, dependencies: manifest.dependencies || {}, peerDependencies: manifest.peerDependencies || {}, optionalDependencies: manifest.optionalDependencies || {} },
exactDependency: { [release.name]: release.version },
restore: pkg.distribution === 'renamed-npm'
? 'Restore application import code, old package name and saved lock together; npm alias alone does not restore the old export/helper surface.'
: 'Restore the saved application manifest/lock and matching artifacts, then frozen-install the previous exact version with its tested core/plugin combination.',
status: 'archive-verified-batch-rehearsal-required',
})
}
assert.equal(rows.length, 22)
const result = { task: 'REL-04', source: 'refactor/release-ledger.json and frozen historical archives', registryAvailabilityRefreshed: false, mutableTagPolicy: 'Use exact versions and saved lock/artifact hashes. No latest/next/rollback tag is assumed or changed.', packages: rows }
const json = `${JSON.stringify(result, null, 2)}\n`
const dependencies = value => Object.entries(value).map(([name, version]) => `${name}@${version}`).join(', ') || '无声明'
const lines = [
'# 逐包回退清单',
'',
'由 `node refactor/scripts/rollback-inventory.mjs --write` 生成;`--check` 校验同步并复核冻结 tarball 完整性。',
'',
'本表核对 20 份完整历史 archive 的 SHA-512/SHA-256 和 manifest。它不表示当前 registry 可用,',
'也不表示全部包的实际回退已验收。机器清单同时保存旧/新 dependencies、peerDependencies 与精确 integrity。',
'',
'| 当前包 | 目标版本 | 恢复版本/对象 | 旧包运行依赖 | 恢复状态 |',
'| --- | --- | --- | --- | --- |',
...rows.map(row => `| ${row.name} | ${row.targetVersion} | ${row.previous ? `${row.previous.name}@${row.previous.version}` : row.distribution === 'site' ? '已验证 Pages 产物' : '完整旧产物尚缺'} | ${row.previous ? dependencies(row.previous.dependencies) : '见原有门槛'} | ${row.status} |`),
'',
'每包优先恢复升级前已验证的应用代码、package.json 和 yarn.lock,再执行 `yarn install --frozen-lockfile`;',
'离线恢复还需保存所需 tarball/依赖缓存。单独把版本改回去并重新解析依赖,不能替代已测试锁文件。',
'外部播放器 SDK、worker/WASM、远端媒体和平台能力也要恢复对应配置,npm 依赖表不覆盖它们。',
'',
'iframe 必须同步恢复旧包名、CommonJS `.default`、helper 路径和应用代码;不将 npm alias 当作兼容门面。',
'Thumbnail 完整原包缺失以及站点部署恢复仍是发布门槛。正式每批重新绑定候选和回退内容,不能直接复用早期演练结果。',
'',
'来源:[机器清单](baselines/rollback-inventory.json)、[维护入口](rollback-rehearsal.md)、[发布台账](release-ledger.md)。',
'',
]
const markdown = lines.join('\n')
for (const [file, contents] of [['refactor/baselines/rollback-inventory.json', json], ['refactor/rollback-inventory.md', markdown]]) {
if (process.argv[2] === '--write')
fs.writeFileSync(path.join(root, file), contents)
else
assert.equal(fs.readFileSync(path.join(root, file), 'utf8').replaceAll('\r\n', '\n'), contents, `Stale rollback inventory: ${file}`)
}
console.log(`Rollback inventory: ${rows.length} packages, ${rows.filter(row => row.previous).length} verified historical archives, remaining batch gates retained`)