Skip to main content

rebar.config

%% `warn_missing_spec` (which livery enforces) is intentionally absent:
%% gpb-generated `_pb` modules do not spec their introspection functions,
%% so they cannot satisfy it. Hand-written modules carry specs and
%% dialyzer enforces types.
%%
%% Generated `*_pb` modules are kept out of every style/static check:
%% erlfmt (exclude_files), elvis (ignore regex), and xref (xref_ignores).
%% `proto/helloworld.proto` is a test fixture; a consumer application runs
%% the gpb plugin against its own protos.
{erl_opts, [debug_info, warnings_as_errors]}.

%% `livery` is declared as a dependency so it joins the build graph; the
%% local `_checkouts/livery` symlink overrides the source (no hex fetch for
%% livery itself). Its transitive deps (h1, h2, ...) are fetched from hex.
%% `gpb` is the protobuf runtime used by generated modules and the codec.
%% h2 >= 0.10.0 (within 0.10.x) is required directly, overriding livery's
%% transitive 0.9.0, for its bidirectional-streaming support: per-stream
%% event routing, send and receive backpressure, and per-stream cancel.
{deps, [
    {livery, "0.3.0"},
    {h2, "~> 0.10.0"},
    {gpb, "5.0.0"}
]}.

%% Compile proto/*.proto -> src/*_pb.erl (maps mode) before erl compile.
{gpb_opts, [
    {i, "proto"},
    {module_name_suffix, "_pb"},
    {o_erl, "src"},
    %% Maps mode generates no .hrl, so point this at src (which always
    %% exists) rather than an empty include/ dir that is absent on a fresh
    %% clone and would break the build.
    {o_hrl, "src"},
    {strings_as_binaries, true},
    {maps, true},
    {maps_unset_optional, omitted},
    type_specs,
    %% Emit descriptor/0,1 returning the file's FileDescriptorProto bytes,
    %% which the reflection service serves to clients.
    descriptor,
    {report_warnings, true}
]}.

{provider_hooks, [
    {pre, [
        {compile, {protobuf, compile}},
        {clean, {protobuf, clean}}
    ]}
]}.

%% Generated protobuf modules carry gpb's internal helpers, some unused
%% per message set. Keep them out of xref's unused-locals analysis.
{xref_ignores, [helloworld_pb, health_pb, reflection_pb, route_guide_pb]}.

{shell, [
    {apps, [livery_grpc]}
]}.

{cover_enabled, true}.
{cover_opts, [verbose]}.
{eunit_opts, [verbose]}.

{xref_checks, [
    undefined_function_calls,
    undefined_functions,
    locals_not_used,
    deprecated_function_calls,
    deprecated_functions
]}.

{dialyzer, [
    {warnings, [unmatched_returns, error_handling, unknown]},
    {plt_extra_apps, [livery, h2, gpb, crypto, ssl, public_key]}
]}.

{project_plugins, [
    {erlfmt, "1.7.0"},
    {rebar3_lint, "4.1.1"},
    {rebar3_gpb_plugin, "3.0.1"},
    rebar3_ex_doc
]}.

{erlfmt, [
    write,
    {files, [
        "{src,include,test,examples}/**/*.{hrl,erl,app.src}",
        "rebar.config"
    ]},
    %% Generated protobuf modules are not hand-edited.
    {exclude_files, ["src/*_pb.erl", "include/*_pb.hrl"]}
]}.

