diff --git a/lib/mix/lib/mix/tasks/cmd.ex b/lib/mix/lib/mix/tasks/cmd.ex index 5749c1b3e7..cd10b8fb77 100644 --- a/lib/mix/lib/mix/tasks/cmd.ex +++ b/lib/mix/lib/mix/tasks/cmd.ex @@ -75,9 +75,19 @@ defmodule Mix.Tasks.Cmd do end if apps == [] or Mix.Project.config()[:app] in apps do + path = hd(args) + rest = tl(args) + + path = + if String.contains?(path, ["/", "\\"]) and Path.type(path) != :absolute do + Path.expand(path, Keyword.get(opts, :cd, ".")) + else + path + end + cmd_opts = Keyword.take(opts, [:cd]) - case Mix.shell().cmd({hd(args), tl(args)}, cmd_opts) do + case Mix.shell().cmd({path, rest}, cmd_opts) do 0 -> :ok status -> exit(status) end diff --git a/lib/mix/test/mix/tasks/cmd_test.exs b/lib/mix/test/mix/tasks/cmd_test.exs index 397fa0f923..8579846318 100644 --- a/lib/mix/test/mix/tasks/cmd_test.exs +++ b/lib/mix/test/mix/tasks/cmd_test.exs @@ -14,6 +14,21 @@ defmodule Mix.Tasks.CmdTest do assert_received {:mix_shell, :run, ["hello world\n"]} end + @tag :unix + test "supports relative paths" do + in_tmp("cmd-relative", fn -> + File.mkdir_p!("priv") + File.write!("priv/world.sh", "#!/bin/sh\necho world") + File.chmod!("priv/world.sh", 0o755) + + Mix.Task.run("cmd", ["priv/world.sh"]) + assert_received {:mix_shell, :run, ["world\n"]} + + Mix.Task.run("cmd", ["--cd", "priv", "./world.sh"]) + assert_received {:mix_shell, :run, ["world\n"]} + end) + end + test "runs the command for each app" do in_fixture("umbrella_dep/deps/umbrella", fn -> Mix.Project.in_project(:umbrella, ".", fn _ ->