-module(version_bump@config).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/version_bump/config.gleam").
-export([default/0, parse_package_json_config/1, parse_gleam_toml_config/1, parse_toml_config/1, parse_json_config/1, load/1]).
-export_type([plugin_spec/0, branch_config/0, config/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(
" Configuration shapes plus the entry point for loading config from a project.\n"
" The `load` implementation (reading .releaserc / release.config / package.json)\n"
" is fleshed out by the config module work; the type is owned here so every\n"
" other module can depend on it without a cycle.\n"
).
-type plugin_spec() :: {plugin_spec,
binary(),
gleam@dict:dict(binary(), binary())}.
-type branch_config() :: {branch_config,
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary())}.
-type config() :: {config,
gleam@option:option(binary()),
binary(),
list(branch_config()),
list(plugin_spec()),
boolean(),
boolean(),
version_bump@semver:versioning_mode()}.
-file("src/version_bump/config.gleam", 58).
?DOC(
" The default configuration for a Gleam project: commit analysis, release\n"
" notes, publishing to Hex, and a GitHub release, over the conventional release\n"
" branches. (This is the Gleam-first analogue of semantic-release's defaults,\n"
" which publish to npm; swap `hex` for `npm` to release a JavaScript package.)\n"
).
-spec default() -> config().
default() ->
{config,
none,
<<"v${version}"/utf8>>,
[{branch_config, <<"main"/utf8>>, none, none, none},
{branch_config, <<"master"/utf8>>, none, none, none},
{branch_config,
<<"next"/utf8>>,
{some, <<"next"/utf8>>},
none,
none},
{branch_config,
<<"beta"/utf8>>,
none,
{some, <<"beta"/utf8>>},
none},
{branch_config,
<<"alpha"/utf8>>,
none,
{some, <<"alpha"/utf8>>},
none}],
[{plugin_spec, <<"commit-analyzer"/utf8>>, maps:new()},
{plugin_spec, <<"release-notes-generator"/utf8>>, maps:new()},
{plugin_spec, <<"hex"/utf8>>, maps:new()},
{plugin_spec, <<"git"/utf8>>, maps:new()},
{plugin_spec, <<"github"/utf8>>, maps:new()}],
false,
true,
stable}.
-file("src/version_bump/config.gleam", 83).
?DOC(" Map the boolean `initial_development` config key to a `VersioningMode`.\n").
-spec versioning_mode_of(boolean()) -> version_bump@semver:versioning_mode().
versioning_mode_of(Initial_development) ->
case Initial_development of
true ->
initial_development;
false ->
stable
end.
-file("src/version_bump/config.gleam", 154).
?DOC(
" Read a file, returning `Some(contents)` when it can be read and `None`\n"
" otherwise. Unreadable or missing files are treated as absent so the loader\n"
" falls through to the next candidate (and ultimately to `default()`).\n"
).
-spec read_if_present(binary()) -> gleam@option:option(binary()).
read_if_present(Path) ->
case simplifile:read(Path) of
{ok, Contents} ->
{some, Contents};
{error, _} ->
none
end.
-file("src/version_bump/config.gleam", 163).
?DOC(
" Join a directory and a filename with a single `/` separator, tolerating a\n"
" trailing slash on the directory.\n"
).
-spec join_path(binary(), binary()) -> binary().
join_path(Dir, Name) ->
case gleam_stdlib:string_ends_with(Dir, <<"/"/utf8>>) of
true ->
<<Dir/binary, Name/binary>>;
false ->
<<<<Dir/binary, "/"/utf8>>/binary, Name/binary>>
end.
-file("src/version_bump/config.gleam", 135).
-spec try_sources(
binary(),
list({binary(),
fun((binary()) -> {ok, config()} |
{error, version_bump@error:release_error()})})
) -> gleam@option:option({ok, config()} |
{error, version_bump@error:release_error()}).
try_sources(Cwd, Sources) ->
case Sources of
[] ->
none;
[{Filename, Parser} | Rest] ->
Path = join_path(Cwd, Filename),
case read_if_present(Path) of
{some, Contents} ->
{some, Parser(Contents)};
none ->
try_sources(Cwd, Rest)
end
end.
-file("src/version_bump/config.gleam", 326).
-spec describe_decode_error(gleam@dynamic@decode:decode_error()) -> binary().
describe_decode_error(Err) ->
<<<<<<<<"expected "/utf8, (erlang:element(2, Err))/binary>>/binary,
", found "/utf8>>/binary,
(erlang:element(3, Err))/binary>>/binary,
(case erlang:element(4, Err) of
[] ->
<<""/utf8>>;
Path ->
<<" at "/utf8, (gleam@string:join(Path, <<"."/utf8>>))/binary>>
end)/binary>>.
-file("src/version_bump/config.gleam", 315).
-spec describe_json_error(gleam@json:decode_error()) -> binary().
describe_json_error(Err) ->
case Err of
unexpected_end_of_input ->
<<"unexpected end of input"/utf8>>;
{unexpected_byte, Byte} ->
<<"unexpected byte "/utf8, Byte/binary>>;
{unexpected_sequence, Seq} ->
<<"unexpected sequence "/utf8, Seq/binary>>;
{unable_to_decode, Errors} ->
<<"unable to decode: "/utf8,
(gleam@string:join(
gleam@list:map(Errors, fun describe_decode_error/1),
<<"; "/utf8>>
))/binary>>
end.
-file("src/version_bump/config.gleam", 306).
?DOC(
" Decode any scalar JSON value (string / bool / int / float) into its string\n"
" form. Values that are not scalars decode to an empty string.\n"
).
-spec scalar_to_string_decoder() -> gleam@dynamic@decode:decoder(binary()).
scalar_to_string_decoder() ->
gleam@dynamic@decode:one_of(
{decoder, fun gleam@dynamic@decode:decode_string/1},
[begin
_pipe = {decoder, fun gleam@dynamic@decode:decode_bool/1},
gleam@dynamic@decode:map(_pipe, fun gleam@bool:to_string/1)
end,
begin
_pipe@1 = {decoder, fun gleam@dynamic@decode:decode_int/1},
gleam@dynamic@decode:map(
_pipe@1,
fun erlang:integer_to_binary/1
)
end,
begin
_pipe@2 = {decoder, fun gleam@dynamic@decode:decode_float/1},
gleam@dynamic@decode:map(
_pipe@2,
fun gleam_stdlib:float_to_string/1
)
end,
gleam@dynamic@decode:success(<<""/utf8>>)]
).
-file("src/version_bump/config.gleam", 300).
?DOC(
" Plugin options are kept as a string-keyed dictionary of stringified scalar\n"
" values. Non-scalar values (nested objects / arrays) are skipped, since the\n"
" core keeps options as strings and individual plugins reparse what they need.\n"
).
-spec options_decoder() -> gleam@dynamic@decode:decoder(gleam@dict:dict(binary(), binary())).
options_decoder() ->
gleam@dynamic@decode:dict(
{decoder, fun gleam@dynamic@decode:decode_string/1},
scalar_to_string_decoder()
).
-file("src/version_bump/config.gleam", 285).
?DOC(
" A plugin entry is either a bare string (the module name with no options) or\n"
" a two-element array of `[name, options]`.\n"
).
-spec plugin_decoder() -> gleam@dynamic@decode:decoder(plugin_spec()).
plugin_decoder() ->
String_plugin = begin
_pipe = {decoder, fun gleam@dynamic@decode:decode_string/1},
gleam@dynamic@decode:map(
_pipe,
fun(Name) -> {plugin_spec, Name, maps:new()} end
)
end,
Array_plugin = begin
gleam@dynamic@decode:field(
0,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Name@1) ->
gleam@dynamic@decode:optional_field(
1,
maps:new(),
options_decoder(),
fun(Options) ->
gleam@dynamic@decode:success(
{plugin_spec, Name@1, Options}
)
end
)
end
)
end,
gleam@dynamic@decode:one_of(String_plugin, [Array_plugin]).
-file("src/version_bump/config.gleam", 271).
?DOC(
" `prerelease` may be given as a string (the identifier) or as `true`, in\n"
" which case the branch name is used as the identifier. We can only know the\n"
" name in the object case, so a bare `true` maps to an empty identifier that\n"
" branch resolution can later default from the name.\n"
).
-spec prerelease_decoder() -> gleam@dynamic@decode:decoder(gleam@option:option(binary())).
prerelease_decoder() ->
As_bool = begin
_pipe = {decoder, fun gleam@dynamic@decode:decode_bool/1},
gleam@dynamic@decode:map(_pipe, fun(B) -> case B of
true ->
{some, <<""/utf8>>};
false ->
none
end end)
end,
gleam@dynamic@decode:one_of(
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
[As_bool]
).
-file("src/version_bump/config.gleam", 241).
?DOC(
" A branch entry is either a bare string (the branch name) or an object with\n"
" a `name` plus optional `channel`, `prerelease`, and `range` keys.\n"
).
-spec branch_decoder() -> gleam@dynamic@decode:decoder(branch_config()).
branch_decoder() ->
String_branch = begin
_pipe = {decoder, fun gleam@dynamic@decode:decode_string/1},
gleam@dynamic@decode:map(
_pipe,
fun(Name) -> {branch_config, Name, none, none, none} end
)
end,
Object_branch = begin
gleam@dynamic@decode:field(
<<"name"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Name@1) ->
gleam@dynamic@decode:optional_field(
<<"channel"/utf8>>,
none,
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
fun(Channel) ->
gleam@dynamic@decode:optional_field(
<<"prerelease"/utf8>>,
none,
prerelease_decoder(),
fun(Prerelease) ->
gleam@dynamic@decode:optional_field(
<<"range"/utf8>>,
none,
gleam@dynamic@decode:optional(
{decoder,
fun gleam@dynamic@decode:decode_string/1}
),
fun(Range) ->
gleam@dynamic@decode:success(
{branch_config,
Name@1,
Channel,
Prerelease,
Range}
)
end
)
end
)
end
)
end
)
end,
gleam@dynamic@decode:one_of(String_branch, [Object_branch]).
-file("src/version_bump/config.gleam", 199).
?DOC(
" Decode a `Config`, starting from `default()` and overriding each field that\n"
" is present in the document.\n"
).
-spec config_decoder() -> gleam@dynamic@decode:decoder(config()).
config_decoder() ->
D = default(),
gleam@dynamic@decode:optional_field(
<<"repositoryUrl"/utf8>>,
erlang:element(2, D),
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
fun(Repository_url) ->
gleam@dynamic@decode:optional_field(
<<"tagFormat"/utf8>>,
erlang:element(3, D),
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Tag_format) ->
gleam@dynamic@decode:optional_field(
<<"branches"/utf8>>,
erlang:element(4, D),
gleam@dynamic@decode:list(branch_decoder()),
fun(Branches) ->
gleam@dynamic@decode:optional_field(
<<"plugins"/utf8>>,
erlang:element(5, D),
gleam@dynamic@decode:list(plugin_decoder()),
fun(Plugins) ->
gleam@dynamic@decode:optional_field(
<<"dryRun"/utf8>>,
erlang:element(6, D),
{decoder,
fun gleam@dynamic@decode:decode_bool/1},
fun(Dry_run) ->
gleam@dynamic@decode:optional_field(
<<"ci"/utf8>>,
erlang:element(7, D),
{decoder,
fun gleam@dynamic@decode:decode_bool/1},
fun(Ci) ->
gleam@dynamic@decode:optional_field(
<<"initialDevelopment"/utf8>>,
false,
{decoder,
fun gleam@dynamic@decode:decode_bool/1},
fun(Initial_development) ->
gleam@dynamic@decode:success(
{config,
Repository_url,
Tag_format,
Branches,
Plugins,
Dry_run,
Ci,
versioning_mode_of(
Initial_development
)}
)
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/version_bump/config.gleam", 184).
?DOC(
" Parse the `\"release\"` object out of a `package.json` document. If there is\n"
" no `\"release\"` key the project simply has no semantic-release config there,\n"
" so the defaults are returned.\n"
).
-spec parse_package_json_config(binary()) -> {ok, config()} |
{error, version_bump@error:release_error()}.
parse_package_json_config(Json_string) ->
Release_decoder = begin
gleam@dynamic@decode:optional_field(
<<"release"/utf8>>,
default(),
config_decoder(),
fun(Release) -> gleam@dynamic@decode:success(Release) end
)
end,
_pipe = gleam@json:parse(Json_string, Release_decoder),
gleam@result:map_error(
_pipe,
fun(Err) ->
{config_error,
<<"invalid package.json: "/utf8,
(describe_json_error(Err))/binary>>}
end
).
-file("src/version_bump/config.gleam", 535).
-spec toml_scalar_to_string(tom:toml()) -> gleam@option:option(binary()).
toml_scalar_to_string(Value) ->
case Value of
{string, S} ->
{some, S};
{bool, B} ->
{some, gleam@bool:to_string(B)};
{int, I} ->
{some, erlang:integer_to_binary(I)};
{float, F} ->
{some, gleam_stdlib:float_to_string(F)};
_ ->
none
end.
-file("src/version_bump/config.gleam", 525).
-spec toml_table_string(gleam@dict:dict(binary(), tom:toml()), binary()) -> gleam@option:option(binary()).
toml_table_string(Fields, Key) ->
case gleam_stdlib:map_get(Fields, Key) of
{ok, Value} ->
toml_scalar_to_string(Value);
{error, _} ->
none
end.
-file("src/version_bump/config.gleam", 516).
-spec toml_options(gleam@dict:dict(binary(), tom:toml())) -> gleam@dict:dict(binary(), binary()).
toml_options(Fields) ->
gleam@dict:fold(
Fields,
maps:new(),
fun(Acc, Key, Value) -> case toml_scalar_to_string(Value) of
{some, S} ->
gleam@dict:insert(Acc, Key, S);
none ->
Acc
end end
).
-file("src/version_bump/config.gleam", 496).
-spec toml_plugin(tom:toml()) -> plugin_spec().
toml_plugin(Value) ->
case Value of
{string, Name} ->
{plugin_spec, Name, maps:new()};
{array, Items} ->
case Items of
[{string, Name@1}, {inline_table, Opts}] ->
{plugin_spec, Name@1, toml_options(Opts)};
[{string, Name@1}, {table, Opts}] ->
{plugin_spec, Name@1, toml_options(Opts)};
[{string, Name@2}] ->
{plugin_spec, Name@2, maps:new()};
_ ->
{plugin_spec, <<""/utf8>>, maps:new()}
end;
{inline_table, Fields} ->
{plugin_spec,
begin
_pipe = toml_table_string(Fields, <<"name"/utf8>>),
gleam@option:unwrap(_pipe, <<""/utf8>>)
end,
maps:new()};
{table, Fields} ->
{plugin_spec,
begin
_pipe = toml_table_string(Fields, <<"name"/utf8>>),
gleam@option:unwrap(_pipe, <<""/utf8>>)
end,
maps:new()};
_ ->
{plugin_spec, <<""/utf8>>, maps:new()}
end.
-file("src/version_bump/config.gleam", 430).
?DOC(" Prefix a key path with the `[tools.version_bump]` table location.\n").
-spec sr(list(binary())) -> list(binary()).
sr(Keys) ->
lists:append([<<"tools"/utf8>>, <<"version_bump"/utf8>>], Keys).
-file("src/version_bump/config.gleam", 469).
?DOC(
" Merge any `[tools.version_bump.plugin_options.<name>]` sub-tables into the\n"
" matching plugin specs' options.\n"
).
-spec apply_plugin_options(
list(plugin_spec()),
gleam@dict:dict(binary(), tom:toml())
) -> list(plugin_spec()).
apply_plugin_options(Plugins, Table) ->
gleam@list:map(
Plugins,
fun(Spec) ->
case tom:get_table(
Table,
sr([<<"plugin_options"/utf8>>, erlang:element(2, Spec)])
) of
{ok, Opts} ->
{plugin_spec,
erlang:element(2, Spec),
maps:merge(erlang:element(3, Spec), toml_options(Opts))};
{error, _} ->
Spec
end
end
).
-file("src/version_bump/config.gleam", 482).
-spec toml_branch(tom:toml()) -> branch_config().
toml_branch(Value) ->
case Value of
{string, Name} ->
{branch_config, Name, none, none, none};
{inline_table, Fields} ->
{branch_config,
begin
_pipe = toml_table_string(Fields, <<"name"/utf8>>),
gleam@option:unwrap(_pipe, <<""/utf8>>)
end,
toml_table_string(Fields, <<"channel"/utf8>>),
toml_table_string(Fields, <<"prerelease"/utf8>>),
toml_table_string(Fields, <<"range"/utf8>>)};
{table, Fields} ->
{branch_config,
begin
_pipe = toml_table_string(Fields, <<"name"/utf8>>),
gleam@option:unwrap(_pipe, <<""/utf8>>)
end,
toml_table_string(Fields, <<"channel"/utf8>>),
toml_table_string(Fields, <<"prerelease"/utf8>>),
toml_table_string(Fields, <<"range"/utf8>>)};
_ ->
{branch_config, <<""/utf8>>, none, none, none}
end.
-file("src/version_bump/config.gleam", 452).
?DOC(
" The host for a gleam.toml `[repository]` field, by its `type` (falling back to\n"
" an explicit `host` key for `type = \"custom\"`).\n"
).
-spec repository_host(gleam@dict:dict(binary(), tom:toml())) -> gleam@option:option(binary()).
repository_host(Table) ->
case tom:get_string(Table, [<<"repository"/utf8>>, <<"type"/utf8>>]) of
{ok, <<"github"/utf8>>} ->
{some, <<"github.com"/utf8>>};
{ok, <<"gitlab"/utf8>>} ->
{some, <<"gitlab.com"/utf8>>};
{ok, <<"bitbucket"/utf8>>} ->
{some, <<"bitbucket.org"/utf8>>};
{ok, <<"codeberg"/utf8>>} ->
{some, <<"codeberg.org"/utf8>>};
{ok, <<"sourcehut"/utf8>>} ->
{some, <<"git.sr.ht"/utf8>>};
_ ->
case tom:get_string(Table, [<<"repository"/utf8>>, <<"host"/utf8>>]) of
{ok, Host} ->
{some, Host};
{error, _} ->
none
end
end.
-file("src/version_bump/config.gleam", 436).
?DOC(
" Derive a repository URL from gleam.toml's standard `[repository]` field, e.g.\n"
" `repository = { type = \"github\", user = \"u\", repo = \"r\" }` -> the GitHub URL.\n"
).
-spec derive_repository_url(gleam@dict:dict(binary(), tom:toml())) -> gleam@option:option(binary()).
derive_repository_url(Table) ->
case {tom:get_string(Table, [<<"repository"/utf8>>, <<"user"/utf8>>]),
tom:get_string(Table, [<<"repository"/utf8>>, <<"repo"/utf8>>])} of
{{ok, User}, {ok, Repo}} ->
case repository_host(Table) of
{some, Host} ->
{some,
<<<<<<<<<<"https://"/utf8, Host/binary>>/binary,
"/"/utf8>>/binary,
User/binary>>/binary,
"/"/utf8>>/binary,
Repo/binary>>};
none ->
none
end;
{_, _} ->
none
end.
-file("src/version_bump/config.gleam", 390).
?DOC(
" Parse the `[tools.version_bump]` table out of a `gleam.toml` — the\n"
" Gleam-native config location. Keys use snake_case (`tag_format`, `dry_run`,\n"
" `branches`, `plugins`). `repository_url` is taken from the table if present,\n"
" otherwise derived from gleam.toml's standard `[repository]` field. Per-plugin\n"
" options live in `[tools.version_bump.plugin_options.<name>]` sub-tables.\n"
"\n"
" A `gleam.toml` with no `[tools.version_bump]` table still yields a working\n"
" config (defaults plus the derived repository URL). Exposed for testing.\n"
).
-spec parse_gleam_toml_config(binary()) -> {ok, config()} |
{error, version_bump@error:release_error()}.
parse_gleam_toml_config(Toml_string) ->
gleam@result:'try'(
begin
_pipe = tom:parse(Toml_string),
gleam@result:map_error(
_pipe,
fun(_) -> {config_error, <<"invalid gleam.toml"/utf8>>} end
)
end,
fun(Table) ->
D = default(),
Repository_url = case tom:get_string(
Table,
sr([<<"repository_url"/utf8>>])
) of
{ok, Url} ->
{some, Url};
{error, _} ->
gleam@option:'or'(
derive_repository_url(Table),
erlang:element(2, D)
)
end,
Tag_format = begin
_pipe@1 = tom:get_string(Table, sr([<<"tag_format"/utf8>>])),
gleam@result:unwrap(_pipe@1, erlang:element(3, D))
end,
Dry_run = begin
_pipe@2 = tom:get_bool(Table, sr([<<"dry_run"/utf8>>])),
gleam@result:unwrap(_pipe@2, erlang:element(6, D))
end,
Ci = begin
_pipe@3 = tom:get_bool(Table, sr([<<"ci"/utf8>>])),
gleam@result:unwrap(_pipe@3, erlang:element(7, D))
end,
Initial_development = begin
_pipe@4 = tom:get_bool(
Table,
sr([<<"initial_development"/utf8>>])
),
gleam@result:unwrap(_pipe@4, false)
end,
Branches = case tom:get_array(Table, sr([<<"branches"/utf8>>])) of
{ok, Items} ->
gleam@list:map(Items, fun toml_branch/1);
{error, _} ->
erlang:element(4, D)
end,
Plugins = case tom:get_array(Table, sr([<<"plugins"/utf8>>])) of
{ok, Items@1} ->
apply_plugin_options(
gleam@list:map(Items@1, fun toml_plugin/1),
Table
);
{error, _} ->
erlang:element(5, D)
end,
{ok,
{config,
Repository_url,
Tag_format,
Branches,
Plugins,
Dry_run,
Ci,
versioning_mode_of(Initial_development)}}
end
).
-file("src/version_bump/config.gleam", 341).
?DOC(
" Parse a TOML configuration document, merging recognised keys over the\n"
" defaults. Exposed for testing.\n"
).
-spec parse_toml_config(binary()) -> {ok, config()} |
{error, version_bump@error:release_error()}.
parse_toml_config(Toml_string) ->
gleam@result:'try'(
begin
_pipe = tom:parse(Toml_string),
gleam@result:map_error(
_pipe,
fun(_) -> {config_error, <<"invalid TOML config"/utf8>>} end
)
end,
fun(Table) ->
D = default(),
Repository_url = case tom:get_string(
Table,
[<<"repositoryUrl"/utf8>>]
) of
{ok, Url} ->
{some, Url};
{error, _} ->
erlang:element(2, D)
end,
Tag_format = begin
_pipe@1 = tom:get_string(Table, [<<"tagFormat"/utf8>>]),
gleam@result:unwrap(_pipe@1, erlang:element(3, D))
end,
Dry_run = begin
_pipe@2 = tom:get_bool(Table, [<<"dryRun"/utf8>>]),
gleam@result:unwrap(_pipe@2, erlang:element(6, D))
end,
Ci = begin
_pipe@3 = tom:get_bool(Table, [<<"ci"/utf8>>]),
gleam@result:unwrap(_pipe@3, erlang:element(7, D))
end,
Initial_development = begin
_pipe@4 = tom:get_bool(Table, [<<"initialDevelopment"/utf8>>]),
gleam@result:unwrap(_pipe@4, false)
end,
Branches = case tom:get_array(Table, [<<"branches"/utf8>>]) of
{ok, Items} ->
gleam@list:map(Items, fun toml_branch/1);
{error, _} ->
erlang:element(4, D)
end,
Plugins = case tom:get_array(Table, [<<"plugins"/utf8>>]) of
{ok, Items@1} ->
gleam@list:map(Items@1, fun toml_plugin/1);
{error, _} ->
erlang:element(5, D)
end,
{ok,
{config,
Repository_url,
Tag_format,
Branches,
Plugins,
Dry_run,
Ci,
versioning_mode_of(Initial_development)}}
end
).
-file("src/version_bump/config.gleam", 174).
?DOC(
" Parse a JSON configuration document, merging any recognised keys over the\n"
" defaults. Unknown keys are ignored. Exposed for testing.\n"
).
-spec parse_json_config(binary()) -> {ok, config()} |
{error, version_bump@error:release_error()}.
parse_json_config(Json_string) ->
_pipe = gleam@json:parse(Json_string, config_decoder()),
gleam@result:map_error(
_pipe,
fun(Err) ->
{config_error,
<<"invalid JSON config: "/utf8,
(describe_json_error(Err))/binary>>}
end
).
-file("src/version_bump/config.gleam", 123).
?DOC(
" Walk the candidate sources in order, returning the parsed config (or parse\n"
" error) for the first source that exists, or `None` if none exist.\n"
).
-spec find_and_parse(binary()) -> gleam@option:option({ok, config()} |
{error, version_bump@error:release_error()}).
find_and_parse(Cwd) ->
Json_files = gleam@list:map(
[<<".releaserc.json"/utf8>>,
<<".releaserc"/utf8>>,
<<"release.config.json"/utf8>>],
fun(Name) -> {Name, fun parse_json_config/1} end
),
Sources = lists:append(
Json_files,
[{<<".releaserc.toml"/utf8>>, fun parse_toml_config/1},
{<<"gleam.toml"/utf8>>, fun parse_gleam_toml_config/1},
{<<"package.json"/utf8>>, fun parse_package_json_config/1}]
),
try_sources(Cwd, Sources).
-file("src/version_bump/config.gleam", 114).
?DOC(
" Load configuration from the project rooted at `cwd`, falling back to\n"
" `default()` when no config file is present.\n"
"\n"
" The lookup order is:\n"
" 1. `.releaserc.json`\n"
" 2. `.releaserc` (parsed as JSON)\n"
" 3. `release.config.json`\n"
" 4. `.releaserc.toml` (parsed as TOML)\n"
" 5. `[tools.version_bump]` in `gleam.toml` (the Gleam-native location;\n"
" also derives `repository_url` from the `[repository]` field)\n"
" 6. the `\"release\"` key of `package.json`\n"
"\n"
" The first file that exists and parses wins; its values are merged over\n"
" `default()`. Since every Gleam project has a `gleam.toml`, step 5 means a\n"
" Gleam package needs no separate config file: with no `[tools.version_bump]`\n"
" table it still releases using the defaults plus the derived repository URL.\n"
" When nothing is found, `Ok(default())` is returned.\n"
).
-spec load(binary()) -> {ok, config()} |
{error, version_bump@error:release_error()}.
load(Cwd) ->
case find_and_parse(Cwd) of
{some, Result} ->
Result;
none ->
{ok, default()}
end.