Files
computer-playbook/docs/contributing/actions/release.md
T
kevinveenbirkenbachandClaude Opus 4.7 66badf258e refactor(changelog): split archive CLI into per-responsibility modules
Break cli/contributing/changelog/archive/__main__.py into four
single-responsibility modules under the same package:

* versioning.py — pad_version / unpad_version / archive_filename
  (the canonical <padded-semver>-<date>.md filename schema).
* archive_dir.py — existing_archives, archived_releases_from_directory,
  build_index_section (filesystem operations on docs/changelog/).
* changelog_md.py — split_into_entries, md_body_after_header,
  trim_and_archive (CHANGELOG.md parsing and trimming, plus the
  always-rebuild-index logic).
* package_mirror.py — mirror_to_debian_changelog,
  mirror_to_rpm_spec_changelog (Debian and RPM regeneration from
  CHANGELOG.md kept entries, with the trailing notice that points at
  docs.infinito.nexus and lists archived versions as plain text).

__main__.py shrinks to argparse plus a thin orchestration layer that
parses CHANGELOG.md once, runs trim_and_archive, reads the populated
archive directory, and mirrors into the package files.

Add `mirror_to_debian_changelog` and `mirror_to_rpm_spec_changelog`
content-idempotency: skip the write when the regenerated content
already matches what is on disk so re-runs leave file mtimes
unchanged. Verified end-to-end: a follow-up run on a fully-processed
tree leaves all three files (CHANGELOG.md, Debian changelog, RPM
spec) byte-identical and mtime-stable.

Replace `datetime.strptime` calls with `date.fromisoformat` so the
DTZ007 lint stays clean: we only need calendar-date parsing for
display formatting, not timezone-aware moments.

Tests follow the same split: one test_<module>.py per source module,
40 tests in total. Shared fixtures live in _helpers.py (underscore
prefix exempts it from the test-file-naming lint), and each test
class explicitly mixes TempRepoMixin with unittest.TestCase so the
test-files-have-tests AST lint sees the direct unittest base.

Update docs/contributing/actions/release.md so the procedure
description matches the current behaviour: package changelogs are
"mirrored" (not "trimmed") from CHANGELOG.md, and the idempotence
section calls out byte-idempotency on each of the three files.

Run the CLI once against the live tree to bring packaging/debian/
changelog and packaging/fedora/infinito-nexus.spec back into sync
with CHANGELOG.md and the docs/changelog/ archive directory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:19:42 +02:00

4.7 KiB

Release 🚀

Contributor guidance for cutting a tagged release of Infinito.Nexus. For local-deploy and edit/redeploy guidance see deploy.md. For commit-message conventions see commit.md.

Versioning 🔢

Release tags follow Semantic Versioning with a leading v: v<MAJOR>.<MINOR>.<PATCH> (for example v7.0.0).

Component Bump when
MAJOR A change is incompatible with prior inventories, on-disk role-meta layout, deploy CLI, or stored runtime state.
MINOR New roles, new CLI surfaces, or a non-breaking schema extension lands.
PATCH Bug fixes, doc fixes, or test-only changes that do not move public surface.

Pre-release suffixes (-rc1, -alpha2, +build.5) MAY be appended; the archive CLI preserves them in archived filenames.

Active Window vs. Archive 🗂️

CHANGELOG.md at the repository root holds the most recent releases inline. Older releases live one-file-per-version under docs/changelog/, linked from the ## Older Releases section at the bottom of the active changelog.

The active window has a default retention of 7 entries. A higher count is fine for short bursts of releases, but the active changelog SHOULD stay short enough that scrolling it is cheap.

Cutting a Release ✂️

  1. Update CHANGELOG.md: prepend a new ## [<version>] - <YYYY-MM-DD> section with the change set, written in the same style as the existing entries. When the release ships package metadata, also update packaging/debian/changelog and the %changelog section of packaging/fedora/infinito-nexus.spec with the corresponding entries.

  2. Trim CHANGELOG.md and mirror its kept entries into the package changelogs:

    python -m cli.contributing.changelog.archive
    

    The CLI keeps the most recent 7 entries (override with --keep N) and processes each of the following files:

    • CHANGELOG.md is trimmed; every older entry is written to its own file under docs/changelog/ named <padded-semver>-<release-date>.md, and the ## Older Releases index at the bottom of the active changelog is rebuilt from the archive directory listing so it never drifts away from what is on disk.
    • packaging/debian/changelog and the %changelog section of packaging/fedora/infinito-nexus.spec are regenerated from the kept CHANGELOG.md entries, with a trailing notice that points at docs.infinito.nexus for further releases and a plain-text list of the archived versions and their dates (no links).

    Pass --dry-run to preview without writing.

  3. Run make test locally and confirm everything is green.

  4. Commit the changelog and any archive additions in a single commit with subject Release version <MAJOR>.<MINOR>.<PATCH> (matching the historical convention).

  5. Tag the commit: git tag -a v<MAJOR>.<MINOR>.<PATCH> -m "Release version <MAJOR>.<MINOR>.<PATCH>".

  6. Push the branch and the tag with git-sign-push, running it outside the sandbox.

CI on Tag Push 🤖

A v* tag push fans out into two CI workflows:

Workflow Purpose
release-version.yml Backfills CI images for the version tag if missing, retags them to release tags, and publishes the version-specific image set.
release-highest.yml Decides whether the new version is the highest published version and, if so, advances the latest floating tag.

Both run from the trusted workflow ref and check out the version tag for the actual build payload, so the release artefacts match the tagged commit byte-for-byte.

Idempotence 🔁

The archive CLI is byte-idempotent. Re-running it on an already-processed tree leaves every file unchanged: CHANGELOG.md is rewritten only when its target content differs from disk, the per-release archive files are never overwritten, and the package changelogs are only rewritten when the regenerated content differs from disk. This makes it safe to run from a pre-commit hook, a release script, or by hand without keeping track of state.