cli.contributing.changelog.archive package

Submodules

cli.contributing.changelog.archive.archive_dir module

Filesystem operations on the docs/changelog/ archive directory.

Provides three primitives the rest of the package builds on:

cli.contributing.changelog.archive.archive_dir.archived_releases_from_directory(archive_dir: Path) → list[tuple[str, str]]

Return (version, date) tuples for every archive file under archive_dir, sorted descending so the newest release comes first.

cli.contributing.changelog.archive.archive_dir.build_index_section(archive_dir: Path, repo_root: Path) → str

Render the ## Older Releases block for the trimmed CHANGELOG.md. Returns "" when no archives exist.

cli.contributing.changelog.archive.archive_dir.existing_archives(archive_dir: Path) → list[Path]

Return every archive file under archive_dir sorted descending by filename. Returns [] when the directory does not exist.

cli.contributing.changelog.archive.changelog_md module

Parse and trim the CHANGELOG.md SPOT.

Three primitives:

  • split_into_entries() splits a CHANGELOG body by version headers and separates any pre-existing ## Older Releases block.

  • md_body_after_header() strips the version header line off an entry body so the remainder can be mirrored into package changelogs.

  • trim_and_archive() keeps the most recent N entries inline, writes every older one to its own file under the archive directory, and rebuilds the ## Older Releases index from the archive listing on every run.

cli.contributing.changelog.archive.changelog_md.md_body_after_header(full_body: str) → str

Strip the ## [version] - date header line off a CHANGELOG.md entry body and return the remaining markdown.

cli.contributing.changelog.archive.changelog_md.split_into_entries(content: str) → tuple[list[tuple[str, str, str]], str]

Split content by version headers.

Returns (entries, trailing) where entries is a list of (version, date, body) tuples and trailing is everything after the last version entry that opens with an archive header.

cli.contributing.changelog.archive.changelog_md.trim_and_archive(changelog_path: Path, archive_dir: Path, repo_root: Path, *, keep: int, dry_run: bool = False) → tuple[int, list[Path]]

Trim changelog_path to keep entries, archive every older release as its own file under archive_dir, and rebuild the ## Older Releases index from the archive directory listing.

The index is rebuilt on every run so it cannot drift from what is on disk: a manually deleted index gets restored, and a stale link to a removed archive gets dropped. The function stays byte-idempotent: when the resulting content matches what is already on disk, the file is not rewritten.

Returns (kept, archive_paths) where archive_paths is the list of newly-written or to-be-written archive files (empty when no entry was displaced past keep).

cli.contributing.changelog.archive.package_mirror module

Mirror the kept CHANGELOG.md entries into the package changelogs.

Both targets (Debian changelog and the RPM %changelog section) are fully regenerated on every run from the kept entries plus an archived-releases notice that points at the documentation site and lists the archived versions and dates as plain text. The notice is folded into the body of the oldest kept entry (not appended after the last entry), because free text after the final entry is not valid changelog data and makes the native parsers warn. Because the package files are regenerated, they cannot drift from the CHANGELOG.md SPOT.

Footer block listing every archived release as plain text and pointing at DOCS_URL for the full history. No links.

cli.contributing.changelog.archive.package_mirror.format_debian_entry(version: str, date_iso: str, body_md: str, maintainer: str, footer_md: str = '') → str

Render one CHANGELOG.md entry as a Debian changelog stanza.

Every non-empty line of the markdown body gets a two-space indent so Debian’s parser accepts it: each change line MUST start with at least two spaces, otherwise dpkg treats it as a badly formatted line, loses the entry boundary and reports an empty maintainer. Blank lines stay blank.

footer_md (the archived-releases notice) is folded into this entry’s change body — indented like the rest — rather than appended after the trailer, because free text after the final -- line is not valid changelog data and makes dpkg-parsechangelog warn. The signature time is a placeholder because CHANGELOG.md only carries calendar dates.

cli.contributing.changelog.archive.package_mirror.format_rpm_entry(version: str, date_iso: str, body_md: str, maintainer: str, footer_md: str = '') → str

Render one CHANGELOG.md entry as an RPM %changelog stanza.

Every non-empty body line gets a - `` continuation prefix so rpm does not read a markdown ``* bullet at column 0 as a new changelog entry header (which makes rpmspec report bad date). Blank lines stay blank. footer_md (the archived-releases notice) is folded into this entry’s body for the same reason it is on the Debian side: trailing free text confuses the parser.

cli.contributing.changelog.archive.package_mirror.mirror_to_debian_changelog(path: Path, entries: list[tuple[str, str, str]], archived: list[tuple[str, str]], *, maintainer: str = 'Kevin Veen-Birkenbach <kevin@veen.world>', dry_run: bool = False) → bool

Regenerate the Debian changelog at path from CHANGELOG.md.

entries is the list of (version, date, body_markdown) tuples for the kept releases. archived is the list of (version, date) tuples for older releases that go into the trailing notice.

Returns True when the file was rewritten, False when nothing happened (no entries or dry run).

cli.contributing.changelog.archive.package_mirror.mirror_to_rpm_spec_changelog(path: Path, entries: list[tuple[str, str, str]], archived: list[tuple[str, str]], *, maintainer: str = 'Kevin Veen-Birkenbach <kevin@veen.world>', dry_run: bool = False) → bool

Regenerate the %changelog section of an RPM spec file at path from CHANGELOG.md.

The file’s pre-%changelog head is preserved verbatim. The %changelog section is replaced with one stanza per entry plus the trailing notice. Returns True when the file was rewritten, False when nothing happened (missing file, no %changelog section, no entries, or dry run).

cli.contributing.changelog.archive.versioning module

Version-string padding and the archive filename schema.

Archive files are named <padded-semver>-<date>.md so that a plain directory listing already sorts them in chronological order. The padding zero-fills each numeric component of the semver to three digits, so 7.0.0 becomes 007.000.000. Pre-release and build suffixes (1.2.3-rc1, 1.2.3+meta) are preserved verbatim and tacked onto the padded core version.

cli.contributing.changelog.archive.versioning.archive_filename(version: str, date: str) → str

Return the canonical archive filename for (version, date).

cli.contributing.changelog.archive.versioning.pad_version(version: str) → str

Zero-pad each numeric component of version to three digits.

cli.contributing.changelog.archive.versioning.unpad_version(padded: str) → str

Inverse of pad_version(). 007.000.000 → 7.0.0.

Module contents