cmd_init_spec.lua

  1package.path = package.path .. ";./?.lua"
  2local wt = dofile("src/main.lua")
  3
  4describe("cmd_init", function()
  5	local temp_dir
  6	local original_cwd
  7
  8	setup(function()
  9		local handle = io.popen("pwd")
 10		if handle then
 11			original_cwd = handle:read("*l")
 12			handle:close()
 13		end
 14		handle = io.popen("mktemp -d")
 15		if handle then
 16			temp_dir = handle:read("*l")
 17			handle:close()
 18		end
 19	end)
 20
 21	teardown(function()
 22		if original_cwd then
 23			os.execute("cd " .. original_cwd)
 24		end
 25		if temp_dir then
 26			os.execute("rm -rf " .. temp_dir)
 27		end
 28	end)
 29
 30	describe("already wt-managed repository", function()
 31		it("reports already using wt structure when .git file points to .bare", function()
 32			if not temp_dir then
 33				pending("temp_dir not available")
 34				return
 35			end
 36			local project = temp_dir .. "/already-wt"
 37			os.execute("mkdir -p " .. project .. "/.bare")
 38			os.execute("git init --bare " .. project .. "/.bare")
 39			local f = io.open(project .. "/.git", "w")
 40			if f then
 41				f:write("gitdir: ./.bare\n")
 42				f:close()
 43			end
 44
 45			local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init")
 46			assert.are.equal(0, code)
 47			assert.is_truthy(output:match("[Aa]lready"))
 48		end)
 49	end)
 50
 51	describe("inside a worktree", function()
 52		it("errors when run from inside a worktree", function()
 53			if not temp_dir then
 54				pending("temp_dir not available")
 55				return
 56			end
 57			local project = temp_dir .. "/wt-project"
 58			local worktree = project .. "/main"
 59			os.execute("mkdir -p " .. project .. "/.bare")
 60			os.execute("git init --bare " .. project .. "/.bare")
 61			os.execute("mkdir -p " .. worktree)
 62			local f = io.open(worktree .. "/.git", "w")
 63			if f then
 64				f:write("gitdir: ../.bare/worktrees/main\n")
 65				f:close()
 66			end
 67
 68			local output, code = wt.run_cmd("cd " .. worktree .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
 69			assert.are_not.equal(0, code)
 70			assert.is_truthy(output:match("worktree") or output:match("not a git"))
 71		end)
 72	end)
 73
 74	describe("not a git repository", function()
 75		it("errors when run in non-git directory", function()
 76			if not temp_dir then
 77				pending("temp_dir not available")
 78				return
 79			end
 80			local project = temp_dir .. "/not-git"
 81			os.execute("mkdir -p " .. project)
 82
 83			local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
 84			assert.are_not.equal(0, code)
 85			assert.is_truthy(output:match("not a git"))
 86		end)
 87	end)
 88
 89	describe(".bare exists but no .git", function()
 90		it("errors and suggests creating .git file", function()
 91			if not temp_dir then
 92				pending("temp_dir not available")
 93				return
 94			end
 95			local project = temp_dir .. "/bare-only"
 96			os.execute("mkdir -p " .. project .. "/.bare")
 97			os.execute("git init --bare " .. project .. "/.bare")
 98
 99			local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
100			assert.are_not.equal(0, code)
101			assert.is_truthy(output:match("%.git") or output:match("gitdir"))
102		end)
103	end)
104
105	describe("existing git worktrees", function()
106		it("errors when .git/worktrees/ exists", function()
107			if not temp_dir then
108				pending("temp_dir not available")
109				return
110			end
111			local project = temp_dir .. "/has-worktrees"
112			os.execute("mkdir -p " .. project)
113			os.execute("git init " .. project)
114			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
115			os.execute("mkdir -p " .. project .. "/.git/worktrees/feature-branch")
116
117			local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
118			assert.are_not.equal(0, code)
119			assert.is_truthy(output:match("worktree"))
120		end)
121	end)
122
123	describe("dirty repository", function()
124		it("errors when uncommitted changes exist", function()
125			if not temp_dir then
126				pending("temp_dir not available")
127				return
128			end
129			local project = temp_dir .. "/dirty-repo"
130			os.execute("mkdir -p " .. project)
131			os.execute("git init " .. project)
132			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
133			local f = io.open(project .. "/dirty.txt", "w")
134			if f then
135				f:write("uncommitted\n")
136				f:close()
137			end
138			os.execute("cd " .. project .. " && git add dirty.txt")
139
140			local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
141			assert.are_not.equal(0, code)
142			assert.is_truthy(output:match("uncommitted") or output:match("stash") or output:match("commit"))
143		end)
144	end)
145
146	describe("--dry-run", function()
147		it("prints plan without modifying filesystem", function()
148			if not temp_dir then
149				pending("temp_dir not available")
150				return
151			end
152			local project = temp_dir .. "/dry-run-test"
153			os.execute("mkdir -p " .. project)
154			os.execute("git init " .. project)
155			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
156
157			local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1"
158			local output, code = wt.run_cmd(cmd)
159			assert.are.equal(0, code)
160			assert.is_truthy(output:match("[Dd]ry run") or output:match("planned"))
161
162			local git_still_dir = io.open(project .. "/.git/HEAD", "r")
163			assert.is_not_nil(git_still_dir)
164			if git_still_dir then
165				git_still_dir:close()
166			end
167
168			local bare_exists = io.open(project .. "/.bare/HEAD", "r")
169			assert.is_nil(bare_exists)
170		end)
171
172		it("lists orphaned files that would be removed", function()
173			if not temp_dir then
174				pending("temp_dir not available")
175				return
176			end
177			local project = temp_dir .. "/dry-orphans"
178			os.execute("mkdir -p " .. project)
179			os.execute("git init " .. project)
180			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
181
182			local f = io.open(project .. "/README.md", "w")
183			if f then
184				f:write("# Test\n")
185				f:close()
186			end
187			os.execute("cd " .. project .. " && git add README.md && git commit -m 'add readme'")
188
189			local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1"
190			local output, code = wt.run_cmd(cmd)
191			assert.are.equal(0, code)
192			assert.is_truthy(output:match("README") or output:match("orphan"))
193		end)
194
195		it("shows target worktree path", function()
196			if not temp_dir then
197				pending("temp_dir not available")
198				return
199			end
200			local project = temp_dir .. "/dry-worktree"
201			os.execute("mkdir -p " .. project)
202			os.execute("git init " .. project)
203			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
204
205			local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1"
206			local output, code = wt.run_cmd(cmd)
207			assert.are.equal(0, code)
208			assert.is_truthy(output:match("worktree") or output:match("main") or output:match("master"))
209		end)
210	end)
211
212	describe("-y/--yes flag", function()
213		it("bypasses confirmation prompt", function()
214			if not temp_dir then
215				pending("temp_dir not available")
216				return
217			end
218			local project = temp_dir .. "/yes-test"
219			os.execute("mkdir -p " .. project)
220			os.execute("git init " .. project)
221			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
222
223			local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
224			assert.are.equal(0, code)
225			assert.is_truthy(output:match("[Cc]onverted") or output:match("[Bb]are"))
226
227			local bare_exists = io.open(project .. "/.bare/HEAD", "r")
228			assert.is_not_nil(bare_exists)
229			if bare_exists then
230				bare_exists:close()
231			end
232
233			local git_is_file = io.open(project .. "/.git", "r")
234			if git_is_file then
235				local content = git_is_file:read("*a")
236				git_is_file:close()
237				assert.is_truthy(content:match("gitdir"))
238			end
239		end)
240	end)
241
242	describe("successful conversion", function()
243		it("moves .git to .bare", function()
244			if not temp_dir then
245				pending("temp_dir not available")
246				return
247			end
248			local project = temp_dir .. "/convert-test"
249			os.execute("mkdir -p " .. project)
250			os.execute("git init " .. project)
251			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
252
253			local _, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
254			assert.are.equal(0, code)
255
256			local bare_head = io.open(project .. "/.bare/HEAD", "r")
257			assert.is_not_nil(bare_head)
258			if bare_head then
259				bare_head:close()
260			end
261		end)
262
263		it("creates .git file pointing to .bare", function()
264			if not temp_dir then
265				pending("temp_dir not available")
266				return
267			end
268			local project = temp_dir .. "/git-file-test"
269			os.execute("mkdir -p " .. project)
270			os.execute("git init " .. project)
271			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
272
273			local _, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
274			assert.are.equal(0, code)
275
276			local git_file = io.open(project .. "/.git", "r")
277			assert.is_not_nil(git_file)
278			if git_file then
279				local content = git_file:read("*a")
280				git_file:close()
281				assert.is_truthy(content:match("gitdir:.*%.bare"))
282			end
283		end)
284
285		it("creates worktree for default branch", function()
286			if not temp_dir then
287				pending("temp_dir not available")
288				return
289			end
290			local project = temp_dir .. "/worktree-created"
291			os.execute("mkdir -p " .. project)
292			os.execute("git init " .. project)
293			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
294
295			local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1"
296			local _, code = wt.run_cmd(cmd)
297			assert.are.equal(0, code)
298
299			local worktrees_output, _ = wt.run_cmd("GIT_DIR=" .. project .. "/.bare git worktree list")
300			assert.is_truthy(worktrees_output:match("main") or worktrees_output:match("master"))
301		end)
302
303		it("removes orphaned files from root", function()
304			if not temp_dir then
305				pending("temp_dir not available")
306				return
307			end
308			local project = temp_dir .. "/orphan-cleanup"
309			os.execute("mkdir -p " .. project)
310			os.execute("git init " .. project)
311			local f = io.open(project .. "/tracked.txt", "w")
312			if f then
313				f:write("tracked\n")
314				f:close()
315			end
316			os.execute("cd " .. project .. " && git add tracked.txt && git commit -m 'add file'")
317
318			local _, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
319			assert.are.equal(0, code)
320
321			local orphan_check = io.open(project .. "/tracked.txt", "r")
322			assert.is_nil(orphan_check)
323		end)
324	end)
325
326	describe("warnings", function()
327		it("warns about submodules", function()
328			if not temp_dir then
329				pending("temp_dir not available")
330				return
331			end
332			local project = temp_dir .. "/submodule-warn"
333			os.execute("mkdir -p " .. project)
334			os.execute("git init " .. project)
335			os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
336			local f = io.open(project .. "/.gitmodules", "w")
337			if f then
338				f:write("[submodule \"lib\"]\n\tpath = lib\n\turl = https://example.com/lib.git\n")
339				f:close()
340			end
341			os.execute("cd " .. project .. " && git add .gitmodules && git commit -m 'add submodules'")
342
343			local output, _ = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1")
344			assert.is_truthy(output:match("submodule") or output:match("[Ww]arning"))
345		end)
346	end)
347end)