Skip to content

Commit 9702826

Browse files
authored
feat: add --git option to igniter.new (#296)
* add --git option to igniter.new * add integration test * add 🔥 to initial commit
1 parent 802885c commit 9702826

File tree

3 files changed

+258
-2
lines changed

3 files changed

+258
-2
lines changed

installer/lib/mix/tasks/igniter.new.ex

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ defmodule Mix.Tasks.Igniter.New do
1515
to the `--with` command, as it may or may not support it. Use `--with-args`
1616
to provide arguments to that command.
1717
* `--no-installer-version-check` - skip the version check for the latest igniter_new version
18+
* `--git` - Initialize a git repository in the project directory and commit the initial state.
1819
1920
## Options for `mix.new`
2021
@@ -71,7 +72,8 @@ defmodule Mix.Tasks.Igniter.New do
7172
module: :string,
7273
sup: :boolean,
7374
umbrella: :boolean,
74-
installer_version_check: :boolean
75+
installer_version_check: :boolean,
76+
git: :boolean
7577
],
7678
aliases: [i: :install, l: :local, e: :example, w: :with]
7779
)
@@ -241,6 +243,10 @@ defmodule Mix.Tasks.Igniter.New do
241243
)
242244
end
243245

246+
if options[:git] do
247+
initialize_git_repo()
248+
end
249+
244250
:ok
245251
end
246252

@@ -312,7 +318,7 @@ defmodule Mix.Tasks.Igniter.New do
312318
end
313319
end
314320

315-
@flags ~w(example sup umbrella installer-version-check no-installer-version-check)
321+
@flags ~w(example sup umbrella installer-version-check no-installer-version-check git)
316322
@flags_with_values ~w(install local with with-args module)
317323
@switches ~w(e)
318324
@switches_with_values ~w(i l)
@@ -383,6 +389,33 @@ defmodule Mix.Tasks.Igniter.New do
383389
@doc false
384390
def igniter_version, do: @igniter_version
385391

