diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index 00e970cbf..e34eefd0e 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -828,7 +828,13 @@ format_skipped({User, Auto}) -> maybe_cover_compile(State) -> {RawOpts, _} = rebar_state:command_parsed_args(State), State1 = case proplists:get_value(cover, RawOpts, false) of - true -> rebar_state:set(State, cover_enabled, true); + true -> + S1 = rebar_state:set(State, cover_enabled, true), + CoverInclMods = case proplists:get_value(cover_incl_mods, RawOpts) of + undefined -> undefined; + Mods -> split_string(Mods) + end, + rebar_state:set(S1, cover_incl_mods, CoverInclMods); false -> State end, rebar_prv_cover:maybe_cover_compile(State1). @@ -856,6 +862,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_incl_mods, undefined, "cover_incl_mods", string, help(cover_incl_mods)}, %% comma-separated list {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 @@ -911,6 +918,8 @@ help(verbosity) -> "Verbosity"; help(cover) -> "Generate cover data"; +help(cover_incl_mods) -> + "List of modules to include for coverage"; help(cover_export_name) -> "Base name of the coverdata file to write"; help(repeat) -> diff --git a/src/rebar_prv_cover.erl b/src/rebar_prv_cover.erl index 611795d98..505251f09 100644 --- a/src/rebar_prv_cover.erl +++ b/src/rebar_prv_cover.erl @@ -45,9 +45,12 @@ do(State) -> -spec maybe_cover_compile(rebar_state:t()) -> ok. maybe_cover_compile(State) -> - maybe_cover_compile(State, apps). + case rebar_state:get(State, cover_incl_mods, undefined) of + undefined -> maybe_cover_compile(State, apps); + Mods -> maybe_cover_compile(State, {modules, Mods}) + end. --spec maybe_cover_compile(rebar_state:t(), [file:name()] | apps) -> ok. +-spec maybe_cover_compile(rebar_state:t(), [file:name()] | apps | {modules, [module()]}) -> ok. maybe_cover_compile(State, Dirs) -> case rebar_state:get(State, cover_enabled, false) of true -> cover_compile(State, Dirs); @@ -92,8 +95,14 @@ analyze(State) -> %% in order for cover data to be reloaded %% this maybe breaks if modules have been deleted %% since code coverage was collected? - {ok, S} = rebar_prv_compile:do(State), - ok = cover_compile(S, apps), + {ok, S1} = rebar_prv_compile:do(State), + {RawOpts, _} = rebar_state:command_parsed_args(S1), + CoverInclMods = case proplists:get_value(cover_incl_mods, RawOpts) of + undefined -> undefined; + Mods -> rebar_string:lexemes(Mods, [$,]) + end, + S2 = rebar_state:set(S1, cover_incl_mods, CoverInclMods), + ok = maybe_cover_compile(S2), do_analyze(State). do_analyze(State) -> @@ -319,6 +328,17 @@ cover_compile(State, apps) -> Apps = filter_checkouts_and_excluded(rebar_state:project_apps(State), ExclApps), AppDirs = app_dirs(Apps), cover_compile(State, lists:filter(fun(D) -> ec_file:is_dir(D) end, AppDirs)); +cover_compile(State, {modules, Mods}) -> + rebar_paths:set_paths([deps], State), + %% start the cover server if necessary + {ok, CoverPid} = start_cover(), + %% redirect cover output + true = redirect_cover_output(State, CoverPid), + ?DEBUG("cover compiling modules: ~p", [Mods]), + lists:foreach(fun(Module) -> + cover_compile_module(erlang:list_to_atom(Module)) + end, Mods), + ok; cover_compile(State, Dirs) -> rebar_paths:set_paths([deps], State), %% start the cover server if necessary @@ -354,6 +374,12 @@ is_ignored(Dir, File, ExclMods) -> Ignored andalso ?DEBUG("cover ignoring ~p ~p", [Dir, File]), Ignored. +cover_compile_module(Module) -> + case catch cover:compile_beam(Module) of + {ok, _} -> ok; + Error -> ?WARN("Cover compilation failed: ~p", [Error]) + end. + cover_compile_file(FileName) -> case catch(cover:compile_beam(FileName)) of {error, Reason} -> @@ -436,8 +462,10 @@ cover_dir(State) -> cover_opts(_State) -> [{reset, $r, "reset", boolean, help(reset)}, {verbose, $v, "verbose", boolean, help(verbose)}, + {cover_incl_mods, undefined, "cover_incl_mods", string, help(cover_incl_mods)}, %% comma-separated list {min_coverage, $m, "min_coverage", integer, help(min_coverage)}]. help(reset) -> "Reset all coverdata."; help(verbose) -> "Print coverage analysis."; +help(cover_incl_mods) -> "List of modules to include for coverage"; 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 6478d18a5..92bf3f13f 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -537,7 +537,13 @@ apply_sys_config(State) -> maybe_cover_compile(State) -> {RawOpts, _} = rebar_state:command_parsed_args(State), State1 = case proplists:get_value(cover, RawOpts, false) of - true -> rebar_state:set(State, cover_enabled, true); + true -> + S1 = rebar_state:set(State, cover_enabled, true), + CoverInclMods = case proplists:get_value(cover_incl_mods, RawOpts) of + undefined -> undefined; + Mods -> rebar_string:lexemes(Mods, [$,]) + end, + rebar_state:set(S1, cover_incl_mods, CoverInclMods); false -> State end, rebar_prv_cover:maybe_cover_compile(State1). @@ -561,6 +567,7 @@ eunit_opts(_State) -> [{app, undefined, "app", string, help(app)}, {application, undefined, "application", string, help(app)}, {cover, $c, "cover", boolean, help(cover)}, + {cover_incl_mods, undefined, "cover_incl_mods", string, help(cover_incl_mods)}, {cover_export_name, undefined, "cover_export_name", string, help(cover_export_name)}, {profile, $p, "profile", boolean, help(profile)}, {dir, $d, "dir", string, help(dir)}, @@ -577,6 +584,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_incl_mods) -> "List of modules to include for coverage"; help(cover_export_name) -> "Base name of the coverdata file to write"; help(profile) -> "Show the slowest tests. Defaults to false."; help(dir) -> "Comma separated list of dirs to load tests from. Equivalent to `[{dir, Dir}]`.";