fix(studio): describe publication version auto-increment limits

This commit is contained in:
xiexian committed 2026-10-06 11:15:05 +08:00
1 parent 1c85e79cc6
commit a4c97196ff
4 files changed
+42 -4

No files matched your search

@@ -876,7 +876,7 @@ export const EN_SETTINGS: Record<string, string> = {
"主题以插件包发布,包里只能有主题;带技能、钩子或 MCP 服务的包请按插件发布。": "A theme is published as a plugin package that holds only themes; a package with skills, hooks or MCP servers is published as a plugin.",
"小写字母、数字、点、下划线、连字符,最多 64 个字符。": "Lowercase letters, digits, dots, underscores and hyphens, up to 64 characters.",
"要发布这个包的新版本,请保持名称不变;改名会发布为另一个包。": "Keep this name to publish a new version of this package. Changing it publishes a different package.",
"留空时新包为 0.1.0,更新自动加一个补丁号。": "Left empty, a new package starts at 0.1.0 and an update bumps the patch number.",
"留空时新包为 0.1.0;更新只自动递增纯数字三段版本的补丁号,其他版本请明确填写。": "Blank starts a new package at 0.1.0. Updates auto-increment only a numeric three-part version; enter other versions explicitly.",
"来源地址": "Source address",
"摘要": "Summary",
"描述": "Description",
@@ -138,7 +138,7 @@ function PublishDraft({ port, handle, onMine, initial }: PublishProps) {
<label>
<span>{t("版本")}</span>
<input value={d.version} disabled={busy} data-action="market.draft" data-value="version" placeholder="0.1.0" spellCheck={false} onChange={set("version")} />
<em className="mkt-tip">{t("留空时新包为 0.1.0,更新自动加一个补丁号。")}</em>
<em className="mkt-tip">{t("留空时新包为 0.1.0;更新只自动递增纯数字三段版本的补丁号,其他版本请明确填写。")}</em>
</label>
<label className="full">
<span>{t("来源地址")}</span>
@@ -22,11 +22,11 @@ const field = (key: string) => screen.getByLabelText<HTMLInputElement | HTMLText
const existingTags = () => screen.getAllByRole<HTMLInputElement>("textbox", { name: new RegExp(`^${t("已有标签 {n}", { n: "" })}`) });
const draw = (port: AgentPort, handle = "demo") => <MarketGroup port={port} account={{ signedIn: true, user: { handle, email: `${handle}@example.com`, label: handle } }} onInstalled={() => {}} onSignIn={() => {}} />;
async function fixture(kind: MarketKind = "plugin", status = "private") {
async function fixture(kind: MarketKind = "plugin", status = "private", latestVersion = "1.4.9") {
const port = new MockPort() as unknown as AgentPort;
const base = (await port.myMarket())[0]!;
const pkg: MarketPackage = {
...base, kind, status, name: "release-kit", handle: "demo", slug: "demo/release-kit", latestVersion: "1.4.9",
...base, kind, status, name: "release-kit", handle: "demo", slug: "demo/release-kit", latestVersion,
summary: "Existing summary", description: "Existing description\nwith a second line.",
repoUrl: "https://github.com/demo/releases", tags: ["ui,ux", "文档,示例", "tools"], installed: undefined,
};
@@ -50,6 +50,31 @@ const nameHint = {
en: "Keep this name to publish a new version of this package. Changing it publishes a different package.",
};
it.each(["zh", "en"].flatMap((lang) => ["1.4.9-rc.1", "release-2026"].map((latest) => ({ lang, latest }))))(
"explains blank-version limits and preserves a corrected $latest update in $lang", async ({ lang, latest }) => {
localStorage.setItem(STORAGE, lang); boot();
const f = await fixture("plugin", "active", latest);
f.publish.mockRejectedValueOnce(new Error("That version is already published"));
await openDraft(f.row);
const version = field("版本");
const hint = within(version.closest("label")!).getByText(lang === "zh"
? "留空时新包为 0.1.0;更新只自动递增纯数字三段版本的补丁号,其他版本请明确填写。"
: "Blank starts a new package at 0.1.0. Updates auto-increment only a numeric three-part version; enter other versions explicitly.");
expect(version.value).toBe("");
fillSource();
await userEvent.click(screen.getByRole("button", { name: t("提交审核") }));
await screen.findByText("That version is already published");
expect(f.publish).toHaveBeenLastCalledWith(expect.objectContaining({ version: "", source }));
fireEvent.change(version, { target: { value: `${latest}.next` } });
await userEvent.click(screen.getByRole("button", { name: t("提交审核") }));
expect(f.publish).toHaveBeenLastCalledWith({
kind: f.pkg.kind, name: f.pkg.name, source, summary: f.pkg.summary, description: f.pkg.description,
repoUrl: f.pkg.repoUrl, version: `${latest}.next`, tags: f.pkg.tags, visibility: "public",
});
expect(hint).toBeTruthy();
},
);
it.each(["zh", "en"] as const)("explains the name choice and submits the author's edited name in %s", async (lang) => {
localStorage.setItem(STORAGE, lang); boot();
const f = await fixture();
@@ -76,6 +76,19 @@ function pluginInput() {
}
describe("PackageRepo.publish", () => {
it.each([
["2.7.0", "2.7.1"], ["2.7.0-rc.1", "0.1.0"], ["release-2026", "0.1.0"],
])("generates %s's blank update version as %s", async (latest, next) => {
const input = PublishSchema.parse({ ...pluginInput(), version: latest });
expect(input.version).toBe(latest);
const { db, updates } = fakePackageDB([
{ ...existing, latest_version: latest }, { ...existing, latest_version: next },
]);
const result = await new PackageRepo(db).publish(user, { ...input, version: "" }, now);
expect(result.version).toBe(next);
expect(updates[0].values[8]).toBe(next);
});
it("persists a kind change when an owned pending package is republished as a plugin", async () => {
const updated: PackageRow = { ...existing, kind: "plugin", install_kind: "plugin", latest_version: "2.7.1" };
const { db, updates } = fakePackageDB([existing, updated]);