392+
defp initialize_git_repo do
393+
Igniter.Installer.Loading.with_spinner(
394+
"Initializing local git repository, staging all files, and committing",
395+
fn ->
396+
case System.cmd("git", ["init"]) do
397+
{_, 0} ->
398+
case System.cmd("git", ["add", "."]) do
399+
{_, 0} ->
400+
case System.cmd("git", ["commit", "-m", "🔥 initial commit 🔥"]) do
401+
{_, 0} ->
402+
Mix.shell().info("Git repository initialized and initial commit created.")
403+
404+
{output, _} ->
405+
Mix.shell().error("Failed to create initial commit: #{output}")
406+
end
407+
408+
{output, _} ->
409+
Mix.shell().error("Failed to add files to git: #{output}")
410+
end
411+
412+
{output, _} ->
413+
Mix.shell().error("Failed to initialize git repository: #{output}")
414+
end
415+
end
416+
)
417+
end
418+
386419
defp maybe_warn_outdated(latest_version, opts) do
387420
if Version.compare(@installer_version, latest_version) == :lt do
388421
if opts[:yes] do
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
defmodule Mix.Tasks.Igniter.NewTest do
2+
use ExUnit.Case, async: true
3+
4+
@moduletag :tmp_dir
5+
6+
describe "igniter.new with --git flag" do
7+
@tag :integration
8+
test "initializes git repository and creates initial commit", %{tmp_dir: tmp_dir} do
9+
unless git_available?() do
10+
:ok
11+
else
12+
IO.inspect(tmp_dir)
13+
project_name = "test_project"
14+
project_path = Path.join(tmp_dir, project_name)
15+
16+
# Change to tmp directory to run the command
17+
original_cwd = File.cwd!()
18+
19+
try do
20+
File.cd!(tmp_dir)
21+
22+
# Run igniter.new with --git flag using System.cmd
23+
{output, exit_code} =
24+
System.cmd(
25+
"mix",
26+
["igniter.new", project_name, "--git", "--yes", "--no-installer-version-check"],
27+
stderr_to_stdout: true,
28+
env: [{"MIX_ENV", "test"}]
29+
)
30+
31+
if exit_code != 0 do
32+
IO.puts("Command failed with output: #{output}")
33+
end
34+
35+
assert exit_code == 0,
36+
"Expected igniter.new to succeed, but got exit code #{exit_code}. Output: #{output}"
37+
38+
# Verify project directory was created
39+
assert File.exists?(project_path), "Project directory should exist at #{project_path}"
40+
41+
# Change to project directory to check git status
42+
File.cd!(project_path)
43+
44+
# Verify .git directory exists
45+
assert File.exists?(".git"), ".git directory should exist"
46+
assert File.dir?(".git"), ".git should be a directory"
47+
48+
# Verify git repository was initialized by checking git status
49+
{output, 0} = System.cmd("git", ["status", "--porcelain"])
50+
# Empty output means all files are committed (working directory clean)
51+
assert String.trim(output) == "",
52+
"Working directory should be clean after initial commit"
53+
54+
# Verify there is at least one commit
55+
{output, 0} = System.cmd("git", ["log", "--oneline"])
56+
57+
assert String.contains?(output, "🔥 initial commit 🔥"),
58+
"Should have initial commit with fire emoji"
59+
60+
# Verify essential files are tracked
61+
{output, 0} = System.cmd("git", ["ls-files"])
62+
tracked_files = String.split(String.trim(output), "\n")
63+
64+
assert "mix.exs" in tracked_files, "mix.exs should be tracked"
65+
assert ".gitignore" in tracked_files, ".gitignore should be tracked"
66+
assert "README.md" in tracked_files, "README.md should be tracked"
67+
68+
# Verify igniter was added to mix.exs
69+
mix_exs_content = File.read!("mix.exs")
70+
71+
assert String.contains?(mix_exs_content, "{:igniter"),
72+
"Igniter dependency should be added to mix.exs"
73+
after
74+
File.cd!(original_cwd)
75+
end
76+
end
77+
end
78+
79+
@tag :integration
80+
test "creates project without git when --git flag is not provided", %{tmp_dir: tmp_dir} do
81+
unless git_available?() do
82+
:ok
83+
else
84+
project_name = "test_project_no_git"
85+
project_path = Path.join(tmp_dir, project_name)
86+
87+
original_cwd = File.cwd!()
88+
89+
try do
90+
File.cd!(tmp_dir)
91+
92+
# Run igniter.new without --git flag
93+
{output, exit_code} =
94+
System.cmd(
95+
"mix",
96+
["igniter.new", project_name, "--yes", "--no-installer-version-check"],
97+
stderr_to_stdout: true,
98+
env: [{"MIX_ENV", "test"}]
99+
)
100+
101+
assert exit_code == 0,
102+
"Expected igniter.new to succeed, but got exit code #{exit_code}. Output: #{output}"
103+
104+
assert File.exists?(project_path), "Project directory should exist"
105+
File.cd!(project_path)
106+
107+
# Verify .git directory does NOT exist
108+
refute File.exists?(".git"),
109+
".git directory should not exist when --git flag is not provided"
110+
after
111+
File.cd!(original_cwd)
112+
end
113+
end
114+
end
115+
116+
@tag :integration
117+
test "git functionality works with other flags", %{tmp_dir: tmp_dir} do
118+
unless git_available?() do
119+
:ok
120+
else
121+
project_name = "test_project_with_sup"
122+
project_path = Path.join(tmp_dir, project_name)
123+
124+
original_cwd = File.cwd!()
125+
126+
try do
127+
File.cd!(tmp_dir)
128+
129+
# Run igniter.new with --git and --sup flags
130+
{output, exit_code} =
131+
System.cmd(
132+
"mix",
133+
[
134+
"igniter.new",
135+
project_name,
136+
"--git",
137+
"--sup",
138+
"--yes",
139+
"--no-installer-version-check"
140+
],
141+
stderr_to_stdout: true,
142+
env: [{"MIX_ENV", "test"}]
143+
)
144+
145+
assert exit_code == 0,
146+
"Expected igniter.new to succeed, but got exit code #{exit_code}. Output: #{output}"
147+
148+
assert File.exists?(project_path)
149+
File.cd!(project_path)
150+
151+
# Verify git repository exists and is clean
152+
assert File.exists?(".git")
153+
{output, 0} = System.cmd("git", ["status", "--porcelain"])
154+
assert String.trim(output) == ""
155+
156+
# Verify project has supervision tree (--sup flag worked)
157+
mix_exs_content = File.read!("mix.exs")
158+
159+
assert String.contains?(mix_exs_content, "mod: {"),
160+
"Should have supervision tree when --sup is used"
161+
162+
# Verify commit exists
163+
{output, 0} = System.cmd("git", ["rev-list", "--count", "HEAD"])
164+
commit_count = String.trim(output) |> String.to_integer()
165+
assert commit_count >= 1, "Should have at least one commit"
166+
after
167+
File.cd!(original_cwd)
168+
end
169+
end
170+
end
171+
end
172+
173+
describe "handle missing git" do
174+
@tag :integration
175+
test "handles missing git gracefully in development", %{tmp_dir: tmp_dir} do
176+
# This test simulates what happens when git is not available
177+
# but --git flag is used. In practice, the initialize_git_repo function
178+
# will output error messages but not crash the entire task.
179+
180+
project_name = "test_project_no_git_binary"
181+
project_path = Path.join(tmp_dir, project_name)
182+
183+
original_cwd = File.cwd!()
184+
185+
try do
186+
File.cd!(tmp_dir)
187+
188+
# Create project first without git
189+
{_output, exit_code} =
190+
System.cmd(
191+
"mix",
192+
["igniter.new", project_name, "--yes", "--no-installer-version-check"],
193+
stderr_to_stdout: true,
194+
env: [{"MIX_ENV", "test"}]
195+
)
196+
197+
assert exit_code == 0
198+
assert File.exists?(project_path)
199+
200+
File.cd!(project_path)
201+
202+
# Now test that the git repo functionality produces appropriate output
203+
# when git commands fail (we can't easily simulate missing git binary in tests)
204+
if git_available?() do
205+
# At least verify that git operations would work in normal circumstances
206+
{_output, exit_code} = System.cmd("git", ["init"])
207+
assert exit_code == 0
208+
end
209+
after
210+
File.cd!(original_cwd)
211+
end
212+
end
213+
end
214+
215+
# Helper to ensure git is available for testing
216+
defp git_available? do
217+
case System.cmd("git", ["--version"]) do
218+
{_, 0} -> true
219+
_ -> false
220+
end
221+
end
222+
end

installer/test/test_helper.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ExUnit.start()

0 commit comments

Comments
 (0)