Skip to content

Commit

Permalink
Add --doc-dir option for circumventing doc providers (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
starbelly authored Dec 21, 2021
1 parent 8b5fbf7 commit 9f1ac0f
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 52 deletions.
61 changes: 40 additions & 21 deletions src/rebar3_hex_build.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-module(rebar3_hex_build).

-export([create_package/3, create_docs/3]).
-export([create_package/3, create_docs/3, create_docs/4]).

-include("rebar3_hex.hrl").

Expand Down Expand Up @@ -153,19 +153,17 @@ known_exclude_file(Path, ExcludeRe) ->
has_checkouts(State) ->
filelib:is_dir(rebar_dir:checkouts_dir(State)).

-dialyzer({nowarn_function, create_docs/3}).
create_docs(State, Repo, App) ->
case maybe_gen_docs(State, Repo) of
{ok, _State1} ->
AppDir = rebar_app_info:dir(App),
AppOpts = rebar_app_info:opts(App),
EdocOpts = rebar_opts:get(AppOpts, edoc_opts, []),
AppDetails = rebar_app_info:app_details(App),
Dir = proplists:get_value(dir, EdocOpts, ?DEFAULT_DOC_DIR),
DocDir = proplists:get_value(doc, AppDetails, Dir),
IndexFile = filename:join(AppDir, DocDir) ++ "/index.html",
case filelib:is_file(IndexFile) of
create_docs(State, Repo, App, #{doc_dir => undefined}).

-dialyzer({nowarn_function, create_docs/4}).
create_docs(State, Repo, App, Args) ->
case maybe_gen_docs(State, Repo, App, Args) of
{ok, DocDir} ->
case docs_detected(DocDir) of
true ->
AppDir = rebar_app_info:dir(App),
AppDetails = rebar_app_info:app_details(App),
Files = rebar3_hex_file:expand_paths([DocDir], AppDir),
Name = rebar_utils:to_list(rebar_app_info:name(App)),
PkgName = rebar_utils:to_list(proplists:get_value(pkg_name, AppDetails, Name)),
Expand Down Expand Up @@ -194,32 +192,53 @@ create_docs(State, Repo, App) ->
{error, Err}
end.

maybe_gen_docs(State, Repo) ->
maybe_gen_docs(_State, _Repo, App, #{doc_dir := DocDir}) when is_list(DocDir) ->
AppDir = rebar_app_info:dir(App),
{ok, filename:absname(filename:join(AppDir, DocDir))};
maybe_gen_docs(State, Repo, App, _Args) ->
case doc_opts(State, Repo) of
{ok, #{provider := PrvName}} ->
{ok, PrvName} ->
case providers:get_provider(PrvName, rebar_state:providers(State)) of
not_found ->
{error, doc_provider_not_found};
{error, {doc_provider_not_found, PrvName}};
Prv ->
case providers:do(Prv, State) of
{ok, State1} ->
{ok, State1};
{ok, _State1} ->
{ok, resolve_dir(App, PrvName)};
_ ->
{error, doc_provider_failed}
{error, {doc_provider_failed, PrvName}}
end
end;
_ ->
{error, no_doc_config}
end.

resolve_dir(App, PrvName) ->
AppDir = rebar_app_info:dir(App),
AppOpts = rebar_app_info:opts(App),
DocOpts =
case PrvName of
edoc ->
rebar_opts:get(AppOpts, edoc_opts, []);
_ ->
rebar_opts:get(AppOpts, PrvName, [])
end,
DocDir = proplists:get_value(dir, DocOpts, ?DEFAULT_DOC_DIR),
filename:absname(filename:join(AppDir, DocDir)).

docs_detected(DocDir) ->
filelib:is_file(DocDir ++ "/index.html").

doc_opts(State, Repo) ->
case Repo of
#{doc := DocOpts} when is_map(DocOpts) ->
{ok, DocOpts};
#{doc := #{provider := PrvName}} when is_atom(PrvName) ->
{ok, PrvName};
_ ->
Opts = rebar_state:opts(State),
case proplists:get_value(doc, rebar_opts:get(Opts, hex, []), undefined) of
DocOpts when is_map(DocOpts) -> {ok, DocOpts};
undefined -> undefined;
PrvName when is_atom(PrvName) -> {ok, PrvName};
#{provider := PrvName} -> {ok, PrvName};
_ -> undefined
end
end.
Expand Down
53 changes: 28 additions & 25 deletions src/rebar3_hex_publish.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ init(State) ->
{opts, [rebar3_hex:repo_opt(),
{yes, $y, "yes", {boolean, false}, help(yes)},
{app, $a, "app", {string, undefined}, help(app)},
{dry_run, undefined, "dry-run", {boolean, false}, help(dry_run)},
{doc_dir, undefined, "doc-dir", {string, undefined}, help(yes)},
{dry_run, undefined, "dry-run", {boolean, false}, help(dry_run)},
{replace, undefined, "replace", {boolean, false}, help(replace)},
{revert, undefined, "revert", string, help(revert)}]}]),
State1 = rebar_state:add_provider(State, Provider),
Expand Down Expand Up @@ -80,7 +81,7 @@ format_error({invalid_licenses, Invalids, AppName}) ->
format_error({invalid_semver, {AppName, Version}}) ->
Err = "~ts.app.src : non-semantic version number \"~ts\" found",
io_lib:format(Err, [AppName, Version]);
format_error({invalid_semver_arg, Vsn}) ->
format_error({invalid_semver_arg, Vsn}) ->
io_lib:format("The version argument provided \"~s\" is not a valid semantic version.", [Vsn]);
format_error({has_unstable_deps, Deps}) ->
MainMsg = "The following pre-release dependencies were found : ",
Expand All @@ -96,11 +97,11 @@ format_error({app_not_found, AppName}) ->
io_lib:format("App ~s specified with --app switch not found in project", [AppName]);
format_error(bad_command) ->
"bad command";
format_error({publish_package, app_switch_required}) ->
format_error({publish_package, app_switch_required}) ->
"--app required when publishing with the package argument in a umbrella";
format_error({publish_docs, app_switch_required}) ->
format_error({publish_docs, app_switch_required}) ->
"--app required when publishing with the docs argument in a umbrella";
format_error({revert, app_switch_required}) ->
format_error({revert, app_switch_required}) ->
"--app required when reverting in a umbrella with multiple apps";
format_error({required, repo}) ->
"publish requires a repo name argument to identify the repo to publish to";
Expand All @@ -116,6 +117,8 @@ format_error({publish, {error, #{<<"errors">> := Errors, <<"message">> := Messag
io_lib:format("Failed to publish package: ~ts~n\t~ts", [Message, ErrorString]);
format_error({publish, {error, #{<<"message">> := Message}}}) ->
io_lib:format("Failed to publish package: ~ts", [Message]);
format_error({create_docs, {error, {doc_provider_not_found, PrvName}}}) ->
io_lib:format("The ~ts documentation provider could not be found", [PrvName]);
format_error({non_hex_deps, Excluded}) ->
Err = "Can not publish package because the following deps are not available"
++ " in hex: ~s",
Expand Down Expand Up @@ -236,10 +239,10 @@ handle_task(#{args := #{app := AppName}, apps := Apps, multi_app := true} = Tas
-dialyzer({nowarn_function, publish/4}).
publish(State, Repo, App, Args) ->
{ok, HexConfig} = write_config(Repo),
case publish_package(State, HexConfig, App, Args) of
abort ->
case publish_package(State, HexConfig, App, Args) of
abort ->
{ok, State};
_ ->
_ ->
publish_docs(State, HexConfig, App, Args)
end.

Expand All @@ -260,7 +263,7 @@ publish_package(State, Repo, App, Args) ->
proceed ->
HexOpts = hex_opts(Args),
rebar_api:info("package argument given, will not publish docs", []),
#{tarball := Tarball} = Package,
#{tarball := Tarball} = Package,
case rebar3_hex_client:publish(Repo, Tarball, HexOpts) of
{ok, _Res} ->
#{name := Name, version := Version} = Package,
Expand All @@ -274,11 +277,11 @@ publish_package(State, Repo, App, Args) ->
abort
end.

create_package(State, Repo, App) ->
create_package(State, Repo, App) ->
case rebar3_hex_build:create_package(State, Repo, App) of
{ok, Package} ->
{ok, Package} ->
Package;
Err ->
Err ->
?RAISE({create_package, Err})
end.

Expand Down Expand Up @@ -338,7 +341,7 @@ maybe_prompt(_Args, Message) ->

hex_opts(Opts) ->
lists:filter(fun({replace, _}) -> true;
({_,_}) -> false
({_,_}) -> false
end,
maps:to_list(Opts)).

Expand All @@ -347,7 +350,7 @@ hex_opts(Opts) ->
%%% ===================================================================

publish_docs(State, Repo, App, Args) ->
#{tarball := Tar, name := Name, vsn := Vsn} = create_docs(State, Repo, App),
#{tarball := Tar, name := Name, vsn := Vsn} = create_docs(State, Repo, App, Args),
case Args of
#{dry_run := true} ->
rebar_api:info("--dry-run enabled : will not publish docs.", []),
Expand All @@ -362,11 +365,11 @@ publish_docs(State, Repo, App, Args) ->
end
end.

create_docs(State, Repo, App) ->
case rebar3_hex_build:create_docs(State, Repo, App) of
create_docs(State, Repo, App, Args) ->
case rebar3_hex_build:create_docs(State, Repo, App, Args) of
{ok, Docs} ->
Docs;
Err ->
Err ->
?RAISE({create_docs, Err})
end.

Expand All @@ -380,7 +383,7 @@ revert_package(State, Repo, AppName, Vsn) ->
assert_valid_version_arg(BinVsn),
{ok, HexConfig} = write_config(Repo),
case rebar3_hex_client:delete_release(HexConfig, BinAppName, BinVsn) of
{ok, _} ->
{ok, _} ->
rebar_api:info("Successfully deleted package ~ts ~ts", [AppName, Vsn]),
Prompt = io_lib:format("Also delete tag v~ts?", [Vsn]),
case rebar3_hex_io:ask(Prompt, boolean, "N") of
Expand Down Expand Up @@ -429,19 +432,19 @@ assert_valid_app(State, App) ->
case rebar3_hex_app:validate(AppData) of
ok ->
{ok, State};
{error, #{warnings := Warnings, errors := Errors}} ->
{error, #{warnings := Warnings, errors := Errors}} ->
lists:foreach(fun(W) -> rebar_log:log(warn, format_error(W), []) end, Warnings),
case Errors of
[] ->
case Errors of
[] ->
{ok, State};
Errs ->
Errs ->
?RAISE({validation_errors, Errs})
end
end.

assert_valid_version_arg(Vsn) ->
assert_valid_version_arg(Vsn) ->
case verl:parse(Vsn) of
{ok, _} ->
{ok, _} ->
ok;
_ ->
?RAISE({invalid_semver_arg, Vsn})
Expand Down Expand Up @@ -500,6 +503,6 @@ support() ->
" <repo> - a valid repository, only required when multiple repositories are configured~n~n"
" <version> - a valid version string, currently only utilized with --revert switch~n~n".

write_config(Repo) ->
write_config(Repo) ->
assert_has_write_key(Repo),
rebar3_hex_config:hex_config_write(Repo).
25 changes: 21 additions & 4 deletions test/rebar3_hex_build_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ all() ->
create_docs_test,
create_docs_unknown_provider_test,
create_docs_no_provider_test,
create_docs_doc_dir_test,
create_docs_doc_dir_missing_test,
create_docs_provider_failure_test
].

Expand Down Expand Up @@ -68,19 +70,34 @@ create_docs_unknown_provider_test(Config) ->
StubConfig = #{type => app, dir => data_dir(Config), name => "valid"},
{State, Repo, App} = test_utils:make_stub(StubConfig),
Repo1 = Repo#{doc => #{provider => foo}},
?assertMatch({error, doc_provider_not_found}, rebar3_hex_build:create_docs(State, Repo1, App)).
?assertMatch({error, {doc_provider_not_found, foo}}, rebar3_hex_build:create_docs(State, Repo1, App)).

create_docs_no_provider_test(Config) ->
StubConfig = #{type => app, dir => data_dir(Config), name => "valid"},
StubConfig = #{type => app, dir => data_dir(Config), name => "no_doc_config"},
{State, Repo, App} = test_utils:make_stub(StubConfig),
Repo1 = Repo#{doc => #{}},
Repo1 = maps:remove(doc, Repo),
?assertMatch({error, no_doc_config}, rebar3_hex_build:create_docs(State, Repo1, App)).

create_docs_doc_dir_test(Config) ->
#{dir := RootDir} = StubConfig = #{type => app, dir => data_dir(Config), name => "doc_attr"},
{State, Repo, App} = test_utils:make_stub(StubConfig),
DocDir = filename:join([RootDir, "doc_attr", "doc"]),
test_utils:mkdir_p(DocDir),
ok = file:write_file(filename:join([DocDir, "index.html"]), "eh?"),
Repo1 = Repo#{doc => #{}},
?assertMatch({ok, _Docs}, rebar3_hex_build:create_docs(State, Repo1, App, #{doc_dir => "doc"})).

create_docs_doc_dir_missing_test(Config) ->
StubConfig = #{type => app, dir => data_dir(Config), name => "doc_attr"},
{State, Repo, App} = test_utils:make_stub(StubConfig),
Repo1 = Repo#{doc => #{}},
?assertMatch({ok, _Docs}, rebar3_hex_build:create_docs(State, Repo1, App, #{doc_dir => "doc"})).

create_docs_provider_failure_test(Config) ->
StubConfig = #{type => app, dir => data_dir(Config), name => "valid"},
{State, Repo, App} = test_utils:make_stub(StubConfig),
Repo1 = Repo#{doc => #{provider => bad_doc}},
{ok, State1} = bad_doc_provider:init(State),
?assertMatch({error, doc_provider_failed}, rebar3_hex_build:create_docs(State1, Repo1, App)).
?assertMatch({error, {doc_provider_failed, bad_doc}}, rebar3_hex_build:create_docs(State1, Repo1, App)).

data_dir(Config) -> ?config(priv_dir, Config).
3 changes: 1 addition & 2 deletions test/support/test_utils.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-module(test_utils).

-export([make_stub/1, stub_app/1, mock_command/4, repo_config/0, repo_config/1]).
-export([mkdir_p/1, make_stub/1, stub_app/1, mock_command/4, repo_config/0, repo_config/1]).

-define(REPO_CONFIG, maps:merge(hex_core:default_config(), #{
name => <<"hexpm">>,
Expand Down Expand Up @@ -42,7 +42,6 @@ make_stub(#{type := app, name := Name, dir := Dir} = StubConfig) ->
_ConfigFile = write_config_file(AppDir, StubConfig1),
_LockFile = write_lock_file(AppDir, StubConfig1),
#{repo := Repo} = StubConfig1,
%%Setup = stub_project(StubConfig1),
State = init_state(AppDir, Repo, StubConfig1),
{ok, App} = rebar3_hex_app:find(rebar_state:project_apps(State), Name),
{ok, State1} = rebar_prv_edoc:init(State),
Expand Down

0 comments on commit 9f1ac0f

Please sign in to comment.