{ex_doc, [
    {source_url, <<"https://github.com/benoitc/livery_grpc">>},
    {main, <<"readme">>},
    {extras, [
        {"README.md", #{title => <<"Overview">>}},
        {"docs/overview.md", #{title => <<"Introduction">>}},
        {"docs/core-concepts.md", #{title => <<"Core concepts">>}},
        {"docs/getting-started.md", #{title => <<"Getting started">>}},
        {"docs/basics-tutorial.md", #{title => <<"Basics tutorial">>}},
        {"docs/guides/streaming.md", #{title => <<"Streaming">>}},
        {"docs/guides/metadata.md", #{title => <<"Metadata">>}},
        {"docs/guides/interceptors.md", #{title => <<"Interceptors">>}},
        {"docs/guides/deadlines.md", #{title => <<"Deadlines">>}},
        {"docs/guides/cancellation.md", #{title => <<"Cancellation">>}},
        {"docs/guides/error-handling.md", #{title => <<"Error handling">>}},
        {"docs/guides/status-codes.md", #{title => <<"Status codes">>}},
        {"docs/guides/compression.md", #{title => <<"Compression">>}},
        {"docs/guides/authentication.md", #{title => <<"Authentication">>}},
        {"docs/guides/health-checking.md", #{title => <<"Health checking">>}},
        {"docs/guides/reflection.md", #{title => <<"Reflection">>}},
        {"docs/guides/retry.md", #{title => <<"Retry">>}},
        {"docs/guides/graceful-shutdown.md", #{title => <<"Graceful shutdown">>}},
        {"docs/guides/flow-control.md", #{title => <<"Flow control">>}},
        {"docs/guides/wait-for-ready.md", #{title => <<"Wait for ready">>}},
        {"docs/guides/grpc-web.md", #{title => <<"gRPC-Web">>}},
        {"docs/guides/generated-stubs.md", #{title => <<"Generated stubs">>}},
        {"docs/guides/erlang-integration.md", #{title => <<"Integrate into an Erlang app">>}},
        {"docs/guides/testing.md", #{title => <<"Testing">>}},
        {"docs/design.md", #{title => <<"Design">>}},
        {"CHANGELOG.md", #{title => <<"Changelog">>}}
    ]},
    {groups_for_extras, [
        {<<"Start here">>, [
            <<"docs/overview.md">>,
            <<"docs/core-concepts.md">>,
            <<"docs/getting-started.md">>
        ]},
        {<<"Tutorial">>, [<<"docs/basics-tutorial.md">>]},
        {<<"Guides">>, [
            <<"docs/guides/streaming.md">>,
            <<"docs/guides/metadata.md">>,
            <<"docs/guides/interceptors.md">>,
            <<"docs/guides/deadlines.md">>,
            <<"docs/guides/cancellation.md">>,
            <<"docs/guides/error-handling.md">>,
            <<"docs/guides/status-codes.md">>,
            <<"docs/guides/compression.md">>,
            <<"docs/guides/authentication.md">>,
            <<"docs/guides/health-checking.md">>,
            <<"docs/guides/reflection.md">>,
            <<"docs/guides/retry.md">>,
            <<"docs/guides/graceful-shutdown.md">>,
            <<"docs/guides/flow-control.md">>,
            <<"docs/guides/wait-for-ready.md">>,
            <<"docs/guides/grpc-web.md">>,
            <<"docs/guides/generated-stubs.md">>,
            <<"docs/guides/erlang-integration.md">>,
            <<"docs/guides/testing.md">>
        ]},
        {<<"Design">>, [<<"docs/design.md">>]},
        {<<"Project">>, [<<"CHANGELOG.md">>]}
    ]},
    {groups_for_modules, [
        {<<"Server and client">>, [livery_grpc, livery_grpc_server, livery_grpc_client]},
        {<<"Streaming and codegen">>, [
            livery_grpc_stream, livery_grpc_service, livery_grpc_codegen
        ]},
        {<<"Built-in services">>, [livery_grpc_reflection, livery_grpc_health]},
        {<<"Wire format">>, [
            livery_grpc_wire,
            livery_grpc_frame,
            livery_grpc_codec,
            livery_grpc_compression,
            livery_grpc_status,
            livery_grpc_timeout,
            livery_grpc_web
        ]},
        {<<"Runtime">>, [livery_grpc_app, livery_grpc_sup, livery_grpc_health_store]}
    ]}
]}.

{hex, [{doc, #{provider => ex_doc}}]}.

{elvis, [
    #{
        dirs => ["src"],
        filter => "*.erl",
        %% Generated protobuf modules (`*_pb.erl`) are not linted. elvis
        %% matches this regex against the file path.
        ignore => ["_pb\\.erl$"],
        rules => [
            {elvis_style, no_macros, disable},
            {elvis_style, no_common_caveats_call, disable},
            {elvis_style, no_init_lists, disable},
            {elvis_style, param_pattern_matching, disable},
            %% The health Watch relay blocks on receive until a status
            %% change or the client disconnect; an after clause is wrong.
            {elvis_style, no_receive_without_timeout, #{ignore => [livery_grpc_health]}},
            %% gen_server using a bare #state{} record, as livery does for
            %% its own gen_servers.
            {elvis_style, state_record_and_type, #{
                ignore => [livery_grpc_health_store, livery_grpc_listener]
            }},
            {elvis_style, no_spec_with_records, #{ignore => [livery_grpc_health_store]}},
            %% These dispatch to the gpb-generated proto module by design
            %% (Mod:encode_msg, Proto:get_service_def, ...).
            {elvis_style, invalid_dynamic_call, #{
                ignore => [
                    livery_grpc_codec,
                    livery_grpc_service,
                    livery_grpc_server,
                    livery_grpc_client,
                    livery_grpc_reflection,
                    livery_grpc_codegen
                ]
            }}
        ],
        ruleset => erl_files_strict
    },
    #{
        dirs => ["."],
        filter => "rebar.config",
        rules => [
            {elvis_project, no_branch_deps, disable}
        ],
        ruleset => rebar_config
    }
]}.

{profiles, [
    {test, [
        {erl_opts, [debug_info, nowarn_export_all, nowarn_missing_spec]},
        {deps, [{proper, "1.4.0"}]},
        %% Compile examples/ in the test profile so the example modules
        %% (route_guide, greeter_example) can be exercised by tests.
        {extra_src_dirs, [{"examples", [{recursive, false}]}]}
    ]},
    {examples, [
        {extra_src_dirs, [{"examples", [{recursive, false}]}]},
        {erl_opts, [debug_info, nowarn_missing_spec]}
    ]}
]}.