Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,15 +297,25 @@ async function writeConfig(

const content = configContent.config?.content ?? "{}\n";

const newConfig: Record<string, string> = { org };
const config = parseJSONC(content);
const deployObj = config.asObjectOrForce().getIfObjectOrForce("deploy");

const upsertKey = (key: string, value: string) => {
const prop = deployObj.get(key);
if (prop) {
prop.setValue(value);
} else {
deployObj.append(key, value);
}
};

upsertKey("org", org);
if (app) {
newConfig.app = app;
upsertKey("app", app);
} else {
deployObj.get("app")?.remove();
}

const config = parseJSONC(content);
const deployObj = config.asObjectOrForce().getIfObjectOrForce("deploy");
deployObj.replaceWith(newConfig);
deployObj.ensureMultiline();

await Deno.writeTextFile(
Expand Down
96 changes: 96 additions & 0 deletions tests/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { assertEquals, assertStringIncludes } from "@std/assert";
import { join } from "@std/path";
import { actionHandler } from "../config.ts";
import type { GlobalContext } from "../main.ts";

// Runs the deploy action handler on a temporary config
async function runDeploy(
content: string,
resolved: { org: string | undefined; app: string | undefined },
): Promise<string> {
const dir = await Deno.makeTempDir();
const path = join(dir, "deno.json");
try {
await Deno.writeTextFile(path, content);
const context = {
config: path,
ignore: [],
allowNodeModules: false,
debug: false,
} as unknown as GlobalContext;

await actionHandler((config) => {
config.org = resolved.org;
config.app = resolved.app;
})(context);

return await Deno.readTextFile(path);
} finally {
await Deno.remove(dir, { recursive: true });
}
}

Deno.test("deploy preserves other deploy fields when persisting org/app", async () => {
const input = `{
"deploy": {
"org": "old-org",
"app": "old-app",
"exclude": ["!dist"],
"framework": "fresh"
}
}
`;
const outputConfigJson = await runDeploy(input, {
org: "my-org",
app: "my-app",
});
const outputConfig = JSON.parse(outputConfigJson);

assertEquals(outputConfig.deploy.org, "my-org");
assertEquals(outputConfig.deploy.app, "my-app");
assertEquals(outputConfig.deploy.exclude, ["!dist"]);
assertEquals(outputConfig.deploy.framework, "fresh");
});

Deno.test("deploy creates the deploy block when the config has none", async () => {
const outputConfigJson = await runDeploy("{}\n", {
org: "my-org",
app: "my-app",
});
const outputConfig = JSON.parse(outputConfigJson);

assertEquals(outputConfig.deploy.org, "my-org");
assertEquals(outputConfig.deploy.app, "my-app");
});

Deno.test("deploy clears app when it doesn't resolve but keeps siblings", async () => {
const input = `{
"deploy": { "org": "old-org", "app": "stale", "exclude": ["!dist"] }
}
`;

const outputConfigJson = await runDeploy(input, {
org: "my-org",
app: undefined,
});
const out = JSON.parse(outputConfigJson);

assertEquals(out.deploy.app, undefined);
assertEquals(out.deploy.exclude, ["!dist"]);
});

Deno.test("deploy preserves comments and formatting (jsonc)", async () => {
const input = `{
// keep this comment
"deploy": {
"org": "old-org", // and this one
"exclude": ["!dist"]
}
}
`;

const out = await runDeploy(input, { org: "my-org", app: undefined });

assertStringIncludes(out, "// keep this comment");
assertStringIncludes(out, "// and this one");
});
Loading