Reads Conventional Commits from git log and produces a per-app bump plan.
Inputs
since— git ref to use as the lower bound (last release tag, etc.). Whennil, auto-detected from the most recentv*tag, falling back to the full history.config— the:commitssection ofReleaser.Config.load/0(bump_rules,breaking_bump,breaking_markers,scope_aliases,no_scope).apps— list of%Releaser.App{}fromReleaser.Workspace.discover/1.
Output
A list of %{app: name, bump: :major | :minor | :patch, commits: [Commit.t()]}
for each app that receives a bump. Apps with no relevant commits are
omitted entirely — callers should treat missing apps as "no bump".
Breaking detection
A commit is breaking if any of the configured breaking_markers applies:
:bang—feat(xml)!: subject:body—BREAKING CHANGE:orBREAKING-CHANGE:in the body
Breaking commits always use breaking_bump (default :major) regardless
of type.
Aggregation
For each app, the highest bump among relevant commits wins:
major > minor > patch > none. No summation — 10 feat commits still
produce a single :minor bump.
Summary
Functions
Returns the most recent tag matching v*, or nil when there is none.
Parses the raw output of git log (with @log_separator) into a list of
commit maps. Exposed for testing.
Returns a list of plan entries for apps that should bump.
Reads git log <range> --format=... and returns raw output.
Exposed so tests can replace it with a fixture.
Types
@type bump() :: :major | :minor | :patch | :none
Functions
@spec detect_last_tag() :: String.t() | nil
Returns the most recent tag matching v*, or nil when there is none.
Parses the raw output of git log (with @log_separator) into a list of
commit maps. Exposed for testing.
@spec plan(keyword()) :: [plan_entry()]
Returns a list of plan entries for apps that should bump.
When no commits are relevant (or --since resolves to HEAD), returns [].
Reads git log <range> --format=... and returns raw output.
Exposed so tests can replace it with a fixture.