Skip to content

Commit bcad883

Browse files
authored
Merge pull request #298 from notJoon/feat/dry-run
2 parents 654c2dd + c89fec1 commit bcad883

4 files changed

Lines changed: 439 additions & 48 deletions

File tree

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ To be released.
7272
- The `--allow-private-address` or `-p` option allows looking up
7373
WebFinger information for private addresses (e.g., `localhost`).
7474

75+
- Added `--dry-run` option to `fedify init` command. This option allows users
76+
to preview what files and configurations would be created without actually
77+
creating them. [[#263], [#298] by Lee ByeongJun]
78+
7579
- Fixed a bug where the `fedify node` command had failed to correctly
7680
render the favicon in terminal emulators that do not support 24-bit
7781
colors. [[#168], [#282] by Hyeonseo Kim]
@@ -80,10 +84,12 @@ To be released.
8084
[#248]: https://github.com/fedify-dev/fedify/issues/248
8185
[#260]: https://github.com/fedify-dev/fedify/issues/260
8286
[#262]: https://github.com/fedify-dev/fedify/issues/262
87+
[#263]: https://github.com/fedify-dev/fedify/issues/263
8388
[#278]: https://github.com/fedify-dev/fedify/pull/278
8489
[#281]: https://github.com/fedify-dev/fedify/pull/281
8590
[#282]: https://github.com/fedify-dev/fedify/pull/282
8691
[#285]: https://github.com/fedify-dev/fedify/pull/285
92+
[#298]: https://github.com/fedify-dev/fedify/pull/298
8793
[#300]: https://github.com/fedify-dev/fedify/pull/300
8894

8995

cli/init.test.ts

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
import { assertEquals, assertStringIncludes } from "@std/assert";
2+
import { join } from "@std/path";
3+
import { exists } from "@std/fs";
4+
5+
const CLI_PATH = join(import.meta.dirname!, "mod.ts");
6+
7+
async function runInit(
8+
args: string[],
9+
): Promise<{ output: string; success: boolean }> {
10+
const cmd = new Deno.Command("deno", {
11+
args: ["run", "-A", CLI_PATH, "init", ...args],
12+
stdout: "piped",
13+
stderr: "piped",
14+
stdin: "null",
15+
});
16+
17+
const process = cmd.spawn();
18+
const output = await process.output();
19+
const decoder = new TextDecoder();
20+
const stdout = decoder.decode(output.stdout);
21+
const stderr = decoder.decode(output.stderr);
22+
23+
return {
24+
output: stdout + stderr,
25+
success: output.success,
26+
};
27+
}
28+
29+
Deno.test("init --dry-run shows preview without creating files", async () => {
30+
const testDir = await Deno.makeTempDir();
31+
const projectDir = join(testDir, "test-project");
32+
33+
try {
34+
const result = await runInit([
35+
projectDir,
36+
"--dry-run",
37+
"--runtime",
38+
"deno",
39+
]);
40+
41+
// Check that dry-run mode is indicated
42+
assertStringIncludes(result.output, "🔍 DRY RUN MODE");
43+
assertStringIncludes(result.output, "Would create files:");
44+
assertStringIncludes(result.output, "Would install dependencies:");
45+
46+
assertStringIncludes(result.output, "federation.ts");
47+
assertStringIncludes(result.output, "logging.ts");
48+
assertStringIncludes(result.output, "main.ts");
49+
assertStringIncludes(result.output, "deno.json");
50+
assertStringIncludes(result.output, ".env");
51+
52+
// Verify no files were actually created
53+
assertEquals(
54+
await exists(projectDir),
55+
false,
56+
"Project directory should not be created",
57+
);
58+
} finally {
59+
await Deno.remove(testDir, { recursive: true });
60+
}
61+
});
62+
63+
Deno.test("init --dry-run with web framework shows correct files", async () => {
64+
const testDir = await Deno.makeTempDir();
65+
const projectDir = join(testDir, "test-hono-project");
66+
67+
try {
68+
const result = await runInit([
69+
projectDir,
70+
"--dry-run",
71+
"--runtime",
72+
"deno",
73+
"--web-framework",
74+
"hono",
75+
]);
76+
77+
// Check Hono-specific files
78+
assertStringIncludes(result.output, "src/federation.ts");
79+
assertStringIncludes(result.output, "src/app.tsx");
80+
assertStringIncludes(result.output, "src/index.ts");
81+
assertStringIncludes(result.output, "@hono/hono");
82+
83+
// Verify no files were created
84+
assertEquals(await exists(projectDir), false);
85+
} finally {
86+
await Deno.remove(testDir, { recursive: true });
87+
}
88+
});
89+
90+
Deno.test("init --dry-run with external stores shows dependencies", async () => {
91+
const testDir = await Deno.makeTempDir();
92+
const projectDir = join(testDir, "test-redis-project");
93+
94+
try {
95+
const result = await runInit([
96+
projectDir,
97+
"--dry-run",
98+
"--runtime",
99+
"deno",
100+
"--kv-store",
101+
"redis",
102+
"--message-queue",
103+
"redis",
104+
]);
105+
106+
// Check Redis dependencies
107+
assertStringIncludes(result.output, "@fedify/redis");
108+
assertStringIncludes(result.output, "ioredis");
109+
assertStringIncludes(result.output, "REDIS_URL");
110+
111+
// Check Redis imports in federation.ts
112+
assertStringIncludes(result.output, "RedisKvStore");
113+
assertStringIncludes(result.output, "RedisMessageQueue");
114+
115+
// Verify no files were created
116+
assertEquals(await exists(projectDir), false);
117+
} finally {
118+
await Deno.remove(testDir, { recursive: true });
119+
}
120+
});
121+
122+
Deno.test("init --dry-run shows command for framework initialization", async () => {
123+
const testDir = await Deno.makeTempDir();
124+
const projectDir = join(testDir, "test-nitro-project");
125+
126+
try {
127+
const result = await runInit([
128+
projectDir,
129+
"--dry-run",
130+
"--runtime",
131+
"node",
132+
"--package-manager",
133+
"npm",
134+
"--web-framework",
135+
"nitro",
136+
]);
137+
138+
// Check that initialization command is shown
139+
assertStringIncludes(result.output, "Would run command:");
140+
assertStringIncludes(result.output, "giget@latest nitro");
141+
142+
// Check Node.js specific files
143+
assertStringIncludes(result.output, "package.json");
144+
assertStringIncludes(result.output, "biome.json");
145+
146+
// Verify no files were created
147+
assertEquals(await exists(projectDir), false);
148+
} finally {
149+
await Deno.remove(testDir, { recursive: true });
150+
}
151+
});
152+
153+
Deno.test("init without --dry-run creates actual files", async () => {
154+
const testDir = await Deno.makeTempDir();
155+
const projectDir = join(testDir, "test-actual-project");
156+
157+
try {
158+
// Run without --dry-run
159+
const result = await runInit([
160+
projectDir,
161+
"--runtime",
162+
"deno",
163+
]);
164+
165+
// Should not show dry-run header
166+
assertEquals(result.output.includes("DRY RUN MODE"), false);
167+
168+
// Verify files were actually created
169+
assertEquals(
170+
await exists(projectDir),
171+
true,
172+
"Project directory should be created",
173+
);
174+
assertEquals(await exists(join(projectDir, "federation.ts")), true);
175+
assertEquals(await exists(join(projectDir, "logging.ts")), true);
176+
assertEquals(await exists(join(projectDir, "main.ts")), true);
177+
assertEquals(await exists(join(projectDir, "deno.json")), true);
178+
assertEquals(await exists(join(projectDir, ".env")), true);
179+
} finally {
180+
await Deno.remove(testDir, { recursive: true });
181+
}
182+
});
183+
184+
Deno.test("init --dry-run fails on non-empty directory", async () => {
185+
const testDir = await Deno.makeTempDir();
186+
187+
try {
188+
// Create a file in the directory
189+
await Deno.writeTextFile(join(testDir, "existing.txt"), "content");
190+
191+
const result = await runInit([
192+
testDir,
193+
"--dry-run",
194+
"--runtime",
195+
"deno",
196+
]);
197+
198+
assertStringIncludes(result.output, "The directory is not empty");
199+
assertEquals(result.success, false);
200+
} finally {
201+
await Deno.remove(testDir, { recursive: true });
202+
}
203+
});
204+
205+
Deno.test("init --dry-run shows prepend files for Fresh", async () => {
206+
const testDir = await Deno.makeTempDir();
207+
const projectDir = join(testDir, "test-fresh-project");
208+
209+
try {
210+
const result = await runInit([
211+
projectDir,
212+
"--dry-run",
213+
"--runtime",
214+
"deno",
215+
"--web-framework",
216+
"fresh",
217+
]);
218+
219+
// Check that prepend files are shown
220+
assertStringIncludes(result.output, "Would prepend to files:");
221+
assertStringIncludes(result.output, "fresh.config.ts");
222+
223+
// Verify no files were created
224+
assertEquals(await exists(projectDir), false);
225+
} finally {
226+
await Deno.remove(testDir, { recursive: true });
227+
}
228+
});
229+
230+
Deno.test("init --dry-run shows dev dependencies for Node.js", async () => {
231+
const testDir = await Deno.makeTempDir();
232+
const projectDir = join(testDir, "test-node-project");
233+
234+
try {
235+
const result = await runInit([
236+
projectDir,
237+
"--dry-run",
238+
"--runtime",
239+
"node",
240+
"--package-manager",
241+
"npm",
242+
]);
243+
244+
// Check dev dependencies
245+
assertStringIncludes(result.output, "Would install dev dependencies:");
246+
assertStringIncludes(result.output, "@biomejs/biome");
247+
248+
// Verify no files were created
249+
assertEquals(await exists(projectDir), false);
250+
} finally {
251+
await Deno.remove(testDir, { recursive: true });
252+
}
253+
});

0 commit comments

Comments
 (0)