chore: initialize qiming workspace repository
This commit is contained in:
165
qimingcode/packages/opencode/script/check-version-consistency.ts
Normal file
165
qimingcode/packages/opencode/script/check-version-consistency.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env bun
|
||||
/**
|
||||
* 版本一致性校验脚本(发布前 + 发布后)。
|
||||
*
|
||||
* 设计目标:
|
||||
* 1) 统一“版本真相来源”为 packages/opencode/package.json 的 version;
|
||||
* 2) 发布前阻断所有“本地版本不一致”;
|
||||
* 3) 发布后阻断所有“registry/安装态版本不一致”。
|
||||
*
|
||||
* 用法:
|
||||
* bun run script/check-version-consistency.ts --phase pre --version 1.1.93
|
||||
* bun run script/check-version-consistency.ts --phase post --version 1.1.93
|
||||
*/
|
||||
import { $ } from "bun"
|
||||
import pkg from "../package.json"
|
||||
|
||||
type Phase = "pre" | "post"
|
||||
|
||||
function parseArg(flag: string): string | undefined {
|
||||
const index = process.argv.indexOf(flag)
|
||||
if (index === -1) return undefined
|
||||
return process.argv[index + 1]
|
||||
}
|
||||
|
||||
const phase = (parseArg("--phase") ?? "pre") as Phase
|
||||
const targetVersion = parseArg("--version") ?? pkg.version
|
||||
|
||||
if (!["pre", "post"].includes(phase)) {
|
||||
console.error(`不支持的 --phase: ${phase},可选值仅为 pre | post`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
async function ensureOptionalDependenciesConsistent(version: string) {
|
||||
// package.json schema 推断类型里未必包含 optionalDependencies;运行时在 release.sh 中会写入同步。
|
||||
const optional =
|
||||
(pkg as typeof pkg & { optionalDependencies?: Record<string, string> }).optionalDependencies ?? {}
|
||||
const entries = Object.entries(optional).filter(([name]) => name.startsWith("qimingcode-"))
|
||||
|
||||
if (entries.length === 0) {
|
||||
// 当前仓库里 optionalDependencies 由 publish.ts 在 dist 聚合包里动态生成。
|
||||
// 因此源码 package.json 允许没有该字段,不应阻断发布。
|
||||
console.warn("package.json 未定义 qimingcode-* optionalDependencies,跳过源码 optional 一致性校验。")
|
||||
return
|
||||
}
|
||||
|
||||
for (const [name, depVersion] of entries) {
|
||||
if (depVersion !== version) {
|
||||
console.error(
|
||||
`optionalDependencies 版本不一致:${name}=${depVersion},期望 ${version}。` +
|
||||
"请先同步 package.json 后再发布。",
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureDistBinariesConsistent(version: string) {
|
||||
const distPaths = [...new Bun.Glob("*/package.json").scanSync({ cwd: "./dist" })]
|
||||
if (distPaths.length === 0) {
|
||||
console.error("dist 目录中未找到任何二进制包 package.json。请先执行构建。")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
for (const rel of distPaths) {
|
||||
const file = `./dist/${rel}`
|
||||
const distPkg = (await Bun.file(file).json()) as { name: string; version: string }
|
||||
if (!distPkg.name.startsWith("qimingcode-")) continue
|
||||
if (distPkg.version !== version) {
|
||||
console.error(
|
||||
`dist 二进制包版本不一致:${distPkg.name}=${distPkg.version},期望 ${version}。` +
|
||||
"请重建二进制后再发布。",
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureLocalSmokeVersion(version: string) {
|
||||
// 选择当前机器最常见的本地产物做烟测(mac arm64),不存在则跳过,不阻断非本机平台构建场景。
|
||||
const smokeBin = "./dist/qimingcode-darwin-arm64/bin/opencode"
|
||||
if (!(await Bun.file(smokeBin).exists())) {
|
||||
console.warn(`未找到本地 smoke 二进制 ${smokeBin},跳过本地版本烟测。`)
|
||||
return
|
||||
}
|
||||
|
||||
const out = await $`${smokeBin} --version`.quiet().nothrow()
|
||||
if (out.exitCode !== 0) {
|
||||
console.error(`本地 smoke 二进制执行失败(exit=${out.exitCode})。`)
|
||||
process.exit(1)
|
||||
}
|
||||
const actual = out.stdout.toString().trim()
|
||||
if (actual !== version) {
|
||||
console.error(`本地二进制版本不一致:smoke=${actual},期望 ${version}。`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureRegistryMainVersion(version: string) {
|
||||
const check = await $`npm view qimingcode@${version} version --registry=https://registry.npmjs.org/`
|
||||
.quiet()
|
||||
.nothrow()
|
||||
if (check.exitCode !== 0) {
|
||||
console.error(`registry 中未查到 qimingcode@${version}。`)
|
||||
process.exit(1)
|
||||
}
|
||||
const actual = check.stdout.toString().trim()
|
||||
if (actual !== version) {
|
||||
console.error(`registry 主包版本不一致:${actual},期望 ${version}。`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureRegistryOptionalsComplete(version: string) {
|
||||
const result =
|
||||
await $`bun run script/verify-registry-complete.ts ${version}`.cwd(process.cwd()).quiet().nothrow()
|
||||
if (result.exitCode !== 0) {
|
||||
console.error("registry optionalDependencies 完整性校验失败。")
|
||||
if (result.stderr.toString().trim()) console.error(result.stderr.toString())
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureInstalledCliVersion(version: string) {
|
||||
const cmd = [
|
||||
"tmpdir=$(mktemp -d)",
|
||||
"cd \"$tmpdir\"",
|
||||
"npm init -y >/dev/null",
|
||||
"npm i \"qimingcode@" + version + "\" --registry=https://registry.npmjs.org/ >/dev/null 2>&1",
|
||||
"./node_modules/.bin/qimingcode -v",
|
||||
].join(" && ")
|
||||
const run = await $`bash -lc ${cmd}`.quiet().nothrow()
|
||||
if (run.exitCode !== 0) {
|
||||
console.error("安装态 CLI 版本校验执行失败。")
|
||||
process.exit(1)
|
||||
}
|
||||
const actual = run.stdout.toString().trim()
|
||||
if (actual !== version) {
|
||||
console.error(`安装态 CLI 版本不一致:${actual},期望 ${version}。`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
async function runPre(version: string) {
|
||||
if (pkg.version !== version) {
|
||||
console.error(`package.json 版本不一致:${pkg.version},期望 ${version}。`)
|
||||
process.exit(1)
|
||||
}
|
||||
await ensureOptionalDependenciesConsistent(version)
|
||||
await ensureDistBinariesConsistent(version)
|
||||
await ensureLocalSmokeVersion(version)
|
||||
console.log(`pre 校验通过:本地主包/optional/dist/烟测版本均为 ${version}`)
|
||||
}
|
||||
|
||||
async function runPost(version: string) {
|
||||
await ensureRegistryMainVersion(version)
|
||||
await ensureRegistryOptionalsComplete(version)
|
||||
await ensureInstalledCliVersion(version)
|
||||
console.log(`post 校验通过:registry 与安装态 CLI 版本均为 ${version}`)
|
||||
}
|
||||
|
||||
if (phase === "pre") {
|
||||
await runPre(targetVersion)
|
||||
} else {
|
||||
await runPost(targetVersion)
|
||||
}
|
||||
Reference in New Issue
Block a user