diff --git a/src/workflows/repo-config-workflow.test.ts b/src/workflows/repo-config-workflow.test.ts index 522adf3..5e87ead 100644 --- a/src/workflows/repo-config-workflow.test.ts +++ b/src/workflows/repo-config-workflow.test.ts @@ -56,7 +56,7 @@ describe("RepoConfigWorkflow dispatch — happy path", () => { }); describe("RepoConfigWorkflow dispatch — file absent", () => { - test("present=false → early return, no DO write, complete", async () => { + test("present=false → skips parse, still writes empty settings, complete", async () => { const instanceId = "config_push-repo-missing-delivery-2"; await using instance = await introspectWorkflowInstance( env.REPO_CONFIG_WORKFLOW, @@ -64,9 +64,10 @@ describe("RepoConfigWorkflow dispatch — file absent", () => { ); await instance.modify(async (m) => { await m.mockStepResult({ name: "fetch-config-file" }, { present: false }); - // parse-and-validate / store-repo-config intentionally NOT mocked — if - // the workflow tried to run them unmocked it would fail, exposing a - // regression in the early-exit branch. + // parse-and-validate intentionally NOT mocked — if the workflow tried + // to run it when the file is absent, the unmocked step would fail and + // expose a regression in the skip-parse branch. + await m.mockStepResult({ name: "store-repo-config" }, { ok: true }); }); await env.REPO_CONFIG_WORKFLOW.create({ id: instanceId, params: base }); await expect(instance.waitForStatus("complete")).resolves.not.toThrow(); diff --git a/src/workflows/steps/sync-repo-config.test.ts b/src/workflows/steps/sync-repo-config.test.ts index 904cd5b..9e62513 100644 --- a/src/workflows/steps/sync-repo-config.test.ts +++ b/src/workflows/steps/sync-repo-config.test.ts @@ -111,7 +111,7 @@ describe("runSyncRepoConfig", () => { }); }); - test("file absent — only runs fetch-config-file and makes no DO writes", async () => { + test("file absent — skips parse-and-validate and writes empty settings to DO", async () => { const { step, calls } = makeStep(); const { REPO_CONFIG_DO, idFromName, get, setRepoConfig } = makeDO(); const github = { @@ -127,10 +127,18 @@ describe("runSyncRepoConfig", () => { logger: noopLogger, }); - expect(calls.map((c) => c.name)).toEqual(["fetch-config-file"]); - expect(idFromName).not.toHaveBeenCalled(); - expect(get).not.toHaveBeenCalled(); - expect(setRepoConfig).not.toHaveBeenCalled(); + expect(calls.map((c) => c.name)).toEqual([ + "fetch-config-file", + "store-repo-config", + ]); + expect(idFromName).toHaveBeenCalledWith("acme/repo"); + expect(get).toHaveBeenCalledTimes(1); + expect(setRepoConfig).toHaveBeenCalledWith({ + repositoryId: 42, + repositoryFullName: "acme/repo", + installationId: 100, + settings: {}, + }); }); test("TOML syntax invalid — parse-and-validate throws; store-repo-config not invoked", async () => { diff --git a/src/workflows/steps/sync-repo-config.ts b/src/workflows/steps/sync-repo-config.ts index f774e36..d3dad9b 100644 --- a/src/workflows/steps/sync-repo-config.ts +++ b/src/workflows/steps/sync-repo-config.ts @@ -49,22 +49,26 @@ export async function runSyncRepoConfig( return { present: true as const, contentBase64: res.contentBase64 }; }); - if (!fileResult.present) { - logger.info("No repo config file present; skipping DO write", { + let settings: StoredRepoConfig["settings"]; + if (fileResult.present) { + const parseResult = await step.do("parse-and-validate", async () => { + const raw = Buffer.from(fileResult.contentBase64, "base64").toString( + "utf8", + ); + return { settings: parseRepoConfigToml(raw) }; + }); + settings = parseResult.settings; + } else { + // No config file at head SHA: persist empty settings so downstream + // `getRepoConfig()` returns a defaulted `RepoConfig` instead of `null`, + // which would otherwise push the task onto the legacy template path. + logger.info("No repo config file present; storing empty settings", { fullName, sha: event.head.sha, }); - return; + settings = {}; } - const parseResult = await step.do("parse-and-validate", async () => { - const raw = Buffer.from(fileResult.contentBase64, "base64").toString( - "utf8", - ); - const settings = parseRepoConfigToml(raw); - return { settings }; - }); - await step.do("store-repo-config", async () => { const id = env.REPO_CONFIG_DO.idFromName(fullName); const stub = env.REPO_CONFIG_DO.get(id); @@ -72,7 +76,7 @@ export async function runSyncRepoConfig( repositoryId, repositoryFullName: fullName, installationId, - settings: parseResult.settings, + settings, }; await stub.setRepoConfig(cfg); return { ok: true as const };