-module(version_bump).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/version_bump.gleam").
-export([apply_dry_run/2, parse_args/1, main/0]).
-export_type([command/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" CLI entrypoint for version_bump, a native Gleam port of semantic-release.\n"
"\n"
" The default invocation runs the full release pipeline against the working\n"
" directory (`--cwd <path>`, default `.`):\n"
"\n"
" 1. read every environment variable into a `Dict(String, String)`\n"
" 2. load configuration from the project (`config.load`)\n"
" 3. apply CLI overrides (e.g. `--dry-run`)\n"
" 4. run `engine.run` and report the resulting `Summary`\n"
"\n"
" On error the formatted message is printed and the process exits non-zero.\n"
" `--version`/`version` prints the tool version; `--help`/`-h` prints usage.\n"
).
-type command() :: {release, binary(), boolean()} | show_version | show_help.
-file("src/version_bump.gleam", 149).
-spec usage() -> binary().
usage() ->
gleam@string:join(
[<<"version_bump "/utf8, "0.1.2"/utf8>>,
<<""/utf8>>,
<<"Usage:"/utf8>>,
<<" version_bump [--cwd <path>] [--dry-run] Run the release pipeline"/utf8>>,
<<" version_bump --version Print the version and exit"/utf8>>,
<<" version_bump --help Print this help and exit"/utf8>>,
<<""/utf8>>,
<<"Flags:"/utf8>>,
<<" --cwd <path> Run against the project at <path> (default: .)"/utf8>>,
<<" --dry-run Compute the next release without tagging or publishing"/utf8>>],
<<"\n"/utf8>>
).
-file("src/version_bump.gleam", 142).
?DOC(" Report an error to the log and exit non-zero.\n").
-spec fail(version_bump@error:release_error()) -> nil.
fail(Err) ->
version_bump@logging:error(version_bump@error:to_string(Err)),
version_bump_ffi:halt(1).
-file("src/version_bump.gleam", 133).
?DOC(" Print a human-readable summary of a successful (or no-op) run.\n").
-spec print_summary(version_bump@engine:summary()) -> nil.
print_summary(Summary) ->
case {erlang:element(2, Summary), erlang:element(3, Summary)} of
{true, {some, V}} ->
version_bump@logging:success(
<<"Published release "/utf8, V/binary>>
);
{false, {some, V@1}} ->
version_bump@logging:info(
<<"Dry-run: next release would be "/utf8, V@1/binary>>
);
{_, none} ->
version_bump@logging:info(<<"No release published"/utf8>>)
end.
-file("src/version_bump.gleam", 125).
?DOC(
" Apply the `--dry-run` flag, only ever turning dry-run on (the flag is an\n"
" override, never a way to force a real release when config disables it). Pure,\n"
" so it is unit-tested directly.\n"
).
-spec apply_dry_run(version_bump@config:config(), boolean()) -> version_bump@config:config().
apply_dry_run(Config, Dry_run) ->
case Dry_run of
true ->
{config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
true,
erlang:element(7, Config),
erlang:element(8, Config)};
false ->
Config
end.
-file("src/version_bump.gleam", 104).
?DOC(" Load config, apply the `--dry-run` override, run the pipeline, and report.\n").
-spec run_release(binary(), boolean()) -> nil.
run_release(Cwd, Dry_run) ->
Env = envoy_ffi:all(),
case version_bump@config:load(Cwd) of
{error, Err} ->
fail(Err);
{ok, Loaded} ->
Config = apply_dry_run(Loaded, Dry_run),
version_bump_task_ffi:run(
version_bump@engine:run(Config, Cwd, Env),
fun(Result) -> case Result of
{ok, Summary} ->
print_summary(Summary);
{error, Err@1} ->
fail(Err@1)
end end
)
end.
-file("src/version_bump.gleam", 78).
?DOC(" Walk the release flags, threading the working directory and dry-run state.\n").
-spec accumulate_release(list(binary()), binary(), boolean()) -> {ok, command()} |
{error, binary()}.
accumulate_release(Args, Cwd, Dry_run) ->
case Args of
[] ->
{ok, {release, Cwd, Dry_run}};
[<<"--dry-run"/utf8>> | Rest] ->
accumulate_release(Rest, Cwd, true);
[<<"--cwd"/utf8>>] ->
{error, <<"--cwd requires a path argument"/utf8>>};
[<<"--cwd"/utf8>>, Value | Rest@1] ->
case gleam_stdlib:string_starts_with(Value, <<"-"/utf8>>) of
true ->
{error, <<"--cwd requires a path argument"/utf8>>};
false ->
accumulate_release(Rest@1, Value, Dry_run)
end;
[Arg | Rest@2] ->
case gleam@string:split_once(Arg, <<"="/utf8>>) of
{ok, {<<"--cwd"/utf8>>, <<""/utf8>>}} ->
{error, <<"--cwd requires a path argument"/utf8>>};
{ok, {<<"--cwd"/utf8>>, Value@1}} ->
accumulate_release(Rest@2, Value@1, Dry_run);
_ ->
{error, <<"Unknown flag: "/utf8, Arg/binary>>}
end
end.
-file("src/version_bump.gleam", 73).
?DOC(
" Parse the flags accepted by the default (release) command: `--dry-run` and\n"
" `--cwd <path>` (the `--cwd=<path>` form is also accepted). Unknown flags are\n"
" rejected so the user gets clear feedback rather than a silent no-op.\n"
).
-spec parse_release_args(list(binary())) -> {ok, command()} | {error, binary()}.
parse_release_args(Args) ->
accumulate_release(Args, <<"."/utf8>>, false).
-file("src/version_bump.gleam", 59).
?DOC(
" Classify the raw arguments into a `Command`. Unknown flags are rejected so\n"
" the user gets clear feedback rather than a silent no-op. Pure, so it is\n"
" unit-tested directly.\n"
).
-spec parse_args(list(binary())) -> {ok, command()} | {error, binary()}.
parse_args(Args) ->
case gleam@list:contains(Args, <<"--version"/utf8>>) orelse gleam@list:contains(
Args,
<<"version"/utf8>>
) of
true ->
{ok, show_version};
false ->
case gleam@list:contains(Args, <<"--help"/utf8>>) orelse gleam@list:contains(
Args,
<<"-h"/utf8>>
) of
true ->
{ok, show_help};
false ->
parse_release_args(Args)
end
end.
-file("src/version_bump.gleam", 40).
-spec main() -> nil.
main() ->
Args = erlang:element(4, argv:load()),
case parse_args(Args) of
{ok, show_version} ->
gleam_stdlib:println(<<"0.1.2"/utf8>>);
{ok, show_help} ->
gleam_stdlib:println(usage());
{ok, {release, Cwd, Dry_run}} ->
run_release(Cwd, Dry_run);
{error, Message} ->
version_bump@logging:error(Message),
gleam_stdlib:println(usage()),
version_bump_ffi:halt(2)
end.