mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
7bc1c49cb6
复用同一个 Publish workflow 入口(package 下拉多一项 bailian-kb-dsh),路由到 独立的 publish-kb-dsh.mjs 处理: - 版本读自身 package.json(不广播全套 bl 版本) - stable 打 bailian-kb-dsh-v<version> tag(与 bl 的 v<version> 错开命名空间) - channel 临时 bump 到 0.0.0-beta-<sha>-<stamp>(形态与 bl channel 一致), finally 还原 package.json - 走自身的 tsc + tsdown build,无 binary,无 OSS CDN - 复用 lib/git.mjs / lib/npm.mjs / lib/proc.mjs 三个薄工具 - 复用 workflow 入口 UI 与 setup 步骤(checkout / pnpm / node 24 / gitleaks / install),stable 走 environment: production Required Reviewers gate 不复用 publish-stable.mjs / publish-channel.mjs:它们的 loadAndValidatePackages 会广播 core 版本给全套锁步包并强校验一致性,把 kb-dsh 塞进去第一步就 throw。 故意分开是为了保住这个隔离。 本地 --dry-run 端到端跑通:build → 幂等性查重 → pack + publint + gitleaks → pnpm publish --tag latest|<channel> --provenance --dry-run;channel 模式的 finally 还原后 git diff 干净。 文档:dsh-plugin.md 补发布小节 + 已知待办(publint 那条 web bundle CJS/ESM warning);publish.md 加 bailian-kb-dsh 定位;packages.mjs 与 AGENTS.md 的 注释同步指向新的 job 与 script 名。
170 lines
5.8 KiB
JavaScript
170 lines
5.8 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Publish bailian-kb-dsh (dsh plugin, downstream host adapter).
|
|
*
|
|
* Deliberately independent from publish-stable.mjs / publish-channel.mjs:
|
|
* - the plugin is NOT in the version-locked bl release set (packages.mjs
|
|
* PACKAGES / ALL_PACKAGES; see packages.mjs footer comment),
|
|
* - it uses tsc + tsdown instead of `vp pack`, and has no binary artifact,
|
|
* - it tags as `bailian-kb-dsh-v<version>` so its lightweight tags never
|
|
* collide with the bl `v<version>` namespace.
|
|
*
|
|
* Shared with the other publish scripts: dry-run gate, CI-only guard,
|
|
* per-mode preflight, `pnpm publish --provenance`, publint + gitleaks scan.
|
|
*/
|
|
import { mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
import { tmpdir } from "os";
|
|
import { join } from "path";
|
|
import { parseArgs } from "util";
|
|
|
|
import {
|
|
createTag,
|
|
currentBranch,
|
|
headSha7,
|
|
isWorkingTreeClean,
|
|
pushTag,
|
|
tagExists,
|
|
utcDateStamp,
|
|
} from "./lib/git.mjs";
|
|
import { npmViewExists, pnpmPack, pnpmPublish } from "./lib/npm.mjs";
|
|
import { ROOT } from "./lib/packages.mjs";
|
|
import { run } from "./lib/proc.mjs";
|
|
|
|
const PKG = { key: "kb-dsh", dir: "packages/bailian-kb-dsh", name: "bailian-kb-dsh" };
|
|
const PKG_JSON_PATH = join(ROOT, PKG.dir, "package.json");
|
|
|
|
function log(msg = "") {
|
|
process.stdout.write(`${msg}\n`);
|
|
}
|
|
|
|
function step(msg) {
|
|
log(`\n==> ${msg}`);
|
|
}
|
|
|
|
function readPackageJson() {
|
|
return JSON.parse(readFileSync(PKG_JSON_PATH, "utf-8"));
|
|
}
|
|
|
|
function writePackageJson(json) {
|
|
writeFileSync(PKG_JSON_PATH, `${JSON.stringify(json, null, 2)}\n`);
|
|
}
|
|
|
|
const { values } = parseArgs({
|
|
options: {
|
|
channel: { type: "string" },
|
|
"dry-run": { type: "boolean", default: false },
|
|
},
|
|
allowPositionals: false,
|
|
});
|
|
const channel = values.channel;
|
|
const dryRun = values["dry-run"];
|
|
const isChannel = channel !== undefined && channel !== "";
|
|
|
|
if (!dryRun && !process.env.CI) {
|
|
process.stderr.write("publish-kb-dsh is CI-only. Pass --dry-run to test locally.\n");
|
|
process.exit(1);
|
|
}
|
|
|
|
// Snapshot for channel mode: the temporary version bump must be reverted in
|
|
// `finally`, even on mid-flight failure. Stable mode does not bump, so the
|
|
// snapshot is a no-op that keeps the restore path uniform.
|
|
const originalPackageJson = readFileSync(PKG_JSON_PATH, "utf-8");
|
|
function restoreOriginal() {
|
|
writeFileSync(PKG_JSON_PATH, originalPackageJson);
|
|
}
|
|
|
|
try {
|
|
if (isChannel) {
|
|
step(`channel release: ${channel}`);
|
|
} else {
|
|
step("stable release");
|
|
if (!dryRun) {
|
|
if (!isWorkingTreeClean()) {
|
|
throw new Error("git working tree is not clean; commit or stash first.");
|
|
}
|
|
const branch = currentBranch();
|
|
if (branch !== "main") {
|
|
throw new Error(`must publish from main, currently on ${branch}.`);
|
|
}
|
|
} else {
|
|
log("[dry-run] skipping working-tree + branch preflight");
|
|
}
|
|
}
|
|
|
|
// Resolve the version we are about to publish.
|
|
const originalVersion = readPackageJson().version;
|
|
let publishVersion = originalVersion;
|
|
if (isChannel) {
|
|
// Match the shape used by publish-channel.mjs (bl channel releases) so
|
|
// consumers see a familiar dist-tag payload; the leading 0.0.0 keeps
|
|
// semver from ever preferring a beta over a real release.
|
|
const sha = headSha7();
|
|
const stamp = utcDateStamp();
|
|
publishVersion = `0.0.0-beta-${sha}-${stamp}`;
|
|
step(`temporarily bump ${PKG.name} to ${publishVersion} (not committed)`);
|
|
const json = readPackageJson();
|
|
json.version = publishVersion;
|
|
writePackageJson(json);
|
|
}
|
|
log(`${PKG.name}@${publishVersion}`);
|
|
|
|
step(`build ${PKG.name}`);
|
|
run("pnpm", ["--filter", PKG.name, "run", "build"]);
|
|
|
|
step(`idempotency: check ${publishVersion} against registry`);
|
|
const alreadyPublished = npmViewExists(PKG.name, publishVersion);
|
|
log(`${PKG.name}@${publishVersion}: ${alreadyPublished ? "already published" : "to publish"}`);
|
|
|
|
if (alreadyPublished) {
|
|
if (!isChannel) {
|
|
throw new Error(
|
|
`version ${publishVersion} is already published; bump ${PKG.dir}/package.json before retrying.`,
|
|
);
|
|
}
|
|
log("channel version already published; skipping npm publish");
|
|
} else {
|
|
step("pack + scan (publint, gitleaks)");
|
|
const tempDir = mkdtempSync(join(tmpdir(), "bailian-kb-dsh-release-"));
|
|
try {
|
|
const packJson = readPackageJson();
|
|
const tarball = pnpmPack(PKG, tempDir, packJson);
|
|
run("tar", ["-xzf", tarball, "-C", tempDir], { stdio: "pipe" });
|
|
const extractDir = join(tempDir, `extract-${PKG.key}`);
|
|
renameSync(join(tempDir, "package"), extractDir);
|
|
run("npx", ["--yes", "publint", extractDir]);
|
|
run("gitleaks", ["detect", "--source", extractDir, "--no-git", "--redact"]);
|
|
} finally {
|
|
rmSync(tempDir, { recursive: true, force: true });
|
|
}
|
|
|
|
const npmTag = isChannel ? channel : "latest";
|
|
step(`publish ${PKG.name}@${publishVersion} (tag=${npmTag}, provenance)`);
|
|
pnpmPublish(PKG, { tag: npmTag, provenance: true, dryRun });
|
|
}
|
|
|
|
if (isChannel) {
|
|
log(`\nchannel release complete: ${channel}@${publishVersion} (npm-only, no tag)`);
|
|
} else {
|
|
// Namespaced tag: bl uses `v<version>`, so we prefix with the package name
|
|
// to avoid colliding when a bl release happens to share the same version
|
|
// fragment.
|
|
const tag = `${PKG.name}-v${publishVersion}`;
|
|
if (dryRun) {
|
|
log("\n[dry-run] skipping git tag");
|
|
} else if (tagExists(tag)) {
|
|
log(`tag ${tag} already exists; skipping tag push`);
|
|
} else {
|
|
step(`tag ${tag} and push`);
|
|
createTag(tag);
|
|
pushTag(tag);
|
|
}
|
|
log(`\nstable release complete: ${PKG.name}@${publishVersion} (npm + tag)`);
|
|
}
|
|
} catch (error) {
|
|
process.stderr.write(`\nrelease publish-kb-dsh failed: ${error.message}\n`);
|
|
// Use exitCode (not process.exit) so `finally` restores any channel bump.
|
|
process.exitCode = 1;
|
|
} finally {
|
|
restoreOriginal();
|
|
}
|