diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar_plugins.erl | 8 | ||||
-rw-r--r-- | src/rebar_prv_common_test.erl | 13 | ||||
-rw-r--r-- | src/rebar_prv_cover.erl | 61 | ||||
-rw-r--r-- | src/rebar_prv_eunit.erl | 5 |
4 files changed, 65 insertions, 22 deletions
diff --git a/src/rebar_plugins.erl b/src/rebar_plugins.erl index 1fc01ff..57c34bc 100644 --- a/src/rebar_plugins.erl +++ b/src/rebar_plugins.erl @@ -96,8 +96,8 @@ handle_plugin(Profile, Plugin, State, Upgrade) -> ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []), %% Add already built plugin deps to the code path - CodePaths = [rebar_app_info:ebin_dir(A) || A <- Apps -- ToBuild], - code:add_pathsa(CodePaths), + PreBuiltPaths = [rebar_app_info:ebin_dir(A) || A <- Apps] -- ToBuild, + code:add_pathsa(PreBuiltPaths), %% Build plugin and its deps [build_plugin(AppInfo, Apps, State2) || AppInfo <- ToBuild], @@ -105,10 +105,12 @@ handle_plugin(Profile, Plugin, State, Upgrade) -> %% Add newly built deps and plugin to code path State3 = rebar_state:update_all_plugin_deps(State2, Apps), NewCodePaths = [rebar_app_info:ebin_dir(A) || A <- ToBuild], + AllPluginEbins = filelib:wildcard(filename:join([rebar_dir:plugins_dir(State), "*", "ebin"])), + CodePaths = PreBuiltPaths++(AllPluginEbins--ToBuild), code:add_pathsa(NewCodePaths++CodePaths), %% Store plugin code paths so we can remove them when compiling project apps - State4 = rebar_state:update_code_paths(State3, all_plugin_deps, CodePaths++NewCodePaths), + State4 = rebar_state:update_code_paths(State3, all_plugin_deps, PreBuiltPaths++NewCodePaths), {plugin_providers(Plugin), State4} catch diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index 9631a0d..f800610 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -8,8 +8,11 @@ -export([init/1, do/1, format_error/1]). -%% exported for test purposes, consider private --export([compile/2, prepare_tests/1, translate_paths/2]). + +-ifdef(TEST). +%% exported for test purposes +-export([compile/2, prepare_tests/1, translate_paths/2, maybe_write_coverdata/1]). +-endif. -include("rebar.hrl"). -include_lib("providers/include/providers.hrl"). @@ -728,7 +731,8 @@ maybe_write_coverdata(State) -> true -> rebar_state:set(State, cover_enabled, true); false -> State end, - rebar_prv_cover:maybe_write_coverdata(State1, ?PROVIDER). + Name = proplists:get_value(cover_export_name, RawOpts, ?PROVIDER), + rebar_prv_cover:maybe_write_coverdata(State1, Name). ct_opts(_State) -> [{dir, undefined, "dir", string, help(dir)}, %% comma-separated list @@ -744,6 +748,7 @@ ct_opts(_State) -> {logopts, undefined, "logopts", string, help(logopts)}, %% comma-separated list {verbosity, undefined, "verbosity", integer, help(verbosity)}, %% Integer {cover, $c, "cover", {boolean, false}, help(cover)}, + {cover_export_name, undefined, "cover_export_name", string, help(cover_export_name)}, {repeat, undefined, "repeat", integer, help(repeat)}, %% integer {duration, undefined, "duration", string, help(duration)}, % format: HHMMSS {until, undefined, "until", string, help(until)}, %% format: YYMoMoDD[HHMMSS] @@ -797,6 +802,8 @@ help(verbosity) -> "Verbosity"; help(cover) -> "Generate cover data"; +help(cover_export_name) -> + "Base name of the coverdata file to write"; help(repeat) -> "How often to repeat tests"; help(duration) -> diff --git a/src/rebar_prv_cover.erl b/src/rebar_prv_cover.erl index c890452..7412038 100644 --- a/src/rebar_prv_cover.erl +++ b/src/rebar_prv_cover.erl @@ -12,6 +12,7 @@ maybe_write_coverdata/2, format_error/1]). +-include_lib("providers/include/providers.hrl"). -include("rebar.hrl"). -define(PROVIDER, cover). @@ -62,6 +63,9 @@ maybe_write_coverdata(State, Task) -> end. -spec format_error(any()) -> iolist(). +format_error({min_coverage_failed, {PassRate, Total}}) -> + io_lib:format("Requiring ~p% coverage to pass. Only ~p% obtained", + [PassRate, Total]); format_error(Reason) -> io_lib:format("~p", [Reason]). @@ -102,13 +106,13 @@ do_analyze(State) -> %% redirect cover output true = redirect_cover_output(State, CoverPid), %% analyze! - ok = case analyze(State, CoverFiles) of - [] -> ok; + case analyze(State, CoverFiles) of + [] -> {ok, State}; Analysis -> print_analysis(Analysis, verbose(State)), - write_index(State, Analysis) - end, - {ok, State}. + write_index(State, Analysis), + maybe_fail_coverage(Analysis, State) + end. get_all_coverdata(CoverDir) -> ok = filelib:ensure_dir(filename:join([CoverDir, "dummy.log"])), @@ -213,11 +217,11 @@ format_table(Stats, CoverFiles) -> Header = header(MaxLength), Separator = separator(MaxLength), TotalLabel = format("total", MaxLength), - TotalCov = format(calculate_total(Stats), 8), + TotalCov = format(calculate_total_string(Stats), 8), [io_lib:format("~ts~n~ts~n~ts~n", [Separator, Header, Separator]), lists:map(fun({Mod, Coverage, _}) -> Name = format(Mod, MaxLength), - Cov = format(percentage(Coverage), 8), + Cov = format(percentage_string(Coverage), 8), io_lib:format(" | ~ts | ~ts |~n", [Name, Cov]) end, Stats), io_lib:format("~ts~n", [Separator]), @@ -239,6 +243,9 @@ separator(Width) -> format(String, Width) -> io_lib:format("~*.ts", [Width, String]). +calculate_total_string(Stats) -> + integer_to_list(calculate_total(Stats))++"%". + calculate_total(Stats) -> percentage(lists:foldl( fun({_Mod, {Cov, Not}, _File}, {CovAcc, NotAcc}) -> @@ -248,8 +255,10 @@ calculate_total(Stats) -> Stats )). -percentage({_, 0}) -> "100%"; -percentage({Cov, Not}) -> integer_to_list(trunc((Cov / (Cov + Not)) * 100)) ++ "%". +percentage_string(Data) -> integer_to_list(percentage(Data))++"%". + +percentage({_, 0}) -> 100; +percentage({Cov, Not}) -> trunc((Cov / (Cov + Not)) * 100). write_index(State, Coverage) -> CoverDir = cover_dir(State), @@ -279,14 +288,25 @@ write_index_section(F, [{Section, DataFile, Mods}|Rest]) -> FmtLink = fun({Mod, Cov, Report}) -> ?FMT("<tr><td><a href='~ts'>~ts</a></td><td>~ts</td>\n", - [strip_coverdir(Report), Mod, percentage(Cov)]) + [strip_coverdir(Report), Mod, percentage_string(Cov)]) end, lists:foreach(fun(M) -> ok = file:write(F, FmtLink(M)) end, Mods), ok = file:write(F, ?FMT("<tr><td><strong>Total</strong></td><td>~ts</td>\n", - [calculate_total(Mods)])), + [calculate_total_string(Mods)])), ok = file:write(F, "</table>\n"), write_index_section(F, Rest). +maybe_fail_coverage(Analysis, State) -> + {_, _CoverFiles, Stats} = lists:keyfind("aggregate", 1, Analysis), + Total = calculate_total(Stats), + PassRate = min_coverage(State), + ?DEBUG("Comparing ~p to pass rate ~p", [Total, PassRate]), + if Total >= PassRate -> + {ok, State} + ; Total < PassRate -> + ?PRV_ERROR({min_coverage_failed, {PassRate, Total}}) + end. + %% fix for r15b which doesn't put the correct path in the `source` section %% of `module_info(compile)` strip_coverdir([]) -> ""; @@ -372,10 +392,10 @@ redirect_cover_output(State, CoverPid) -> [append]), group_leader(F, CoverPid). -write_coverdata(State, Task) -> +write_coverdata(State, Name) -> DataDir = cover_dir(State), ok = filelib:ensure_dir(filename:join([DataDir, "dummy.log"])), - ExportFile = filename:join([DataDir, atom_to_list(Task) ++ ".coverdata"]), + ExportFile = filename:join([DataDir, rebar_utils:to_list(Name) ++ ".coverdata"]), case cover:export(ExportFile) of ok -> %% dump accumulated coverdata after writing @@ -401,12 +421,23 @@ verbose(State) -> {Verbose, _} -> Verbose end. +min_coverage(State) -> + Command = proplists:get_value(min_coverage, command_line_opts(State), undefined), + Config = proplists:get_value(min_coverage, config_opts(State), undefined), + case {Command, Config} of + {undefined, undefined} -> 0; + {undefined, Rate} -> Rate; + {Rate, _} -> Rate + end. + cover_dir(State) -> filename:join([rebar_dir:base_dir(State), "cover"]). cover_opts(_State) -> [{reset, $r, "reset", boolean, help(reset)}, - {verbose, $v, "verbose", boolean, help(verbose)}]. + {verbose, $v, "verbose", boolean, help(verbose)}, + {min_coverage, $m, "min_coverage", integer, help(min_coverage)}]. help(reset) -> "Reset all coverdata."; -help(verbose) -> "Print coverage analysis.". +help(verbose) -> "Print coverage analysis."; +help(min_coverage) -> "Mandate a coverage percentage required to succeed (0..100)". diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index 2361432..4b71416 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -472,7 +472,8 @@ maybe_write_coverdata(State) -> true -> rebar_state:set(State, cover_enabled, true); false -> State end, - rebar_prv_cover:maybe_write_coverdata(State1, ?PROVIDER). + Name = proplists:get_value(cover_export_name, RawOpts, ?PROVIDER), + rebar_prv_cover:maybe_write_coverdata(State1, Name). handle_results(ok) -> ok; handle_results(error) -> @@ -484,6 +485,7 @@ eunit_opts(_State) -> [{app, undefined, "app", string, help(app)}, {application, undefined, "application", string, help(app)}, {cover, $c, "cover", boolean, help(cover)}, + {cover_export_name, undefined, "cover_export_name", string, help(cover_export_name)}, {dir, $d, "dir", string, help(dir)}, {file, $f, "file", string, help(file)}, {module, $m, "module", string, help(module)}, @@ -495,6 +497,7 @@ eunit_opts(_State) -> help(app) -> "Comma separated list of application test suites to run. Equivalent to `[{application, App}]`."; help(cover) -> "Generate cover data. Defaults to false."; +help(cover_export_name) -> "Base name of the coverdata file to write"; help(dir) -> "Comma separated list of dirs to load tests from. Equivalent to `[{dir, Dir}]`."; help(file) -> "Comma separated list of files to load tests from. Equivalent to `[{file, File}]`."; help(module) -> "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`."; |