Skip to content

Commit 6db611e

Browse files
committed
chore: run tasks with Mix.shell().cmd/1 to avoid state issues
1 parent ec37905 commit 6db611e

2 files changed

Lines changed: 33 additions & 54 deletions

File tree

lib/igniter.ex

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,10 +2119,6 @@ defmodule Igniter do
21192119
end)
21202120
end
21212121

2122-
# Runs queued tasks with tracking. Builds a list of all tasks to run; as each
2123-
# completes successfully it is removed from the pending list. On compile or
2124-
# runtime failure, writes a concise error log (reason + tasks that did not run)
2125-
# and re-raises.
21262122
@doc false
21272123
def run_queued_tasks_with_tracking(tasks) when is_list(tasks) do
21282124
sort_tasks_with_delayed_last(tasks) |> run_next()
@@ -2131,41 +2127,29 @@ defmodule Igniter do
21312127
defp run_next([]), do: :ok
21322128

21332129
defp run_next([{task_name, args} | rest]) do
2134-
Mix.Task.reenable(task_name)
2135-
Enum.each(["compile", "app.config", "loadpaths"], &Mix.Task.reenable/1)
2136-
Mix.Task.run(task_name, args)
2137-
run_next(rest)
2138-
rescue
2139-
e ->
2140-
tasks_not_run = Enum.map([{task_name, args} | rest], &format_task_for_log/1)
2141-
error_log = format_task_failure_log(e, task_name, args, tasks_not_run)
2142-
Mix.shell().error("\n" <> error_log <> "\n")
2143-
reraise e, __STACKTRACE__
2144-
end
2145-
2146-
defp format_task_for_log({task_name, []}), do: "mix #{task_name}"
2147-
defp format_task_for_log({task_name, args}), do: "mix #{task_name} #{Enum.join(args, " ")}"
2148-
2149-
defp format_task_failure_log(exception, task_name, args, tasks_not_run) do
2150-
kind = failure_kind(exception)
21512130
task_invocation = format_task_for_log({task_name, args})
2152-
reason = Exception.message(exception)
2153-
2154-
lines = [
2155-
"Task failed (#{kind}): #{task_invocation}",
2156-
"Reason: #{reason}",
2157-
"",
2158-
"Tasks that did not run:",
2159-
Enum.map_join(tasks_not_run, "\n", fn t -> " • " <> t end)
2160-
]
21612131

2162-
Enum.join(lines, "\n")
2163-
end
2132+
case Mix.shell().cmd("mix #{task_name} #{Enum.join(args, " ")}") do
2133+
0 ->
2134+
run_next(rest)
2135+
2136+
exit_code ->
2137+
tasks_not_run = Enum.map([{task_name, args} | rest], &format_task_for_log/1)
21642138

2165-
defp failure_kind(%CompileError{}), do: "compile error"
2166-
defp failure_kind(%Mix.Error{}), do: "mix error"
2139+
error_log =
2140+
[
2141+
"Task failed (exit code #{exit_code}): #{task_invocation}",
2142+
"",
2143+
"Tasks that did not run:",
2144+
Enum.map_join(tasks_not_run, "\n", fn t -> " • " <> t end)
2145+
]
2146+
|> Enum.join("\n")
21672147

2168-
defp failure_kind(_) do
2169-
"runtime error"
2148+
Mix.shell().error("\n" <> error_log <> "\n")
2149+
raise Mix.Error, message: "#{task_invocation} exited with code #{exit_code}"
2150+
end
21702151
end
2152+
2153+
defp format_task_for_log({task_name, []}), do: "mix #{task_name}"
2154+
defp format_task_for_log({task_name, args}), do: "mix #{task_name} #{Enum.join(args, " ")}"
21712155
end

test/igniter_test.exs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,11 @@ defmodule IgniterTest do
371371
end
372372

373373
describe "run_queued_tasks_with_tracking/1" do
374+
setup do
375+
Mix.shell(Mix.Shell.Process)
376+
on_exit(fn -> Mix.shell(Mix.Shell.IO) end)
377+
end
378+
374379
test "empty list returns :ok and runs nothing" do
375380
assert :ok == Igniter.run_queued_tasks_with_tracking([])
376381
end
@@ -393,29 +398,19 @@ defmodule IgniterTest do
393398
assert :ok == Igniter.run_queued_tasks_with_tracking(tasks_with_delayed)
394399
end
395400

396-
test "on task failure, logs concise error with reason and tasks that did not run, then re-raises" do
397-
output =
398-
capture_io(:stderr, fn ->
399-
try do
400-
Igniter.run_queued_tasks_with_tracking([
401-
{"nonexistent.task.xyz.igniter_test", []},
402-
{"compile", []}
403-
])
404-
rescue
405-
_ -> :rescued
406-
end
407-
end)
401+
test "on task failure, logs error with task info and tasks that did not run, then raises" do
402+
assert_raise Mix.Error, fn ->
403+
Igniter.run_queued_tasks_with_tracking([
404+
{"nonexistent.task.xyz.igniter_test", []},
405+
{"compile", []}
406+
])
407+
end
408408

409+
assert_received {:mix_shell, :error, [output]}
409410
assert output =~ "Task failed"
410411
assert output =~ "Tasks that did not run"
411412
assert output =~ "mix nonexistent.task.xyz.igniter_test"
412413
assert output =~ "mix compile"
413414
end
414-
415-
test "on task failure, exception is re-raised" do
416-
assert_raise Mix.NoTaskError, fn ->
417-
Igniter.run_queued_tasks_with_tracking([{"nonexistent.task.xyz.igniter_test", []}])
418-
end
419-
end
420415
end
421416
end

0 commit comments

Comments
 (0)