summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--src/rebar.app.src2
-rw-r--r--src/rebar.hrl4
-rw-r--r--src/rebar_app_info.erl11
-rw-r--r--src/rebar_core.erl8
-rw-r--r--src/rebar_dir.erl13
-rw-r--r--src/rebar_prv_eunit.erl220
-rw-r--r--src/rebar_prv_install_deps.erl96
-rw-r--r--src/rebar_prv_lock.erl20
-rw-r--r--src/rebar_prv_new.erl15
-rw-r--r--src/rebar_prv_release.erl2
-rw-r--r--src/rebar_state.erl66
-rw-r--r--src/rebar_templater.erl2
-rw-r--r--src/rebar_utils.erl1
-rw-r--r--test/mock_git_resource.erl4
-rw-r--r--test/mock_pkg_resource.erl6
-rw-r--r--test/rebar_as_SUITE.erl22
-rw-r--r--test/rebar_compile_SUITE.erl127
-rw-r--r--test/rebar_eunit_SUITE.erl379
-rw-r--r--test/rebar_new_SUITE.erl26
-rw-r--r--test/rebar_opts_parser_SUITE.erl54
-rw-r--r--test/rebar_profiles_SUITE.erl19
-rw-r--r--test/rebar_release_SUITE.erl46
-rw-r--r--test/rebar_test_utils.erl44
24 files changed, 1030 insertions, 159 deletions
diff --git a/README.md b/README.md
index b738850..5465a4b 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ configuration work. rebar also provides dependency management, enabling
application writers to easily re-use common libraries from a variety of
locations (git, hg, etc).
-3.0 Alpha
+3.0 Alpha-2
====
[DOCUMENTATION](http://www.rebar3.org/v3.0/docs)
diff --git a/src/rebar.app.src b/src/rebar.app.src
index 62cabf9..ee4bfd7 100644
--- a/src/rebar.app.src
+++ b/src/rebar.app.src
@@ -3,7 +3,7 @@
{application, rebar,
[{description, "Rebar: Erlang Build Tool"},
- {vsn, "3.0.0-alpha"},
+ {vsn, "3.0.0-alpha-2"},
{modules, []},
{registered, []},
{applications, [kernel,
diff --git a/src/rebar.hrl b/src/rebar.hrl
index 0dfcad0..1f051d7 100644
--- a/src/rebar.hrl
+++ b/src/rebar.hrl
@@ -14,7 +14,9 @@
-define(FMT(Str, Args), lists:flatten(io_lib:format(Str, Args))).
-define(DEFAULT_BASE_DIR, "_build").
--define(DEFAULT_PROJECT_APP_DIRS, ["_checkouts", "apps", "lib", "."]).
+-define(DEFAULT_ROOT_DIR, ".").
+-define(DEFAULT_PROJECT_APP_DIRS, ["apps", "lib", "."]).
+-define(DEFAULT_CHECKOUTS_DIR, "_checkouts").
-define(DEFAULT_DEPS_DIR, "lib").
-define(DEFAULT_PLUGINS_DIR, "plugins").
-define(DEFAULT_TEST_DEPS_DIR, "test/lib").
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl
index 99bc25b..9659c0b 100644
--- a/src/rebar_app_info.erl
+++ b/src/rebar_app_info.erl
@@ -34,6 +34,8 @@
source/2,
state/1,
state/2,
+ is_checkout/1,
+ is_checkout/2,
valid/1,
valid/2]).
@@ -53,6 +55,7 @@
out_dir :: file:name(),
source :: string() | tuple() | undefined,
state :: rebar_state:t() | undefined,
+ is_checkout=false :: boolean(),
valid :: boolean()}).
%%============================================================================
@@ -238,6 +241,14 @@ state(AppInfo=#app_info_t{}, State) ->
state(#app_info_t{state=State}) ->
State.
+-spec is_checkout(t(), boolean()) -> t().
+is_checkout(AppInfo=#app_info_t{}, IsCheckout) ->
+ AppInfo#app_info_t{is_checkout=IsCheckout}.
+
+-spec is_checkout(t()) -> boolean().
+is_checkout(#app_info_t{is_checkout=IsCheckout}) ->
+ IsCheckout.
+
-spec valid(t()) -> boolean().
valid(AppInfo=#app_info_t{valid=undefined}) ->
case rebar_app_utils:validate_application_info(AppInfo) of
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index db82766..6abab68 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -82,6 +82,8 @@ process_command(State, Command) ->
case Command of
do ->
do(TargetProviders, State);
+ as ->
+ do(TargetProviders, State);
_ ->
Profiles = providers:profiles(CommandProvider),
State1 = rebar_state:apply_profiles(State, Profiles),
@@ -91,7 +93,11 @@ process_command(State, Command) ->
State2 = rebar_state:command_parsed_args(State1, Args),
do(TargetProviders, State2);
{error, {invalid_option, Option}} ->
- {error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])}
+ {error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])};
+ {error, {invalid_option_arg, {Option, Arg}}} ->
+ {error, io_lib:format("Invalid argument ~s to option ~s", [Arg, Option])};
+ {error, {missing_option_arg, Option}} ->
+ {error, io_lib:format("Missing argument to option ~s", [Option])}
end
end
end.
diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl
index 628ebd3..4a9bf09 100644
--- a/src/rebar_dir.erl
+++ b/src/rebar_dir.erl
@@ -3,6 +3,8 @@
-export([base_dir/1,
deps_dir/1,
deps_dir/2,
+ checkouts_dir/1,
+ checkouts_dir/2,
plugins_dir/1,
lib_dirs/1,
home_dir/0,
@@ -40,6 +42,17 @@ deps_dir(State) ->
deps_dir(DepsDir, App) ->
filename:join(DepsDir, App).
+root_dir(State) ->
+ rebar_state:get(State, root_dir, ?DEFAULT_ROOT_DIR).
+
+-spec checkouts_dir(rebar_state:t()) -> file:filename_all().
+checkouts_dir(State) ->
+ filename:join(root_dir(State), rebar_state:get(State, checkouts_dir, ?DEFAULT_CHECKOUTS_DIR)).
+
+-spec checkouts_dir(rebar_state:t(), file:filename_all()) -> file:filename_all().
+checkouts_dir(State, App) ->
+ filename:join(checkouts_dir(State), App).
+
-spec plugins_dir(rebar_state:t()) -> file:filename_all().
plugins_dir(State) ->
case lists:member(global, rebar_state:current_profiles(State)) of
diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl
index 0e0e937..6872c99 100644
--- a/src/rebar_prv_eunit.erl
+++ b/src/rebar_prv_eunit.erl
@@ -37,13 +37,14 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
?INFO("Performing EUnit tests...", []),
- {Opts, _} = rebar_state:command_parsed_args(State),
- EUnitOpts = resolve_eunit_opts(State, Opts),
- TestApps = filter_checkouts(rebar_state:project_apps(State)),
- ok = compile_tests(State, TestApps),
- ok = maybe_cover_compile(State, Opts),
- AppsToTest = test_dirs(State, TestApps),
- Result = eunit:test(AppsToTest, EUnitOpts),
+ case prepare_tests(State) of
+ {ok, Tests} -> do_tests(State, Tests);
+ Error -> Error
+ end.
+
+do_tests(State, Tests) ->
+ EUnitOpts = resolve_eunit_opts(State),
+ Result = eunit:test(Tests, EUnitOpts),
ok = rebar_prv_cover:maybe_write_coverdata(State, ?PROVIDER),
case handle_results(Result) of
{error, Reason} ->
@@ -58,45 +59,9 @@ format_error(unknown_error) ->
format_error({error_running_tests, Reason}) ->
io_lib:format("Error running tests: ~p", [Reason]).
-eunit_opts(_State) ->
- [{cover, $c, "cover", boolean, help(cover)},
- {verbose, $v, "verbose", boolean, help(verbose)}].
-
-help(cover) -> "Generate cover data";
-help(verbose) -> "Verbose output".
-
-filter_checkouts(Apps) -> filter_checkouts(Apps, []).
-
-filter_checkouts([], Acc) -> lists:reverse(Acc);
-filter_checkouts([App|Rest], Acc) ->
- AppDir = filename:absname(rebar_app_info:dir(App)),
- CheckoutsDir = filename:absname("_checkouts"),
- case lists:prefix(CheckoutsDir, AppDir) of
- true -> filter_checkouts(Rest, Acc);
- false -> filter_checkouts(Rest, [App|Acc])
- end.
-
-resolve_eunit_opts(State, Opts) ->
- EUnitOpts = rebar_state:get(State, eunit_opts, []),
- case proplists:get_value(verbose, Opts, false) of
- true -> set_verbose(EUnitOpts);
- false -> EUnitOpts
- end.
-
-test_dirs(State, TestApps) ->
- %% we need to add "./ebin" if it exists but only if it's not already
- %% due to be added
- F = fun(App) -> rebar_app_info:dir(App) =/= rebar_dir:get_cwd() end,
- BareEbin = filename:join([rebar_dir:base_dir(State), "ebin"]),
- case lists:any(F, TestApps) andalso filelib:is_dir(BareEbin) of
- false -> application_dirs(TestApps, []);
- true -> [{dir, BareEbin}|application_dirs(TestApps, [])]
- end.
-
-application_dirs([], Acc) -> lists:reverse(Acc);
-application_dirs([App|Rest], Acc) ->
- AppName = list_to_atom(binary_to_list(rebar_app_info:name(App))),
- application_dirs(Rest, [{application, AppName}|Acc]).
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
test_state(State) ->
ErlOpts = rebar_state:get(State, eunit_compile_opts, []),
@@ -120,14 +85,33 @@ first_files(State) ->
EUnitFirst = rebar_state:get(State, eunit_first_files, []),
[{erl_first_files, EUnitFirst}].
-set_verbose(Opts) ->
- %% if `verbose` is already set don't set it again
- case lists:member(verbose, Opts) of
- true -> Opts;
- false -> [verbose] ++ Opts
+prepare_tests(State) ->
+ {RawOpts, _} = rebar_state:command_parsed_args(State),
+ resolve_apps(State, RawOpts).
+
+resolve_apps(State, RawOpts) ->
+ case proplists:get_value(app, RawOpts) of
+ undefined -> resolve_suites(State, project_apps(State), RawOpts);
+ %% convert app name strings to `rebar_app_info` objects
+ Apps -> AppNames = string:tokens(Apps, [$,]),
+ ProjectApps = project_apps(State),
+ case filter_apps_by_name(AppNames, ProjectApps) of
+ {ok, TestApps} -> resolve_suites(State, TestApps, RawOpts);
+ Error -> Error
+ end
+ end.
+
+resolve_suites(State, Apps, RawOpts) ->
+ case proplists:get_value(suite, RawOpts) of
+ undefined -> compile_tests(State, Apps, all, RawOpts);
+ Suites -> SuiteNames = string:tokens(Suites, [$,]),
+ case filter_suites_by_apps(SuiteNames, Apps) of
+ {ok, S} -> compile_tests(State, Apps, S, RawOpts);
+ Error -> Error
+ end
end.
-compile_tests(State, TestApps) ->
+compile_tests(State, TestApps, Suites, RawOpts) ->
F = fun(AppInfo) ->
AppDir = rebar_app_info:dir(AppInfo),
S = case rebar_app_info:state(AppInfo) of
@@ -141,24 +125,80 @@ compile_tests(State, TestApps) ->
ec_cnv:to_list(rebar_app_info:out_dir(AppInfo)))
end,
lists:foreach(F, TestApps),
- case filelib:is_dir(filename:join([rebar_dir:get_cwd(), "test"])) of
- true -> compile_bare_tests(State, TestApps);
- false -> ok
+ ok = maybe_cover_compile(State, RawOpts),
+ {ok, test_set(TestApps, Suites)}.
+
+maybe_cover_compile(State, Opts) ->
+ State1 = case proplists:get_value(cover, Opts, false) of
+ true -> rebar_state:set(State, cover_enabled, true);
+ false -> State
+ end,
+ rebar_prv_cover:maybe_cover_compile(State1).
+
+project_apps(State) ->
+ filter_checkouts(rebar_state:project_apps(State)).
+
+filter_checkouts(Apps) -> filter_checkouts(Apps, []).
+
+filter_checkouts([], Acc) -> lists:reverse(Acc);
+filter_checkouts([App|Rest], Acc) ->
+ case rebar_app_info:is_checkout(App) of
+ true -> filter_checkouts(Rest, Acc);
+ false -> filter_checkouts(Rest, [App|Acc])
+ end.
+
+%% make sure applications specified actually exist
+filter_apps_by_name(AppNames, ProjectApps) ->
+ filter_apps_by_name(AppNames, ProjectApps, []).
+
+filter_apps_by_name([], _ProjectApps, Acc) -> {ok, lists:reverse(Acc)};
+filter_apps_by_name([Name|Rest], ProjectApps, Acc) ->
+ case find_app_by_name(Name, ProjectApps) of
+ {error, app_not_found} ->
+ ?PRV_ERROR({error_running_tests,
+ "Application `" ++ Name ++ "' not found in project."});
+ App ->
+ filter_apps_by_name(Rest, ProjectApps, [App|Acc])
+ end.
+
+find_app_by_name(_, []) -> {error, app_not_found};
+find_app_by_name(Name, [App|Rest]) ->
+ case Name == binary_to_list(rebar_app_info:name(App)) of
+ true -> App;
+ false -> find_app_by_name(Name, Rest)
+ end.
+
+%% ensure specified suites are in the applications included
+filter_suites_by_apps(Suites, ProjectApps) ->
+ filter_suites_by_apps(Suites, ProjectApps, []).
+
+filter_suites_by_apps([], _ProjectApps, Acc) -> {ok, lists:reverse(Acc)};
+filter_suites_by_apps([Suite|Rest], Apps, Acc) ->
+ Modules = app_modules([binary_to_atom(rebar_app_info:name(A), unicode) || A <- Apps], []),
+ case lists:member(list_to_atom(Suite), Modules) of
+ false ->
+ ?PRV_ERROR({error_running_tests,
+ "Module `" ++ Suite ++ "' not found in applications."});
+ true ->
+ filter_suites_by_apps(Rest, Apps, [Suite|Acc])
end.
-compile_bare_tests(State, TestApps) ->
- F = fun(App) -> rebar_app_info:dir(App) == rebar_dir:get_cwd() end,
- case lists:filter(F, TestApps) of
- %% compile and link just the `test` directory of the base dir
- [] ->
- Source = filename:join([rebar_dir:get_cwd(), "test"]),
- Target = filename:join([rebar_dir:base_dir(State), "test"]),
- ok = rebar_file_utils:symlink_or_copy(Source, Target),
- rebar_erlc_compiler:compile(replace_src_dirs(State),
- rebar_dir:base_dir(State),
- filename:join([rebar_dir:base_dir(State), "ebin"]));
- %% already compiled `./test` so do nothing
- _ -> ok
+app_modules([], Acc) -> Acc;
+app_modules([App|Rest], Acc) ->
+ Unload = case application:load(App) of
+ ok -> true;
+ {error, {already_loaded, _}} -> false
+ end,
+ NewAcc = case application:get_key(App, modules) of
+ {ok, Modules} -> Modules ++ Acc;
+ undefined -> Acc
+ end,
+ case Unload of
+ true ->
+ application:unload(App),
+ app_modules(Rest, NewAcc);
+ false ->
+ app_modules(Rest, NewAcc)
end.
replace_src_dirs(State) ->
@@ -167,15 +207,47 @@ replace_src_dirs(State) ->
StrippedOpts = lists:keydelete(src_dirs, 1, ErlOpts),
rebar_state:set(State, erl_opts, [{src_dirs, ["test"]}|StrippedOpts]).
-maybe_cover_compile(State, Opts) ->
- State1 = case proplists:get_value(cover, Opts, false) of
- true -> rebar_state:set(State, cover_enabled, true);
- false -> State
- end,
- rebar_prv_cover:maybe_cover_compile(State1).
+test_set(Apps, all) -> set_apps(Apps, []);
+test_set(_Apps, Suites) -> set_suites(Suites, []).
+
+set_apps([], Acc) -> lists:reverse(Acc);
+set_apps([App|Rest], Acc) ->
+ AppName = list_to_atom(binary_to_list(rebar_app_info:name(App))),
+ set_apps(Rest, [{application, AppName}|Acc]).
+
+set_suites([], Acc) -> lists:reverse(Acc);
+set_suites([Suite|Rest], Acc) ->
+ set_suites(Rest, [{module, list_to_atom(Suite)}|Acc]).
+
+resolve_eunit_opts(State) ->
+ {Opts, _} = rebar_state:command_parsed_args(State),
+ EUnitOpts = rebar_state:get(State, eunit_opts, []),
+ case proplists:get_value(verbose, Opts, false) of
+ true -> set_verbose(EUnitOpts);
+ false -> EUnitOpts
+ end.
+
+set_verbose(Opts) ->
+ %% if `verbose` is already set don't set it again
+ case lists:member(verbose, Opts) of
+ true -> Opts;
+ false -> [verbose] ++ Opts
+ end.
handle_results(ok) -> ok;
handle_results(error) ->
{error, unknown_error};
handle_results({error, Reason}) ->
{error, {error_running_tests, Reason}}.
+
+eunit_opts(_State) ->
+ [{app, undefined, "app", string, help(app)},
+ {cover, $c, "cover", boolean, help(cover)},
+ {suite, undefined, "suite", string, help(suite)},
+ {verbose, $v, "verbose", boolean, help(verbose)}].
+
+help(app) -> "List of application test suites to run";
+help(cover) -> "Generate cover data";
+help(suite) -> "List of test suites to run";
+help(verbose) -> "Verbose output".
+
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index e4a87ee..e92a3f0 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -174,7 +174,7 @@ compile_order(Source, ProjectApps) ->
case rebar_digraph:compile_order(Source) of
{ok, Sort} ->
%% Valid apps are compiled and good
- {ok, lists:dropwhile(fun rebar_app_info:valid/1, Sort -- ProjectApps)};
+ {ok, lists:dropwhile(fun not_needs_compile/1, Sort -- ProjectApps)};
{error, Error} ->
{error, Error}
end.
@@ -214,23 +214,28 @@ handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, State) -
{[AppInfo | Fetched], NewSeen, NewState}.
maybe_lock(Profile, AppInfo, Seen, State, Level) ->
- case Profile of
- default ->
- Name = rebar_app_info:name(AppInfo),
- case sets:is_element(Name, Seen) of
- false ->
- Locks = rebar_state:lock(State),
- case lists:any(fun(App) -> rebar_app_info:name(App) =:= Name end, Locks) of
- true ->
- {sets:add_element(Name, Seen), State};
+ case rebar_app_info:is_checkout(AppInfo) of
+ false ->
+ case Profile of
+ default ->
+ Name = rebar_app_info:name(AppInfo),
+ case sets:is_element(Name, Seen) of
false ->
- {sets:add_element(Name, Seen),
- rebar_state:lock(State, rebar_app_info:dep_level(AppInfo, Level))}
+ Locks = rebar_state:lock(State),
+ case lists:any(fun(App) -> rebar_app_info:name(App) =:= Name end, Locks) of
+ true ->
+ {sets:add_element(Name, Seen), State};
+ false ->
+ {sets:add_element(Name, Seen),
+ rebar_state:lock(State, rebar_app_info:dep_level(AppInfo, Level))}
+ end;
+ true ->
+ {Seen, State}
end;
- true ->
+ _ ->
{Seen, State}
end;
- _ ->
+ true ->
{Seen, State}
end.
@@ -367,7 +372,7 @@ handle_dep(State, DepsDir, AppInfo, Locks, Level) ->
maybe_fetch(AppInfo, Upgrade, Seen, State) ->
AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)),
%% Don't fetch dep if it exists in the _checkouts dir
- case in_checkouts(AppInfo) of
+ case rebar_app_info:is_checkout(AppInfo) of
true ->
false;
false ->
@@ -392,13 +397,6 @@ maybe_fetch(AppInfo, Upgrade, Seen, State) ->
end
end.
-in_checkouts(AppInfo) ->
- Apps = rebar_app_discover:find_apps(["_checkouts"], all),
- case rebar_app_utils:find(rebar_app_info:name(AppInfo), Apps) of
- {ok, _} -> true;
- error -> false
- end.
-
in_default(AppInfo, State) ->
Name = ec_cnv:to_list(rebar_app_info:name(AppInfo)),
DefaultAppDir = filename:join([rebar_state:get(State, base_dir), "default", "lib", Name]),
@@ -427,11 +425,25 @@ parse_deps(DepsDir, Deps, State, Locks, Level) ->
end
end, {[], []}, Deps).
-parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, _DepsDir, _State) when is_list(Vsn) ->
- {SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name)
- ,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]};
-parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, _DepsDir, _State) when is_atom(Name) ->
- {SrcDepsAcc, [ec_cnv:to_binary(Name) | PkgDepsAcc]};
+parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_list(Vsn) ->
+ CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
+ case rebar_app_info:discover(CheckoutsDir) of
+ {ok, _App} ->
+ Dep = new_dep(DepsDir, Name, [], [], State),
+ {[Dep | SrcDepsAcc], PkgDepsAcc};
+ not_found ->
+ {SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name)
+ ,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]}
+ end;
+parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_atom(Name) ->
+ CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
+ case rebar_app_info:discover(CheckoutsDir) of
+ {ok, _App} ->
+ Dep = new_dep(DepsDir, Name, [], [], State),
+ {[Dep | SrcDepsAcc], PkgDepsAcc};
+ not_found ->
+ {SrcDepsAcc, [ec_cnv:to_binary(Name) | PkgDepsAcc]}
+ end;
parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) ->
Dep = new_dep(DepsDir, Name, [], Source, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
@@ -445,8 +457,15 @@ parse_dep({Name, _Vsn, Source, Opts}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State)
?WARN("Dependency option list ~p in ~p is not supported and will be ignored", [Opts, Name]),
Dep = new_dep(DepsDir, Name, [], Source, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
-parse_dep({_Name, {pkg, Name, Vsn}, Level}, {SrcDepsAcc, PkgDepsAcc}, _, _) when is_integer(Level) ->
- {SrcDepsAcc, [{Name, Vsn} | PkgDepsAcc]};
+parse_dep({_Name, {pkg, Name, Vsn}, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_integer(Level) ->
+ CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
+ case rebar_app_info:discover(CheckoutsDir) of
+ {ok, _App} ->
+ Dep = new_dep(DepsDir, Name, [], [], State),
+ {[Dep | SrcDepsAcc], PkgDepsAcc};
+ not_found ->
+ {SrcDepsAcc, [{Name, Vsn} | PkgDepsAcc]}
+ end;
parse_dep({Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source)
, is_integer(Level) ->
Dep = new_dep(DepsDir, Name, [], Source, State),
@@ -456,12 +475,19 @@ parse_dep(Dep, _, _, _) ->
new_dep(DepsDir, Name, Vsn, Source, State) ->
- Dir = ec_cnv:to_list(filename:join(DepsDir, Name)),
- {ok, Dep} = case rebar_app_info:discover(Dir) of
+ CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
+ {ok, Dep} = case rebar_app_info:discover(CheckoutsDir) of
{ok, App} ->
- {ok, App};
+ {ok, rebar_app_info:is_checkout(App, true)};
not_found ->
- rebar_app_info:new(Name, Vsn, ec_cnv:to_list(filename:join(DepsDir, Name)))
+ Dir = ec_cnv:to_list(filename:join(DepsDir, Name)),
+ case rebar_app_info:discover(Dir) of
+ {ok, App} ->
+ {ok, App};
+ not_found ->
+ rebar_app_info:new(Name, Vsn,
+ ec_cnv:to_list(filename:join(DepsDir, Name)))
+ end
end,
C = rebar_config:consult(rebar_app_info:dir(Dep)),
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(Dep)),
@@ -528,3 +554,7 @@ warn_skip_pkg({Name, Source}, State) ->
false -> ?WARN(Msg, Args);
true -> ?ERROR(Msg, Args), ?FAIL
end.
+
+not_needs_compile(App) ->
+ not(rebar_app_info:is_checkout(App))
+ andalso rebar_app_info:valid(App).
diff --git a/src/rebar_prv_lock.erl b/src/rebar_prv_lock.erl
index 8a69434..e839168 100644
--- a/src/rebar_prv_lock.erl
+++ b/src/rebar_prv_lock.erl
@@ -30,16 +30,16 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
AllDeps = rebar_state:lock(State),
- Locks = lists:map(fun(Dep) ->
- Dir = rebar_app_info:dir(Dep),
- Source = rebar_app_info:source(Dep),
-
- %% If source is tuple it is a source dep
- %% e.g. {git, "git://github.com/ninenines/cowboy.git", "master"}
- {rebar_app_info:name(Dep)
- ,rebar_fetch:lock_source(Dir, Source)
- ,rebar_app_info:dep_level(Dep)}
- end, AllDeps),
+ Locks = [begin
+ Dir = rebar_app_info:dir(Dep),
+ Source = rebar_app_info:source(Dep),
+
+ %% If source is tuple it is a source dep
+ %% e.g. {git, "git://github.com/ninenines/cowboy.git", "master"}
+ {rebar_app_info:name(Dep)
+ ,rebar_fetch:lock_source(Dir, Source)
+ ,rebar_app_info:dep_level(Dep)}
+ end || Dep <- AllDeps, not(rebar_app_info:is_checkout(Dep))],
Dir = rebar_state:dir(State),
file:write_file(filename:join(Dir, ?LOCK_FILE), io_lib:format("~p.~n", [Locks])),
{ok, State}.
diff --git a/src/rebar_prv_new.erl b/src/rebar_prv_new.erl
index 77e100f..58e27fd 100644
--- a/src/rebar_prv_new.erl
+++ b/src/rebar_prv_new.erl
@@ -33,15 +33,24 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
case rebar_state:command_args(State) of
+ ["help"] ->
+ ?CONSOLE("Call `rebar3 new help <template>` for a detailed description~n", []),
+ show_short_templates(rebar_templater:list_templates(State)),
+ {ok, State};
["help", TemplateName] ->
case lists:keyfind(TemplateName, 1, rebar_templater:list_templates(State)) of
- false -> io:format("template not found.~n");
+ false -> ?CONSOLE("template not found.", []);
Term -> show_template(Term)
end,
{ok, State};
[TemplateName | Opts] ->
- Force = is_forced(State),
- ok = rebar_templater:new(TemplateName, parse_opts(Opts), Force, State),
+ case lists:keyfind(TemplateName, 1, rebar_templater:list_templates(State)) of
+ false ->
+ ?CONSOLE("template not found.", []);
+ _ ->
+ Force = is_forced(State),
+ ok = rebar_templater:new(TemplateName, parse_opts(Opts), Force, State)
+ end,
{ok, State};
[] ->
show_short_templates(rebar_templater:list_templates(State)),
diff --git a/src/rebar_prv_release.erl b/src/rebar_prv_release.erl
index 766bfe4..db012d5 100644
--- a/src/rebar_prv_release.erl
+++ b/src/rebar_prv_release.erl
@@ -47,7 +47,7 @@ do(State) ->
,{caller, Caller}], AllOptions);
Config ->
relx:main([{lib_dirs, LibDirs}
- ,{config, Config}
+ ,{config, lists:reverse(Config)}
,{output_dir, OutputDir}
,{caller, Caller}], AllOptions)
end,
diff --git a/src/rebar_state.erl b/src/rebar_state.erl
index fa0a963..cd127c0 100644
--- a/src/rebar_state.erl
+++ b/src/rebar_state.erl
@@ -240,7 +240,7 @@ merge_opts(NewOpts, OldOpts) ->
true ->
NewValue;
false ->
- lists:umerge(lists:sort(NewValue), lists:sort(OldValue))
+ tup_umerge(tup_sort(NewValue), tup_sort(OldValue))
end;
(_Key, NewValue, _OldValue) ->
NewValue
@@ -362,3 +362,67 @@ add_hook(pre, {PreHooks, PostHooks}, Hook) ->
{[Hook | PreHooks], PostHooks};
add_hook(post, {PreHooks, PostHooks}, Hook) ->
{PreHooks, [Hook | PostHooks]}.
+
+
+%% Sort the list in proplist-order, meaning that `{a,b}' and `{a,c}'
+%% both compare as usual, and `a' and `b' do the same, but `a' and `{a,b}' will
+%% compare based on the first element of the key, and in order. So the following
+%% list will sort as:
+%% - `[native, {native,o3}, check]' -> `[check, native, {native, o3}]'
+%% - `[native, {native,o3}, {native, o2}, check]' -> `[check,native,{native,o3},{native,o2}]'
+%% Meaning that:
+%% a) no deduplication takes place
+%% b) the key of a tuple is what counts in being sorted, but atoms are seen as {atom}
+%% as far as comparison is concerned (departing from lists:ukeysort/2)
+%% c) order is preserved for similar keys and tuples no matter their size (sort is stable)
+%%
+%% These properties let us merge proplists fairly easily.
+tup_sort(List) ->
+ lists:sort(fun(A, B) when is_tuple(A), is_tuple(B) -> element(1, A) =< element(1, B)
+ ; (A, B) when is_tuple(A) -> element(1, A) =< B
+ ; (A, B) when is_tuple(B) -> A =< element(1, B)
+ ; (A, B) -> A =< B
+ end, List).
+
+%% Custom merge functions. The objective is to behave like lists:umerge/2,
+%% except that we also compare the merge elements based on the key if they're a
+%% tuple, such that `{key, val1}' is always prioritized over `{key, val0}' if
+%% the former is from the 'new' list.
+%%
+%% This lets us apply proper overrides to list of elements according to profile
+%% priority. This function depends on a stable proplist sort.
+tup_umerge([], Olds) ->
+ Olds;
+tup_umerge([New|News], Olds) ->
+ lists:reverse(umerge(News, Olds, [], New)).
+
+%% This is equivalent to umerge2_2 in the stdlib, except we use the expanded
+%% value/key only to compare
+umerge(News, [Old|Olds], Merged, Cmp) when element(1, Cmp) == element(1, Old);
+ element(1, Cmp) == Old;
+ Cmp == element(1, Old);
+ Cmp =< Old ->
+ umerge(News, Olds, [Cmp | Merged], Cmp, Old);
+umerge(News, [Old|Olds], Merged, Cmp) ->
+ umerge(News, Olds, [Old | Merged], Cmp);
+umerge(News, [], Merged, Cmp) ->
+ lists:reverse(News, [Cmp | Merged]).
+
+%% Similar to stdlib's umerge2_1 in the stdlib, except that when the expanded
+%% value/keys compare equal, we check if the element is a full dupe to clear it
+%% (like the stdlib function does) or otherwise keep the duplicate around in
+%% an order that prioritizes 'New' elements.
+umerge([New|News], Olds, Merged, CmpMerged, Cmp) when CmpMerged == Cmp ->
+ umerge(News, Olds, Merged, New);
+umerge([New|News], Olds, Merged, _CmpMerged, Cmp) when element(1,New) == element(1, Cmp);
+ element(1,New) == Cmp;
+ New == element(1, Cmp);
+ New =< Cmp ->
+ umerge(News, Olds, [New | Merged], New, Cmp);
+umerge([New|News], Olds, Merged, _CmpMerged, Cmp) -> % >
+ umerge(News, Olds, [Cmp | Merged], New);
+umerge([], Olds, Merged, CmpMerged, Cmp) when CmpMerged == Cmp ->
+ lists:reverse(Olds, Merged);
+umerge([], Olds, Merged, _CmpMerged, Cmp) ->
+ lists:reverse(Olds, [Cmp | Merged]).
+
diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl
index 143c28b..75cbb87 100644
--- a/src/rebar_templater.erl
+++ b/src/rebar_templater.erl
@@ -156,7 +156,7 @@ default_author_and_email() ->
%% Ok, try mecurial
case rebar_utils:sh("hg showconfig ui.username", [return_on_error]) of
{ok, NameEmail} ->
- case re:run(NameEmail, [{capture, [1,2], list}]) of
+ case re:run(NameEmail, "^(.*) <(.*)>$", [{capture, [1,2], list}]) of
{match, [Name, Email]} ->
{Name, Email};
_ ->
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index 2f27fd3..df25997 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -387,6 +387,7 @@ beams(Dir) ->
-spec abort() -> no_return().
abort() ->
throw(rebar_abort).
+
-spec abort(string(), [term()]) -> no_return().
abort(String, Args) ->
?ERROR(String, Args),
diff --git a/test/mock_git_resource.erl b/test/mock_git_resource.erl
index 6940f54..9c799fd 100644
--- a/test/mock_git_resource.erl
+++ b/test/mock_git_resource.erl
@@ -55,7 +55,7 @@ mock_lock(_) ->
%% should be updated on a per-name basis: `{update, ["App1", "App3"]}'.
mock_update(Opts) ->
ToUpdate = proplists:get_value(upgrade, Opts, []),
- ct:pal("TOUp: ~p", [ToUpdate]),
+% ct:pal("TOUp: ~p", [ToUpdate]),
meck:expect(
?MOD, needs_update,
fun(_Dir, {git, Url, _Ref}) ->
@@ -110,7 +110,7 @@ mock_download(Opts) ->
AppDeps = proplists:get_value({App,Vsn}, Deps, []),
rebar_test_utils:create_app(
Dir, App, Vsn,
- [element(1,D) || D <- AppDeps]
+ [kernel, stdlib] ++ [element(1,D) || D <- AppDeps]
),
rebar_test_utils:create_config(Dir, [{deps, AppDeps}]),
{ok, 'WHATEVER'}
diff --git a/test/mock_pkg_resource.erl b/test/mock_pkg_resource.erl
index a22d1b0..afb6fb4 100644
--- a/test/mock_pkg_resource.erl
+++ b/test/mock_pkg_resource.erl
@@ -78,9 +78,9 @@ mock_download(Opts) ->
App = binary_to_list(AppBin),
filelib:ensure_dir(Dir),
AppDeps = proplists:get_value({App,Vsn}, Deps, []),
- {ok, AppInfo} = rebar_test_utils:create_empty_app(
- Dir, App, Vsn,
- [element(1,D) || D <- AppDeps]
+ {ok, AppInfo} = rebar_test_utils:create_app(
+ Dir, App, binary_to_list(Vsn),
+ [kernel, stdlib] ++ [element(1,D) || D <- AppDeps]
),
rebar_test_utils:create_config(Dir, [{deps, AppDeps}]),
Tarball = filename:join([Dir, App++"-"++binary_to_list(Vsn)++".tar"]),
diff --git a/test/rebar_as_SUITE.erl b/test/rebar_as_SUITE.erl
index 864d468..1d1112b 100644
--- a/test/rebar_as_SUITE.erl
+++ b/test/rebar_as_SUITE.erl
@@ -11,7 +11,8 @@
as_multiple_profiles_multiple_tasks/1,
as_comma_placement/1,
as_comma_then_space/1,
- as_dir_name/1]).
+ as_dir_name/1,
+ as_with_task_args/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -29,7 +30,7 @@ init_per_testcase(_, Config) ->
all() -> [as_basic, as_multiple_profiles, as_multiple_tasks,
as_multiple_profiles_multiple_tasks,
as_comma_placement, as_comma_then_space,
- as_dir_name].
+ as_dir_name, as_with_task_args].
as_basic(Config) ->
AppDir = ?config(apps, Config),
@@ -118,3 +119,20 @@ as_dir_name(Config) ->
true = filelib:is_dir(filename:join([AppDir, "_build", "foo+bar+baz"])).
+
+as_with_task_args(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("as_with_task_args_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ rebar_test_utils:run_and_check(Config,
+ [],
+ ["as", "default", "compile"],
+ {ok, [{app, Name}]}),
+
+ rebar_test_utils:run_and_check(Config,
+ [],
+ ["as", "default", "clean", "-a"],
+ {ok, [{app, Name, invalid}]}).
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index 2c5a11f..8564754 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -4,6 +4,7 @@
init_per_suite/1,
end_per_suite/1,
init_per_testcase/2,
+ end_per_testcase/2,
all/0,
build_basic_app/1,
build_release_apps/1,
@@ -12,7 +13,9 @@
build_all_srcdirs/1,
recompile_when_opts_change/1,
dont_recompile_when_opts_dont_change/1,
- dont_recompile_yrl_or_xrl/1]).
+ dont_recompile_yrl_or_xrl/1,
+ deps_in_path/1,
+ checkout_priority/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -30,12 +33,15 @@ end_per_suite(_Config) ->
init_per_testcase(_, Config) ->
rebar_test_utils:init_rebar_state(Config).
+end_per_testcase(_, _Config) ->
+ catch meck:unload().
+
all() ->
[build_basic_app, build_release_apps,
build_checkout_apps, build_checkout_deps,
build_all_srcdirs,
recompile_when_opts_change, dont_recompile_when_opts_dont_change,
- dont_recompile_yrl_or_xrl].
+ dont_recompile_yrl_or_xrl, deps_in_path, checkout_priority].
build_basic_app(Config) ->
AppDir = ?config(apps, Config),
@@ -88,8 +94,11 @@ build_checkout_deps(Config) ->
rebar_test_utils:create_app(filename:join([CheckoutsDir,Name2]), Name2, Vsn2, [kernel, stdlib]),
rebar_test_utils:create_app(filename:join([DepsDir,Name2]), Name2, Vsn1, [kernel, stdlib]),
+ Deps = [{list_to_atom(Name2), Vsn2, {git, "", ""}}],
+ {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, Deps}])),
+
rebar_test_utils:run_and_check(
- Config, [], ["compile"],
+ Config, RebarConfig, ["compile"],
{ok, [{app, Name1}, {checkout, Name2}]}
),
ok = application:load(list_to_atom(Name2)),
@@ -211,3 +220,115 @@ dont_recompile_yrl_or_xrl(Config) ->
?assert(ModTime == NewModTime).
+deps_in_path(Config) ->
+ AppDir = ?config(apps, Config),
+ StartPaths = code:get_path(),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ DepName = rebar_test_utils:create_random_name("dep1_"),
+ PkgName = rebar_test_utils:create_random_name("pkg1_"),
+ mock_git_resource:mock([]),
+ mock_pkg_resource:mock([
+ {pkgdeps, [{{iolist_to_binary(PkgName), iolist_to_binary(Vsn)}, []}]}
+ ]),
+
+ RConfFile = rebar_test_utils:create_config(AppDir, [{deps, [
+ {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}},
+ {list_to_atom(PkgName), Vsn}
+ ]}]),
+ {ok, RConf} = file:consult(RConfFile),
+ %% Make sure apps we look for are not visible
+ %% Hope not to find src name
+ ?assertEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, DepName)]]),
+ %% Hope not to find pkg name in there
+ ?assertEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, PkgName)]]),
+ %% Build things
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]}
+ ),
+ %% Find src name in there
+ ?assertNotEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, DepName)]]),
+ %% find pkg name in there
+ ?assertNotEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, PkgName)]]),
+ code:set_path(StartPaths),
+ %% Make sure apps we look for are not visible again
+ %% Hope not to find src name
+ ?assertEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, DepName)]]),
+ %% Hope not to find pkg name in there
+ ?assertEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, PkgName)]]),
+ %% Rebuild
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]}
+ ),
+ %% Find src name in there
+ ?assertNotEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, DepName)]]),
+ %% find pkg name in there
+ ?assertNotEqual([], [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, PkgName)]]).
+
+checkout_priority(Config) ->
+ AppDir = ?config(apps, Config),
+ CheckoutsDir = ?config(checkouts, Config),
+ StartPaths = code:get_path(),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ DepName = rebar_test_utils:create_random_name("dep1_"),
+ PkgName = rebar_test_utils:create_random_name("pkg1_"),
+ mock_git_resource:mock([]),
+ mock_pkg_resource:mock([
+ {pkgdeps, [{{iolist_to_binary(PkgName), iolist_to_binary(Vsn)}, []}]}
+ ]),
+
+ RConfFile = rebar_test_utils:create_config(AppDir, [{deps, [
+ {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}},
+ {list_to_atom(PkgName), Vsn}
+ ]}]),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]}
+ ),
+
+ %% Build two checkout apps similar to dependencies to be fetched,
+ %% but on a different version
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(filename:join([CheckoutsDir,DepName]), DepName, Vsn2, [kernel, stdlib]),
+ rebar_test_utils:create_app(filename:join([CheckoutsDir,PkgName]), PkgName, Vsn2, [kernel, stdlib]),
+
+ %% Rebuild and make sure the checkout apps are in path
+ code:set_path(StartPaths),
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name}, {checkout, DepName}, {checkout, PkgName}]}
+ ),
+
+ [DepPath] = [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, DepName)]],
+ [PkgPath] = [Path || Path <- code:get_path(),
+ {match, _} <- [re:run(Path, PkgName)]],
+
+ {ok, [DepApp]} = file:consult(filename:join([DepPath, DepName ++ ".app"])),
+ {ok, [PkgApp]} = file:consult(filename:join([PkgPath, PkgName ++ ".app"])),
+
+ {application, _, DepProps} = DepApp,
+ {application, _, PkgProps} = PkgApp,
+
+ ?assertEqual(Vsn2, proplists:get_value(vsn, DepProps)),
+ ?assertEqual(Vsn2, proplists:get_value(vsn, PkgProps)).
diff --git a/test/rebar_eunit_SUITE.erl b/test/rebar_eunit_SUITE.erl
index d2d8608..4ec92f2 100644
--- a/test/rebar_eunit_SUITE.erl
+++ b/test/rebar_eunit_SUITE.erl
@@ -4,8 +4,21 @@
init_per_suite/1,
end_per_suite/1,
init_per_testcase/2,
- all/0,
- test_basic_app/1]).
+ all/0]).
+-export([test_basic_app/1,
+ test_multi_app/1,
+ test_profile/1,
+ test_basic_exports/1,
+ test_multi_exports/1,
+ test_basic_defines/1,
+ test_multi_defines/1,
+ test_single_app_flag/1,
+ test_multiple_app_flag/1,
+ test_nonexistent_app_flag/1,
+ test_single_suite_flag/1,
+ test_suite_in_app_flag/1,
+ test_suite_in_wrong_app_flag/1,
+ test_nonexistent_suite_flag/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -24,14 +37,372 @@ init_per_testcase(_, Config) ->
rebar_test_utils:init_rebar_state(Config, "eunit_").
all() ->
- [test_basic_app].
+ [test_basic_app, test_multi_app, test_profile,
+ test_basic_exports, test_multi_exports,
+ test_basic_defines, test_multi_defines,
+ test_single_app_flag, test_multiple_app_flag, test_nonexistent_app_flag,
+ test_single_suite_flag, test_suite_in_app_flag,
+ test_suite_in_wrong_app_flag, test_nonexistent_suite_flag].
test_basic_app(Config) ->
AppDir = ?config(apps, Config),
Name = rebar_test_utils:create_random_name("basic_"),
Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{d, some_define}]}],
rebar_test_utils:run_and_check(Config, RebarConfig, ["eunit"], {ok, [{app, Name}]}).
+
+test_multi_app(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit"],
+ {ok, [{app, Name1}, {app, Name2}]}).
+
+test_profile(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("profile_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]},
+ {profiles, [{test, [{erl_opts, [debug_info]}]}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["as", "test", "eunit"],
+ {ok, [{app, Name}]}).
+
+test_basic_exports(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("basic_exports_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit"],
+ {ok, [{app, Name}]}),
+
+ App = list_to_atom("not_a_real_src_" ++ Name),
+ Suite = list_to_atom("not_a_real_src_" ++ Name ++ "_tests"),
+ AppExports = App:module_info(exports),
+ SuiteExports = Suite:module_info(exports),
+ AppExpect = [{some_test_, 0}],
+ SuiteExpect = [{some_test_, 0}, {define_test_, 0}],
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, AppExports) end, AppExpect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteExports) end, SuiteExpect).
+
+test_multi_exports(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit"],
+ {ok, [{app, Name1}, {app, Name2}]}),
+
+ App1 = list_to_atom("not_a_real_src_" ++ Name1),
+ Suite1 = list_to_atom("not_a_real_src_" ++ Name1 ++ "_tests"),
+ AppExports1 = App1:module_info(exports),
+ SuiteExports1 = Suite1:module_info(exports),
+ App2 = list_to_atom("not_a_real_src_" ++ Name2),
+ Suite2 = list_to_atom("not_a_real_src_" ++ Name2 ++ "_tests"),
+ AppExports2 = App2:module_info(exports),
+ SuiteExports2 = Suite2:module_info(exports),
+ AppExpect = [{some_test_, 0}],
+ SuiteExpect = [{some_test_, 0}, {define_test_, 0}],
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, AppExports1) end, AppExpect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteExports1) end, SuiteExpect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, AppExports2) end, AppExpect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteExports2) end, SuiteExpect).
+
+test_basic_defines(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("basic_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["eunit"], {ok, [{app, Name}]}),
+
+ App = list_to_atom("not_a_real_src_" ++ Name),
+ Suite = list_to_atom("not_a_real_src_" ++ Name ++ "_tests"),
+ AppOpts = proplists:get_value(options, App:module_info(compile), []),
+ SuiteOpts = proplists:get_value(options, Suite:module_info(compile), []),
+ Expect = [{d, some_define}],
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, AppOpts) end, Expect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteOpts) end, Expect).
+
+test_multi_defines(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit"],
+ {ok, [{app, Name1}, {app, Name2}]}),
+
+ App1 = list_to_atom("not_a_real_src_" ++ Name1),
+ Suite1 = list_to_atom("not_a_real_src_" ++ Name1 ++ "_tests"),
+ AppOpts1 = proplists:get_value(options, App1:module_info(compile), []),
+ SuiteOpts1 = proplists:get_value(options, Suite1:module_info(compile), []),
+ App2 = list_to_atom("not_a_real_src_" ++ Name2),
+ Suite2 = list_to_atom("not_a_real_src_" ++ Name2 ++ "_tests"),
+ AppOpts2 = proplists:get_value(options, App2:module_info(compile), []),
+ SuiteOpts2 = proplists:get_value(options, Suite2:module_info(compile), []),
+ Expect = [{d, some_define}],
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, AppOpts1) end, Expect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteOpts1) end, Expect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, AppOpts2) end, Expect),
+ lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteOpts2) end, Expect).
+
+test_single_app_flag(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ BareSuite = io_lib:format("-module(all_tests).\n"
+ "-compile(export_all).\n"
+ "-include_lib(\"eunit/include/eunit.hrl\").\n"
+ "some_test_() -> ?_assert(true).\n"
+ "define_test_() -> ?_assertEqual(true, ?some_define).\n", []),
+ FileName = filename:join([AppDir, "test", "all_tests.erl"]),
+ ok = filelib:ensure_dir(FileName),
+ ok = ec_file:write(FileName, BareSuite),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit", "--app=" ++ Name1],
+ {ok, [{app, Name1}, {app, Name2}]}),
+
+ Suite1 = list_to_atom("not_a_real_src_" ++ Name1 ++ "_tests"),
+ {module, Suite1} = code:ensure_loaded(Suite1),
+ Suite2 = list_to_atom("not_a_real_src_" ++ Name2 ++ "_tests"),
+ {error, nofile} = code:ensure_loaded(Suite2),
+ {error, nofile} = code:ensure_loaded(all_tests).
+
+test_multiple_app_flag(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ BareSuite = io_lib:format("-module(all_tests).\n"
+ "-compile(export_all).\n"
+ "-include_lib(\"eunit/include/eunit.hrl\").\n"
+ "some_test_() -> ?_assert(true).\n"
+ "define_test_() -> ?_assertEqual(true, ?some_define).\n", []),
+ FileName = filename:join([AppDir, "test", "all_tests.erl"]),
+ ok = filelib:ensure_dir(FileName),
+ ok = ec_file:write(FileName, BareSuite),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit", "--app=" ++ Name1 ++ "," ++ Name2],
+ {ok, [{app, Name1}, {app, Name2}]}),
+
+ Suite1 = list_to_atom("not_a_real_src_" ++ Name1 ++ "_tests"),
+ {module, Suite1} = code:ensure_loaded(Suite1),
+ Suite2 = list_to_atom("not_a_real_src_" ++ Name2 ++ "_tests"),
+ {module, Suite2} = code:ensure_loaded(Suite2),
+ {error, nofile} = code:ensure_loaded(all_tests).
+
+test_nonexistent_app_flag(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ {error, {_, Error}} = rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit", "--app=not_a_real_app"],
+ return),
+
+ Error = {error_running_tests, "Application `not_a_real_app' not found in project."}.
+
+test_single_suite_flag(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit", "--suite=not_a_real_src_" ++ Name1],
+ {ok, [{app, Name1}, {app, Name2}]}),
+
+ Suite1 = list_to_atom("not_a_real_src_" ++ Name1 ++ "_tests"),
+ {module, Suite1} = code:ensure_loaded(Suite1).
+
+test_suite_in_app_flag(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit",
+ "--app=" ++ Name1,
+ "--suite=not_a_real_src_" ++ Name1],
+ {ok, [{app, Name1}, {app, Name2}]}),
+
+ Suite1 = list_to_atom("not_a_real_src_" ++ Name1 ++ "_tests"),
+ {module, Suite1} = code:ensure_loaded(Suite1),
+ Suite2 = list_to_atom("not_a_real_src_" ++ Name2 ++ "_tests"),
+ {error, nofile} = code:ensure_loaded(Suite2).
+
+test_suite_in_wrong_app_flag(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ {error, {_, Error}} = rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit",
+ "--app=" ++ Name1,
+ "--suite=not_a_real_src_" ++ Name2],
+ return),
+
+ Error = {error_running_tests, "Module `not_a_real_src_" ++
+ Name2 ++
+ "' not found in applications."}.
+
+test_nonexistent_suite_flag(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("multi_exports_app1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name1]),
+ Name1,
+ Vsn1,
+ [kernel, stdlib]),
+ Name2 = rebar_test_utils:create_random_name("multi_exports_app2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(filename:join([AppDir,Name2]),
+ Name2,
+ Vsn2,
+ [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ {error, {_, Error}} = rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit", "--suite=not_a_real_module"],
+ return),
+
+ Error = {error_running_tests, "Module `not_a_real_module' not found in applications."}.
diff --git a/test/rebar_new_SUITE.erl b/test/rebar_new_SUITE.erl
index e382ae4..3cee6f2 100644
--- a/test/rebar_new_SUITE.erl
+++ b/test/rebar_new_SUITE.erl
@@ -6,7 +6,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-all() -> [app, app_with_fallbacks].
+all() -> [app_git_user, app_hg_user, app_with_fallbacks].
init_per_testcase(Case, Config0) ->
@@ -31,7 +31,7 @@ mock_empty_escript_templates() ->
meck:new(rebar_utils, [passthrough]),
meck:expect(rebar_utils, escript_foldl, fun(_,_,_) -> {ok, []} end).
-app(Config) ->
+app_git_user(Config) ->
meck:expect(rebar_utils, sh, fun("git config --global user.name", _) -> {ok, "gitname"};
("git config --global user.email", _) -> {ok, "git@email.com"}
end),
@@ -73,6 +73,28 @@ app_with_fallbacks(Config) ->
{filename:join(["src", Name++"_app.erl"]), [Name]}
]).
+app_hg_user(Config) ->
+ meck:expect(rebar_utils, sh, fun("hg showconfig ui.username", _) -> {ok, "hgname <hg@email.com>"};
+ (_, _) -> {error, fallback}
+ end),
+
+ Name = ?config(name, Config),
+ rebar_test_utils:run_and_check(
+ Config, [],
+ ["new", "test_app", Name],
+ {ok, []}
+ ),
+ validate_files(
+ Config, Name,
+ [{"LICENSE", ["hgname", "hg@email.com"]},
+ {"README.md", [Name]},
+ {".gitignore", []},
+ {"rebar.config", []},
+ {filename:join(["src", Name++".app.src"]), [Name]},
+ {filename:join(["src", Name++"_sup.erl"]), [Name]},
+ {filename:join(["src", Name++"_app.erl"]), [Name]}
+ ]).
+
validate_files(_Config, Name, Checks) ->
[begin
Path = filename:join([Name, File]),
diff --git a/test/rebar_opts_parser_SUITE.erl b/test/rebar_opts_parser_SUITE.erl
new file mode 100644
index 0000000..fc738b9
--- /dev/null
+++ b/test/rebar_opts_parser_SUITE.erl
@@ -0,0 +1,54 @@
+-module(rebar_opts_parser_SUITE).
+
+-export([all/0, init_per_testcase/2]).
+-export([bad_arg_to_flag/1, missing_arg_to_flag/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+
+all() -> [bad_arg_to_flag, missing_arg_to_flag].
+
+init_per_testcase(_, Config) ->
+ rebar_test_utils:init_rebar_state(Config, "opts_parser_").
+
+bad_arg_to_flag(Config) ->
+ ok = meck:new(getopt),
+ ok = meck:expect(getopt,
+ parse,
+ fun(_, _) -> {error, {invalid_option_arg, {foo, "null"}}} end),
+
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("bad_arg_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ {error, Error} = rebar_test_utils:run_and_check(Config,
+ [],
+ ["compile", "--foo=null"],
+ return),
+
+ true = meck:validate(getopt),
+ ok = meck:unload(getopt),
+
+ "Invalid argument null to option foo" = lists:flatten(Error).
+
+missing_arg_to_flag(Config) ->
+ ok = meck:new(getopt),
+ ok = meck:expect(getopt, parse, fun(_, _) -> {error, {missing_option_arg, foo}} end),
+
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("missing_arg_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ {error, Error} = rebar_test_utils:run_and_check(Config,
+ [],
+ ["compile", "--foo"],
+ return),
+
+ true = meck:validate(getopt),
+ ok = meck:unload(getopt),
+
+ "Missing argument to option foo" = lists:flatten(Error). \ No newline at end of file
diff --git a/test/rebar_profiles_SUITE.erl b/test/rebar_profiles_SUITE.erl
index a4f926e..6288053 100644
--- a/test/rebar_profiles_SUITE.erl
+++ b/test/rebar_profiles_SUITE.erl
@@ -100,12 +100,17 @@ profile_merges(_Config) ->
{test2, "hello"},
{test3, [key3]},
{test4, "oldvalue"},
+ {test5, [{key5, true}]},
+ {test6, [{key6, false}]},
{profiles,
[{profile1,
[{test1, [{key3, 5}, key1]}]},
{profile2, [{test2, "goodbye"},
{test3, []},
- {test4, []}]}]}],
+ {test4, []},
+ {test5, [{key5, false}]},
+ {test6, [{key6, true}]}
+ ]}]}],
State = rebar_state:new(RebarConfig),
State1 = rebar_state:apply_profiles(State, [profile1, profile2]),
@@ -118,7 +123,9 @@ profile_merges(_Config) ->
%% Check that a newvalue of []/"" doesn't override non-string oldvalues
[key3] = rebar_state:get(State1, test3),
- [] = rebar_state:get(State1, test4).
+ [] = rebar_state:get(State1, test4),
+ [{key5, false}, {key5, true}] = rebar_state:get(State1, test5),
+ [{key6, true}, {key6, false}] = rebar_state:get(State1, test6).
add_to_profile(_Config) ->
RebarConfig = [{foo, true}, {bar, false}],
@@ -165,7 +172,7 @@ test_profile_applied_at_completion(Config) ->
Name = rebar_test_utils:create_random_name("test_profile_at_completion_"),
Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{d, some_define}]}],
rebar_test_utils:create_config(AppDir, RebarConfig),
@@ -184,7 +191,7 @@ test_profile_applied_before_compile(Config) ->
Name = rebar_test_utils:create_random_name("test_profile_before_compile_"),
Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{d, some_define}]}],
rebar_test_utils:create_config(AppDir, RebarConfig),
@@ -199,7 +206,7 @@ test_profile_applied_before_eunit(Config) ->
Name = rebar_test_utils:create_random_name("test_profile_before_eunit_"),
Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{d, some_define}]}],
rebar_test_utils:create_config(AppDir, RebarConfig),
@@ -214,7 +221,7 @@ test_profile_applied_to_apps(Config) ->
Name = rebar_test_utils:create_random_name("test_profile_applied_to_apps_"),
Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{d, some_define}]}],
rebar_test_utils:create_config(AppDir, RebarConfig),
diff --git a/test/rebar_release_SUITE.erl b/test/rebar_release_SUITE.erl
index 92219a5..3809106 100644
--- a/test/rebar_release_SUITE.erl
+++ b/test/rebar_release_SUITE.erl
@@ -3,7 +3,10 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-all() -> [release, tar].
+all() -> [release,
+ dev_mode_release,
+ profile_dev_mode_override_release,
+ tar].
init_per_testcase(Case, Config0) ->
Config = rebar_test_utils:init_rebar_state(Config0),
@@ -33,9 +36,46 @@ release(Config) ->
rebar_test_utils:run_and_check(
Config, RebarConfig,
["release"],
- {ok, [{release, list_to_atom(Name), Vsn}]}
+ {ok, [{release, list_to_atom(Name), Vsn, false}]}
).
+dev_mode_release(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = ?config(name, Config),
+ Vsn = "1.0.0",
+ {ok, RebarConfig} =
+ file:consult(rebar_test_utils:create_config(AppDir,
+ [{relx, [{release, {list_to_atom(Name), Vsn},
+ [list_to_atom(Name)]},
+ {lib_dirs, [AppDir]},
+ {dev_mode, true}]}])),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig,
+ ["release"],
+ {ok, [{release, list_to_atom(Name), Vsn, true}]}
+ ).
+
+
+profile_dev_mode_override_release(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = ?config(name, Config),
+ Vsn = "1.0.0",
+ {ok, RebarConfig} =
+ file:consult(rebar_test_utils:create_config(AppDir,
+ [{relx, [{release, {list_to_atom(Name), Vsn},
+ [list_to_atom(Name)]},
+ {lib_dirs, [AppDir]},
+ {dev_mode, true}]},
+ {profiles,
+ [{ct,
+ [{relx, [{dev_mode, false}]}]}]}])),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig,
+ ["as", "ct", "release"],
+ {ok, [{release, list_to_atom(Name), Vsn, false}]}
+ ).
+
+
tar(Config) ->
AppDir = ?config(apps, Config),
Name = ?config(name, Config),
@@ -48,5 +88,5 @@ tar(Config) ->
rebar_test_utils:run_and_check(
Config, RebarConfig,
["tar"],
- {ok, [{release, list_to_atom(Name), Vsn}, {tar, Name, Vsn}]}
+ {ok, [{release, list_to_atom(Name), Vsn, false}, {tar, Name, Vsn}]}
).
diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl
index 7c52a18..2eb14ac 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -3,7 +3,7 @@
-include_lib("eunit/include/eunit.hrl").
-export([init_rebar_state/1, init_rebar_state/2, run_and_check/4]).
-export([expand_deps/2, flat_deps/1, flat_pkgdeps/1, top_level_deps/1]).
--export([create_app/4, create_empty_app/4, create_config/2]).
+-export([create_app/4, create_eunit_app/4, create_empty_app/4, create_config/2]).
-export([create_random_name/1, create_random_vsn/0]).
%%%%%%%%%%%%%%
@@ -25,7 +25,8 @@ init_rebar_state(Config, Name) ->
ok = ec_file:mkdir_p(CheckoutsDir),
Verbosity = rebar3:log_level(),
rebar_log:init(command_line, Verbosity),
- State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}]),
+ State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}
+ ,{root_dir, AppsDir}]),
[{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, State} | Config].
%% @doc Takes common test config, a rebar config ([] if empty), a command to
@@ -69,7 +70,17 @@ run_and_check(Config, RebarConfig, Command, Expect) ->
%% And returns a `rebar_app_info' object.
create_app(AppDir, Name, Vsn, Deps) ->
write_src_file(AppDir, Name),
- write_test_file(AppDir, Name),
+ write_app_src_file(AppDir, Name, Vsn, Deps),
+ rebar_app_info:new(Name, Vsn, AppDir, Deps).
+
+%% @doc Creates a dummy application including:
+%% - src/<file>.erl
+%% - src/<file>.app.src
+%% - test/<file>_tests.erl
+%% And returns a `rebar_app_info' object.
+create_eunit_app(AppDir, Name, Vsn, Deps) ->
+ write_eunitized_src_file(AppDir, Name),
+ write_eunit_suite_file(AppDir, Name),
write_app_src_file(AppDir, Name, Vsn, Deps),
rebar_app_info:new(Name, Vsn, AppDir, Deps).
@@ -217,7 +228,7 @@ check_results(AppDir, Expected) ->
?assertEqual(iolist_to_binary(Vsn),
iolist_to_binary(LockVsn))
end
- ; ({release, Name, Vsn}) ->
+ ; ({release, Name, Vsn, ExpectedDevMode}) ->
ct:pal("Release: ~p-~s", [Name, Vsn]),
{ok, Cwd} = file:get_cwd(),
try
@@ -228,6 +239,15 @@ check_results(AppDir, Expected) ->
{ok, RelxState2} = rlx_prv_app_discover:do(RelxState1),
{ok, RelxState3} = rlx_prv_rel_discover:do(RelxState2),
+ LibDir = filename:join([ReleaseDir, Name, "lib"]),
+ {ok, RelLibs} = file:list_dir(LibDir),
+ IsSymLinkFun =
+ fun(X) ->
+ ec_file:is_symlink(filename:join(LibDir, X))
+ end,
+ DevMode = lists:all(IsSymLinkFun, RelLibs),
+ ?assertEqual(ExpectedDevMode, DevMode),
+
%% throws not_found if it doesn't exist
rlx_state:get_realized_release(RelxState3, Name, Vsn)
catch
@@ -250,10 +270,15 @@ write_src_file(Dir, Name) ->
ok = filelib:ensure_dir(Erl),
ok = ec_file:write(Erl, erl_src_file("not_a_real_src_" ++ Name ++ ".erl")).
-write_test_file(Dir, Name) ->
+write_eunitized_src_file(Dir, Name) ->
+ Erl = filename:join([Dir, "src", "not_a_real_src_" ++ Name ++ ".erl"]),
+ ok = filelib:ensure_dir(Erl),
+ ok = ec_file:write(Erl, erl_eunitized_src_file("not_a_real_src_" ++ Name ++ ".erl")).
+
+write_eunit_suite_file(Dir, Name) ->
Erl = filename:join([Dir, "test", "not_a_real_src_" ++ Name ++ "_tests.erl"]),
ok = filelib:ensure_dir(Erl),
- ok = ec_file:write(Erl, erl_test_file("not_a_real_src_" ++ Name ++ ".erl")).
+ ok = ec_file:write(Erl, erl_eunit_suite_file("not_a_real_src_" ++ Name ++ ".erl")).
write_app_file(Dir, Name, Version, Deps) ->
Filename = filename:join([Dir, "ebin", Name ++ ".app"]),
@@ -268,13 +293,18 @@ write_app_src_file(Dir, Name, Version, Deps) ->
erl_src_file(Name) ->
io_lib:format("-module(~s).\n"
"-export([main/0]).\n"
+ "main() -> ok.\n", [filename:basename(Name, ".erl")]).
+
+erl_eunitized_src_file(Name) ->
+ io_lib:format("-module(~s).\n"
+ "-export([main/0]).\n"
"main() -> ok.\n"
"-ifdef(TEST).\n"
"-include_lib(\"eunit/include/eunit.hrl\").\n"
"some_test_() -> ?_assertEqual(ok, main()).\n"
"-endif.\n", [filename:basename(Name, ".erl")]).
-erl_test_file(Name) ->
+erl_eunit_suite_file(Name) ->
BaseName = filename:basename(Name, ".erl"),
io_lib:format("-module(~s_tests).\n"
"-compile(export_all).\n"