refactor(cron): remove auto migration wrapper

This commit is contained in:
Ted Li
2026-06-04 13:08:43 -07:00
parent bd861ffa33
commit ee962f7e2e
4 changed files with 12 additions and 101 deletions

View File

@@ -9,7 +9,7 @@ const autoMigrateLegacyState = vi.hoisted(() =>
const autoMigrateLegacyTaskStateSidecars = vi.hoisted(() =>
vi.fn(async () => ({ migrated: true, skipped: false, changes: ["task-imported"], warnings: [] })),
);
const autoMigrateLegacyCronStore = vi.hoisted(() =>
const repairLegacyCronStoreWithoutPrompt = vi.hoisted(() =>
vi.fn(async () => ({ changes: ["cron-imported"], warnings: [] })),
);
const readConfigFileSnapshot = vi.hoisted(() =>
@@ -31,8 +31,8 @@ vi.mock("./doctor-state-migrations.js", () => ({
autoMigrateLegacyTaskStateSidecars,
}));
vi.mock("./doctor/cron/auto-migration.js", () => ({
autoMigrateLegacyCronStore,
vi.mock("./doctor/cron/index.js", () => ({
repairLegacyCronStoreWithoutPrompt,
}));
vi.mock("../config/io.js", () => ({
@@ -54,7 +54,7 @@ describe("runDoctorConfigPreflight state migration", () => {
expect(autoMigrateLegacyStateDir).toHaveBeenCalledOnce();
expect(readConfigFileSnapshot).toHaveBeenCalledOnce();
expect(autoMigrateLegacyCronStore).toHaveBeenCalledWith({
expect(repairLegacyCronStoreWithoutPrompt).toHaveBeenCalledWith({
cfg: { gateway: { mode: "local", port: 19091 } },
});
expect(autoMigrateLegacyState).toHaveBeenCalledWith({
@@ -100,7 +100,7 @@ describe("runDoctorConfigPreflight state migration", () => {
});
expect(autoMigrateLegacyState).not.toHaveBeenCalled();
expect(autoMigrateLegacyCronStore).not.toHaveBeenCalled();
expect(repairLegacyCronStoreWithoutPrompt).not.toHaveBeenCalled();
expect(autoMigrateLegacyTaskStateSidecars).toHaveBeenCalledWith({ env: process.env });
expect(note).toHaveBeenCalledWith("- task-imported", "Doctor changes");
});

View File

@@ -16,19 +16,19 @@ import { noteIncludeConfinementWarning } from "./doctor-config-analysis.js";
import { findDoctorLegacyConfigIssues } from "./doctor/shared/legacy-config-issues.js";
type DoctorStateMigrationsModule = typeof import("./doctor-state-migrations.js");
type DoctorCronAutoMigrationModule = typeof import("./doctor/cron/auto-migration.js");
type DoctorCronModule = typeof import("./doctor/cron/index.js");
let doctorStateMigrationsPromise: Promise<DoctorStateMigrationsModule> | null = null;
let doctorCronAutoMigrationPromise: Promise<DoctorCronAutoMigrationModule> | null = null;
let doctorCronPromise: Promise<DoctorCronModule> | null = null;
function loadDoctorStateMigrations(): Promise<DoctorStateMigrationsModule> {
doctorStateMigrationsPromise ??= import("./doctor-state-migrations.js");
return doctorStateMigrationsPromise;
}
function loadDoctorCronAutoMigration(): Promise<DoctorCronAutoMigrationModule> {
doctorCronAutoMigrationPromise ??= import("./doctor/cron/auto-migration.js");
return doctorCronAutoMigrationPromise;
function loadDoctorCron(): Promise<DoctorCronModule> {
doctorCronPromise ??= import("./doctor/cron/index.js");
return doctorCronPromise;
}
async function maybeMigrateLegacyConfig(): Promise<string[]> {
@@ -182,8 +182,8 @@ export async function runDoctorConfigPreflight(
const baseConfig = snapshot.sourceConfig ?? snapshot.config ?? {};
if (options.migrateState !== false) {
if (snapshot.valid) {
const { autoMigrateLegacyCronStore } = await loadDoctorCronAutoMigration();
const cronResult = await autoMigrateLegacyCronStore({ cfg: baseConfig });
const { repairLegacyCronStoreWithoutPrompt } = await loadDoctorCron();
const cronResult = await repairLegacyCronStoreWithoutPrompt({ cfg: baseConfig });
noteStateMigrationResult(cronResult);
}
const { autoMigrateLegacyState, autoMigrateLegacyTaskStateSidecars } =

View File

@@ -1,79 +0,0 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../../../config/config.js";
import { loadCronStore } from "../../../cron/store.js";
import { autoMigrateLegacyCronStore } from "./auto-migration.js";
let tempRoot: string | null = null;
async function makeTempStorePath() {
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cron-auto-migration-"));
return path.join(tempRoot, "cron", "jobs.json");
}
afterEach(async () => {
if (tempRoot) {
await fs.rm(tempRoot, { recursive: true, force: true });
tempRoot = null;
}
});
function createCronConfig(storePath: string): OpenClawConfig {
return {
cron: {
store: storePath,
webhook: "https://example.invalid/cron-finished",
},
};
}
async function writeLegacyCronStore(storePath: string) {
await fs.mkdir(path.dirname(storePath), { recursive: true });
await fs.writeFile(
storePath,
JSON.stringify({
version: 1,
jobs: [
{
jobId: "legacy-job",
name: "Legacy job",
notify: true,
createdAtMs: Date.parse("2026-02-01T00:00:00.000Z"),
updatedAtMs: Date.parse("2026-02-02T00:00:00.000Z"),
schedule: { kind: "cron", cron: "0 7 * * *", tz: "UTC" },
payload: { kind: "systemEvent", text: "Morning brief" },
state: {},
},
],
}),
"utf-8",
);
}
function requireRecord(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error(`expected ${label}`);
}
return value as Record<string, unknown>;
}
describe("autoMigrateLegacyCronStore", () => {
it("imports legacy cron jobs into SQLite and archives the legacy store", async () => {
const storePath = await makeTempStorePath();
await writeLegacyCronStore(storePath);
const result = await autoMigrateLegacyCronStore({ cfg: createCronConfig(storePath) });
const [job] = (await loadCronStore(storePath)).jobs as unknown as Array<
Record<string, unknown>
>;
expect(job?.id).toBe("legacy-job");
expect(job?.jobId).toBeUndefined();
expect(requireRecord(job?.delivery, "cron delivery").mode).toBe("webhook");
await expect(fs.stat(`${storePath}.migrated`)).resolves.toBeTruthy();
expect(result.changes.join("\n")).toContain("Cron store migrated to SQLite");
expect(result.warnings).toEqual([]);
});
});

View File

@@ -1,10 +0,0 @@
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import { repairLegacyCronStoreWithoutPrompt, type LegacyCronRepairResult } from "./index.js";
export type CronAutoMigrationResult = LegacyCronRepairResult;
export async function autoMigrateLegacyCronStore(params: {
cfg: OpenClawConfig;
}): Promise<CronAutoMigrationResult> {
return await repairLegacyCronStoreWithoutPrompt(params);
}