Resolves the baseline of an app: the last version that was actually released.
A cascade bump is a relative operation — it only makes sense against a fixed
reference point. Using the working-tree mix.exs version as that reference is
wrong, because a bump mutates exactly that value: run two bumps before
committing and the second one measures from the first one's output, bumping
an app twice for a single release cycle.
The baseline answers "what version of this app does the world already have?" and is resolved from the first source that knows, in descending authority:
- Hex — a published release is ground truth.
- Git tags —
<app>-v<version>, as emitted byReleaser.Hooks.GitTag. Covers projects that commit and tag on bump but publish later. - Git HEAD — the version in
mix.exsat HEAD. Covers the common flow where bump leaves the working tree dirty and the commit comes later.
When no source knows the app (never published, no tags, not in git), the
baseline is nil and callers fall back to bumping unconditionally.
Injecting sources
:sources overrides the chain with a list of (App.t() -> String.t() | nil)
functions. Tests use this to avoid touching the network or the repository.
Summary
Functions
Returns the highest version among tags scoped to app_name, or nil.
Resolves the baseline version of a single app, or nil when unknown.
Resolves baselines for many apps at once, returning %{app_name => baseline}.
Types
@type source() :: (Releaser.App.t() -> String.t() | nil)
Functions
Returns the highest version among tags scoped to app_name, or nil.
Tags are matched on the exact <app_name>-v prefix, so ex_pdf never picks up
an ex_pdf_components-v2.0.0 tag. Comparison is semantic, not lexicographic:
1.0.10 outranks 1.0.9. Malformed tags are ignored.
Resolves the baseline version of a single app, or nil when unknown.
Sources are consulted in order and the first parseable version wins; a source
returning nil or a malformed version falls through to the next.
Resolves baselines for many apps at once, returning %{app_name => baseline}.
Each distinct app is resolved exactly once, and resolutions run concurrently —
the Hex source shells out to mix hex.info per app, so a serial chain would
make every bump pay the sum of those round-trips. A source that hangs past
:timeout (default 30000ms) yields nil for that app rather
than failing the bump.