Add deps.check

This commit is contained in:
José Valim
2012-07-19 11:46:19 +02:00
parent 8736dc61eb
commit 3e1bd2bfaa
9 changed files with 129 additions and 17 deletions
+1 -1
View File
@@ -266,7 +266,7 @@ defmodule ExUnit.Assertions do
if name == ExUnit.AssertionError do
raise(error)
else
flunk "Expected exception #{inspect exception}, got #{inspect name}"
flunk "Expected exception #{inspect exception}, got #{inspect name} (#{error.message})"
end
end
end
+2 -2
View File
@@ -188,7 +188,7 @@ defmodule ExUnit.AssertionsTest do
end
rescue
error in [ExUnit.AssertionError] ->
"Expected exception ArgumentError, got UndefinedFunctionError" = error.message
"Expected exception ArgumentError, got UndefinedFunctionError (undefined function: Certainly.Undefined.function/3)" = error.message
end
end
@@ -199,7 +199,7 @@ defmodule ExUnit.AssertionsTest do
end
rescue
error in [ExUnit.AssertionError] ->
"Expected exception SyntaxError, got FunctionClauseError" = error.message
"Expected exception SyntaxError, got FunctionClauseError (no function clause matching: :lists.flatten(1))" = error.message
end
end
+1 -1
View File
@@ -2,7 +2,7 @@ defmodule Mix.CLI do
@moduledoc false
defmacrop exceptions do
[Mix.Error, Mix.NoTaskError, Mix.InvalidTaskError, Mix.NoProjectError]
[Mix.Error, Mix.NoTaskError, Mix.InvalidTaskError, Mix.NoProjectError, Mix.NotMetDepsError]
end
@doc """
+3 -1
View File
@@ -12,4 +12,6 @@ end
defexception Mix.NoProjectError, message: "Could not find a Mix.Project"
defexception Mix.Error, message: nil
defexception Mix.Error, message: nil
defexception Mix.NotMetDepsError, message: "Some dependencies were not met"
+1 -1
View File
@@ -1,5 +1,5 @@
defmodule Mix.SCM.Git do
def cloned?(path) do
def available?(path) do
File.dir?(File.join(path, ".git"))
end
end
+32
View File
@@ -0,0 +1,32 @@
defmodule Mix.Tasks.Deps.Check do
use Mix.Task
import Mix.Tasks.Deps, [all: 0, format_dep: 1, format_status: 1]
@moduledoc """
Checks if all dependencies are valid and if not, abort.
Prints the invalid dependencies status before aborting.
This task is not exhibited in `mix help` but it is part
of mix public API and can be depended on.
"""
def run(_) do
case Enum.partition all, match?({ _, _, _, { :ok, _ }, _ }, &1) do
{ _, [] } -> :ok
{ _, not_ok } ->
if Enum.all? not_ok, match?({ _, _, _, { :unavailable, _ }, _ }, &1) do
raise Mix.NotMetDepsError, message:
"Dependencies are not available, run `mix deps.get` before proceeding"
else
shell = Mix.shell
Enum.each not_ok, fn(dep) ->
shell.error "* #{format_dep(dep)}"
shell.error " #{format_status elem(dep, 4)}"
end
raise Mix.NotMetDepsError
end
end
end
end
+16 -8
View File
@@ -3,6 +3,10 @@ defmodule Mix.Tasks.Deps do
@shortdoc "List dependencies and their status"
@moduledoc """
List all dependencies and their status.
"""
@doc """
Returns all dependencies in the following format:
@@ -24,18 +28,25 @@ defmodule Mix.Tasks.Deps do
Enum.map deps, with_scm_and_status(&1)
end
@doc """
Get all dependencies that match the specific `status`.
"""
def all(status) do
Enum.filter all, match?({ _, _, _, { ^status, _ }, _ }, &1)
end
@doc """
Formats the status of a dependency. It can be either:
* `{ :ok, vsn }` - Everything is :ok, got version `vsn`;
* `{ :uncloned, path }` - The dependency is not checked out;
* `{ :unavailable, path }` - The dependency is not available;
* `{ :noappfile, path }` - The .app file at path could not be found;
* `{ :invalidapp, path }` - The .app file at path is not properly formatted;
* `{ :invalidvsn, actual }` - The dependency does not match the specified requirement, got `actual`;
"""
def format_status({ :ok, _vsn }), do: "ok"
def format_status({ :uncloned, path }), do: "the dependency is not checked out at: #{path}"
def format_status({ :unavailable, _ }), do: "the dependency is not available, run `mix deps.get`"
def format_status({ :noappfile, path }), do: "could not find app file at #{path}"
def format_status({ :invalidapp, path }), do: "the app file at #{path} is invalid"
def format_status({ :invalidvsn, vsn }), do: "the dependency does not match the specified version, got #{vsn}"
@@ -57,13 +68,10 @@ defmodule Mix.Tasks.Deps do
"#{app} #{version}[#{opts}]"
end
@doc """
"""
def run(_) do
shell = Mix.shell
Enum.map all, fn(dep) ->
Enum.each all, fn(dep) ->
shell.info "* #{format_dep(dep)}"
shell.info " #{format_status elem(dep, 4)}"
end
@@ -97,11 +105,11 @@ defmodule Mix.Tasks.Deps do
defp status(scm, app, req, _) do
deps_path = deps_path(app)
if scm.cloned? deps_path do
if scm.available? deps_path do
app_path = File.join deps_path, "ebin/#{app}.app"
validate_app_file(app_path, app, req)
else
{ :uncloned, deps_path }
{ :unavailable, deps_path }
end
end
+1 -1
View File
@@ -1,5 +1,5 @@
defmodule Mix.Tasks.Deps.Get do
use Mix.Task
@shortdoc "Get uncloned dependencies"
@shortdoc "Get all unavailable dependencies"
end
+72 -2
View File
@@ -17,7 +17,28 @@ defmodule Mix.Tasks.DepsTest do
end
end
test "mix deps prints list of dependencies and their status" do
defmodule SuccessfulDepsApp do
def project do
[
deps: [
{ "ok", "0.1.0", git: "https://github.com/elixir-lang/ok.git" }
]
]
end
end
defmodule UnclonedDepsApp do
def project do
[
deps: [
{ "uncloned", "0.1.0", git: "https://github.com/elixir-lang/uncloned.git" }
]
]
end
end
test "prints list of dependencies and their status" do
Mix.Project.push DepsApp
in_fixture "deps_status", fn ->
@@ -32,7 +53,56 @@ defmodule Mix.Tasks.DepsTest do
assert_received { :mix_shell, :info, ["* noappfile [git: \"https://github.com/elixir-lang/noappfile.git\"]"] }
assert_received { :mix_shell, :info, [" could not find app file at deps/noappfile/ebin/noappfile.app"] }
assert_received { :mix_shell, :info, ["* uncloned [git: \"https://github.com/elixir-lang/uncloned.git\"]"] }
assert_received { :mix_shell, :info, [" the dependency is not checked out at: deps/uncloned"] }
assert_received { :mix_shell, :info, [" the dependency is not available, run `mix deps.get`"] }
end
after
Mix.Project.pop
end
test "check list of dependencies and their status on success" do
Mix.Project.push SuccessfulDepsApp
in_fixture "deps_status", fn ->
Mix.Tasks.Deps.Check.run []
end
after
Mix.Project.pop
end
test "check list of dependencies and their status on first run" do
Mix.Project.push UnclonedDepsApp
in_fixture "deps_status", fn ->
assert_raise Mix.NotMetDepsError, "Dependencies are not available, run `mix deps.get` before proceeding", fn ->
Mix.Tasks.Deps.Check.run []
end
refute_received { :mix_shell, :error, ["* uncloned [git: \"https://github.com/elixir-lang/uncloned.git\"]"] }
refute_received { :mix_shell, :error, [" the dependency is not available, run `mix deps.get`"] }
end
after
Mix.Project.pop
end
test "check list of dependencies and their status on failure" do
Mix.Project.push DepsApp
in_fixture "deps_status", fn ->
assert_raise Mix.NotMetDepsError, fn ->
Mix.Tasks.Deps.Check.run []
end
refute_received { :mix_shell, :error, ["* ok (0.1.0) [git: \"https://github.com/elixir-lang/ok.git\"]"] }
refute_received { :mix_shell, :error, [" ok"] }
assert_received { :mix_shell, :error, ["* invalidvsn [git: \"https://github.com/elixir-lang/invalidvsn.git\"]"] }
assert_received { :mix_shell, :error, [" the dependency does not match the specified version, got 0.1.0"] }
assert_received { :mix_shell, :error, ["* invalidapp [git: \"https://github.com/elixir-lang/invalidapp.git\"]"] }
assert_received { :mix_shell, :error, [" the app file at deps/invalidapp/ebin/invalidapp.app is invalid"] }
assert_received { :mix_shell, :error, ["* noappfile [git: \"https://github.com/elixir-lang/noappfile.git\"]"] }
assert_received { :mix_shell, :error, [" could not find app file at deps/noappfile/ebin/noappfile.app"] }
assert_received { :mix_shell, :error, ["* uncloned [git: \"https://github.com/elixir-lang/uncloned.git\"]"] }
assert_received { :mix_shell, :error, [" the dependency is not available, run `mix deps.get`"] }
end
after
Mix.Project.pop