From 089e315677fd122d71d8908b2a0621711e62ab2e Mon Sep 17 00:00:00 2001 From: bougyman's bot Date: Mon, 28 Sep 2026 21:37:52 -0400 Subject: [PATCH] chore: handle .local/bin/mise as priority --- .../lib/mix/tasks/stokowski.ex | 31 ++++++++++--- .../test/mix/tasks/stokowski_test.exs | 43 +++++++++++++++++-- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/apps/repo_management/lib/mix/tasks/stokowski.ex b/apps/repo_management/lib/mix/tasks/stokowski.ex index 1b4bc86..3a658f4 100644 --- a/apps/repo_management/lib/mix/tasks/stokowski.ex +++ b/apps/repo_management/lib/mix/tasks/stokowski.ex @@ -29,11 +29,12 @@ defmodule Mix.Tasks.Stokowski do ensure_vendor!(vendor) validate_api_key!(workflow) - resolved_runners = resolve_configured_runners!(workflow, root) + mise = mise_executable!() + resolved_runners = resolve_configured_runners!(workflow, root, mise) uv = executable!("uv") - runner_executables = - Enum.map(resolved_runners, fn {_runner, {executable, _version}} -> executable end) + path_executables = + [mise | Enum.map(resolved_runners, fn {_runner, {executable, _version}} -> executable end)] Enum.each(resolved_runners, fn {runner, {executable, version}} -> Mix.shell().info("Using #{String.capitalize(runner)} #{version} at #{executable}") @@ -48,7 +49,7 @@ defmodule Mix.Tasks.Stokowski do try do System.cmd(uv, command_args, cd: root, - env: [{"PATH", prepend_path(runner_executables)}], + env: [{"PATH", prepend_path(path_executables)}], stderr_to_stdout: true, into: IO.stream(:stdio, :line) ) @@ -70,8 +71,11 @@ defmodule Mix.Tasks.Stokowski do @doc false def resolve_runner!(root, runner) when runner in ["codex", "claude"] do + resolve_runner!(root, runner, mise_executable!()) + end + + defp resolve_runner!(root, runner, mise) do expected_version = configured_runner_version!(Path.join(root, "mise.toml"), runner) - mise = executable!("mise") case System.cmd(mise, ["which", runner], cd: root) do {output, 0} -> @@ -132,7 +136,20 @@ defmodule Mix.Tasks.Stokowski do end end - defp resolve_configured_runners!(workflow, root) do + defp mise_executable! do + local_mise = + case System.get_env("HOME") do + home when is_binary(home) and home != "" -> + System.find_executable(Path.join([home, ".local", "bin", "mise"])) + + _missing_home -> + nil + end + + local_mise || executable!("mise") + end + + defp resolve_configured_runners!(workflow, root, mise) do runner_names = case Workflow.read(workflow) do {:ok, parsed_workflow} -> Workflow.runner_values(parsed_workflow) |> Enum.uniq() @@ -146,7 +163,7 @@ defmodule Mix.Tasks.Stokowski do Mix.raise("workflow.yaml uses unsupported runner #{inspect(runner)}") end - {runner, resolve_runner!(root, runner)} + {runner, resolve_runner!(root, runner, mise)} end) end diff --git a/apps/repo_management/test/mix/tasks/stokowski_test.exs b/apps/repo_management/test/mix/tasks/stokowski_test.exs index ddbc649..198a992 100644 --- a/apps/repo_management/test/mix/tasks/stokowski_test.exs +++ b/apps/repo_management/test/mix/tasks/stokowski_test.exs @@ -41,6 +41,25 @@ defmodule Mix.Tasks.StokowskiTest do refute File.exists?(Path.join(vendor, "uv.lock")) end + @tag :tmp_dir + test "prefers user-local mise and prepends it to the runner path", %{tmp_dir: tmp_dir} do + {root, vendor, _invocation} = fake_checkout(tmp_dir, 0) + + capture_io(fn -> StokowskiTask.run([], root) end) + + path = + vendor + |> Path.join("path.log") + |> File.read!() + |> String.trim() + |> String.split(":") + + assert Enum.take(path, 2) == [ + Path.join([tmp_dir, "home", ".local", "bin"]), + Path.join(tmp_dir, "runner-bin") + ] + end + @tag :tmp_dir test "reports a nonzero exit and still removes the generated lockfile", %{tmp_dir: tmp_dir} do {root, vendor, _invocation} = fake_checkout(tmp_dir, 23) @@ -151,7 +170,7 @@ defmodule Mix.Tasks.StokowskiTest do @tag :tmp_dir test "accepts prerelease Claude pins", %{tmp_dir: tmp_dir} do {root, _vendor, _invocation} = fake_checkout(tmp_dir, 0) - claude = Path.join(tmp_dir, "bin/claude") + claude = Path.join(tmp_dir, "runner-bin/claude") File.write!(claude, "#!/bin/sh\nprintf '%s\\n' '2.1.270-rc.1 (Claude Code)'\n") File.chmod!(claude, 0o755) @@ -188,10 +207,15 @@ defmodule Mix.Tasks.StokowskiTest do root = Path.join(tmp_dir, "repo") vendor = Path.join([root, "vendor", "stokowski"]) bin = Path.join(tmp_dir, "bin") + home = Path.join(tmp_dir, "home") + mise_bin = Path.join([home, ".local", "bin"]) + runner_bin = Path.join(tmp_dir, "runner-bin") invocation = Path.join(vendor, "invocation.log") File.mkdir_p!(vendor) File.mkdir_p!(bin) + File.mkdir_p!(mise_bin) + File.mkdir_p!(runner_bin) File.write!(Path.join(root, "workflow.yaml"), "tracker: {kind: linear}\n") File.write!( @@ -209,6 +233,7 @@ defmodule Mix.Tasks.StokowskiTest do pwd printf '%s\\n' "$@" } > "$3/invocation.log" + printf '%s\\n' "$PATH" > "$3/path.log" : > "$3/uv.lock" printf 'fake uv stdout\\n' printf 'fake uv stderr\\n' >&2 @@ -216,14 +241,14 @@ defmodule Mix.Tasks.StokowskiTest do """ ) - codex = Path.join(bin, "codex") + codex = Path.join(runner_bin, "codex") write_executable!(codex, "#!/bin/sh\nprintf '%s\\n' '#{codex_version}'\n") - claude = Path.join(bin, "claude") + claude = Path.join(runner_bin, "claude") write_executable!(claude, "#!/bin/sh\nprintf '%s\\n' '2.1.270 (Claude Code)'\n") write_executable!( - Path.join(bin, "mise"), + Path.join(mise_bin, "mise"), """ #!/bin/sh case "$1 $2" in @@ -234,8 +259,12 @@ defmodule Mix.Tasks.StokowskiTest do """ ) + write_executable!(Path.join(bin, "mise"), "#!/bin/sh\nexit 86\n") + original_path = System.get_env("PATH") + original_home = System.get_env("HOME") System.put_env("PATH", Enum.join([bin, original_path], ":")) + System.put_env("HOME", home) on_exit(fn -> if original_path do @@ -243,6 +272,12 @@ defmodule Mix.Tasks.StokowskiTest do else System.delete_env("PATH") end + + if original_home do + System.put_env("HOME", original_home) + else + System.delete_env("HOME") + end end) {root, vendor, invocation}