Configuration¶
Everything has a working default, so a repository that has configured nothing
still works: put a Markdown file in .changes, tag a commit, and the changelog
follows. Configuration is for what only the project knows — where its issues and
releases live — and for choices worth writing down.
The file¶
moneta reads omniblack.yaml, looking from the working directory up to the
repository root and using the first one it finds. The file is shared with the
other omniblack tools:
scopes:
- name: history
- name: render
- name: ci
internal: true
moneta:
strict-scopes: true
issues:
url: "https://gitlab.com/terryp/moneta/-/issues/{{ .ID }}"
releases:
url: "https://gitlab.com/terryp/moneta/-/releases/{{ .Tag }}"
scopes is at the top level because it is for commits as well as fragments:
moneta create offers it, and moneta commit-msg and moneta check --commits
check commit scopes against it. Everything that is moneta’s alone goes under
moneta:.
moneta ignores the top-level keys of other tools, so adding one does not break
it. A misspelled key under moneta: is an error, and so is a bad value. Both
are reported when the file is loaded, so a setting cannot silently do nothing.
An empty file, or a moneta: key with nothing under it, gives the defaults.
Moving from .moneta.yaml¶
moneta does not read .moneta.yaml. If one is nearer the working directory than
any omniblack.yaml, moneta stops with an error rather than rendering from the
defaults. With the defaults, the changelog would lose its issue and release
links without a warning. To move:
Put the contents of
.moneta.yamlundermoneta:inomniblack.yaml.Move
scopes.knownto a top-levelscopeslist, one- name:per scope.Rename
scopes.stricttomoneta.strict-scopes.Delete
.moneta.yaml.
Templates¶
moneta.filename, moneta.id, moneta.issues.url,
moneta.merge-requests.url and moneta.releases.url are Go text/templates.
moneta render --template uses the same language, so there is one to learn
rather than one per field.
Quote them. A YAML scalar that starts with {{ is a flow mapping, not a string.
Every template is tried when the file is loaded, against two different inputs.
moneta refuses the configuration if the template does not parse, names a field
that does not exist, or gives the same output for both inputs. The last one
catches a URL with no {{ .ID }} in it, which would link every issue to the
same page. These errors come at load, not in a published changelog.
Reference¶
Under moneta:¶
changes-dirWhere fragments live, relative to the repository root. Default:
.changes.tag-prefixWhat comes before the version number in a release tag. Default:
v. Set it to""for a project that tags1.2.0.tag-patternA glob that names the tags that are releases, in the syntax
git tag -luses. Default: none, and then a tag is a release only if it is a version undertag-prefix, so alatestor a deploy tag is not in the changelog. Set it when some version tags are not yours. For example, a repository that releases two components asa/v1.2.0andb/v0.3.0setstag-prefix: a/vandtag-pattern: "a/v*"for the changelog ofa. When you set a pattern, it is the only rule: a tag it matches is a release even if the tag is not a version. The pattern must matchtag-prefixfollowed by a version, and it must matchfirst-version. If it does not, moneta ignores the tags thatmoneta nextsuggests. To keep a changelog for each component, with fragments that say which component they are for, usemodulesinstead.first-versionWhat
moneta nextsuggests when there is no release yet. Default:v0.1.0.sinceIgnore every tag at or below this one. Default: none. A project that starts to use moneta later in its life has old tags with no
.changesdirectory. Those tags do no harm to attribution, but each one shows as an empty version. Setsinceto the last tag before moneta.yank-prefixThe tag namespace that withdraws a release:
yanked/v1.2.0yanksv1.2.0, and the tag’s annotation is the reason. Default:yanked/.contentWhere entry text comes from:
worktree,headoras-published. Default:worktree. It never changes which version an entry is in. Withmodules, it also says where a fragment’smodules:comes from.moneta render --contentoverrides it. Commands explains the three values.filenameThe name
moneta newandmoneta creategive a fragment. A template over.Slug,.Year,.Month,.Day,.Hour,.Minute,.Timestamp,.Kind,.Scope,.Moduleand.UUID. The time fields are UTC and zero-padded..Timestampis all of them in one word, such as20260925T143000Z..Scopeis every scope joined with-, and.Moduleis every module joined with-..UUIDis a new UUIDv7, the same oneidsees. Default:{{ .Slug }}-{{ .Year }}-{{ .Month }}-{{ .Day }}-{{ .Hour }}-{{ .Minute }}.md.idThe
id:thatmoneta new,moneta createandmoneta commitwrite into a fragment, so the fragment keeps its entry when it is moved or renamed. A template over the same fields asfilename. Default:{{ .UUID }}. Set it to""to write noid:; the filename stem is then the key. Entries of one kind are listed in key order, so with noid:put{{ .Timestamp }}first infilenameto keep them in the order they were written. A template that gives the same id to every fragment is an error, because fragments that share an id are one entry.strict-scopesReject a fragment whose scope is not in the top-level
scopes, or is internal. Default:false. Setting it with no scope that is not internal is an error, because then every fragment that has a scope would fail. Commit scopes do not use this setting: they are always checked against the list when there is one.kindsThe kinds of change, in the order the changelog shows them. Each has a
name, theheadingit renders under, and abumpofnone,patch,minorormajor. Akindslist replaces the default list. It does not add to it. Default: Keep a Changelog’s kinds.name
heading
bump
addedAdded
minor
changedChanged
minor
deprecatedDeprecated
minor
removedRemoved
major
fixedFixed
patch
securitySecurity
patch
pre-1.0.policyHow to bump below 1.0.
softenmakes a breaking change a minor bump and everything else a patch.stricttreats 0.x like any other major version. Default:soften.issues.urlMakes each issue reference a link. A template over
.ID, the reference as the fragment wrote it. Default: none, and references stay plain text.issues.requiredReject a fragment that has no
issues:. Default:false.merge-requests.urlThe same as
issues.url, for a fragment’smerge_requests:.check.require-fragmentMakes
moneta checkfail a branch that changes the project and adds no fragment, as if--require-fragmentwere given.--require-fragment=falseturns it off for one run. Default:false. Commands explains the gate.releases.urlMakes each release heading a link. A template over
.Tagand.Module. Only the version is the link. The date and the[YANKED]marker are outside it, and Unreleased is never a link, because it has no tag. Default: none.modulesSplits the repository into modules. Each module has its own tags, its own releases and its own changelog. Default: none, and the repository has one changelog. The Modules section below tells how they work. Each entry has these keys:
key
default
namerequired
Must be unique. No
/,,or whitespace.pathnone
The module’s directory, relative to the root. moneta uses the module when it runs in this directory.
tag-prefix<name>/vtag-pattern<tag-prefix>*Two modules must not match the same tag.
first-version<tag-prefix>0.1.0sincenone
A tag of this module.
releases.urlmoneta.releases.urlWhen you set
modules, the top-leveltag-prefix,tag-pattern,first-versionandsincehave no effect, so setting one is an error. Set them on each module.
Modules¶
Some repositories release more than one thing. With modules, each one has
its own tags and its own changelog:
moneta:
modules:
- name: core
path: core
- name: cli
path: cmd/cli
The tags are core/v1.2.0 and cli/v0.3.0. A yank works in the same way:
yanked/core/v1.2.0 withdraws core/v1.2.0.
The fragments stay in the one changes-dir. Each fragment names the modules
it is for:
---
kind: fixed
modules: [core, cli]
---
Read the configuration from the shared file.
A change to shared code often ships in more than one module. One fragment that names both modules says this once. Each module announces the entry in its own next release.
Each module’s changelog uses the same rule as a repository without modules. The only difference is that it uses the module’s tags and the fragments that name the module.
moneta reads modules: in the same way as the text of the fragment: from the
working tree. Thus you can correct it after a release, as you can correct a
typo:
If you add a module to a fragment after a release, the entry goes into the first release of that module whose tag holds the fragment. That is the release that shipped it.
If you remove a module from a fragment, the entry goes out of the changelog of that module, released versions too.
The tags still decide which release of the module holds the entry. If the
fragment is deleted, moneta reads modules: from the copy in the tag, as it
does for the text. --content as-published reads modules: from the tags for
every fragment, so each module shows what its tags shipped.
moneta check rejects a fragment that names no module, or a module that is not
in the list. Such a fragment is not in a changelog. A fragment that was written
before the repository had modules names none, and is not in any changelog. To
hide the old releases, set since on each module.
The commands that read a changelog (render, next, list) work on one
module. The Modules section of Commands tells how to select it.