On this page
Cleanup utilities for per-package .rlsbl/ directories after releasable model migration, removing orphaned changelog and release state files from the old...
#rlsbl.releasable_cleanup
#rlsbl.releasable_cleanup
Cleanup utilities for per-package .rlsbl/ directories after releasable model migration, removing orphaned changelog and release state files from the old layout.
When a workspace uses explicit-mode releasables, changelog and release state moves to per-releasable directories under .rlsbl-monorepo/releasables/{name}/. The per-package .rlsbl/changes/ and .rlsbl/releases/ directories become dead state that should be removed.
These functions are intended for use by migration tooling (Phase 10), not for automatic invocation during scaffold or release.
#cleanup_per_package_release_state
def cleanup_per_package_release_state(workspace_root, projects=None, releasables=None, dry_run=False)Remove per-package .rlsbl/ state for packages in explicit-mode releasables.
Only acts when the workspace is in explicit mode ([[releasables]] is defined in workspace.toml). For each project that belongs to a releasable (releasable is a string, not False), removes:
.rlsbl/changes/-- changelog state (moved to releasable level).rlsbl/releases/-- release state (moved to releasable level).rlsbl/bases/-- merge bases (moved to releasable level).rlsbl/version-- rlsbl scaffold version fileCHANGELOG.md-- generated changelog (now per-releasable).rlsbl/config.json-- only when identical to the releasable-level config.rlsbl/lint/-- only when byte-identical to the releasable-level lint config
Exemptions (never removed):
.rlsbl/hooks/-- per-package script hooks are a live feature.- Members whose path resolves to the workspace root: the root
.rlsbl/ and root CHANGELOG.md are workspace-level files (e.g. the combined root changelog), not per-package residue.
Uses saferm for removal so there is an audit trail and the files are recoverable.
Args:
workspace_root: path to the monorepo root (containing .rlsbl-monorepo/).projects: optional pre-loaded list of WorkspaceProject. If None, loads
from workspace.toml.
releasables: optional pre-loaded list of Releasable. If None, loads
from workspace.toml.
dry_run: when True, only collect and return the paths that WOULD be
removed; nothing is deleted.
Returns:
- A list of paths that were removed (or would be removed under
dry_run). Empty if nothing to clean.
Raises:
RuntimeError: if saferm is not available on PATH.subprocess.CalledProcessError: if saferm fails for a path.
#run_cleanup_command
def run_cleanup_command(workspace_root, *, dry_run=False)CLI entry for rlsbl monorepo cleanup.
Removes per-package release-state residue from releasable member packages (via :func:cleanup_per_package_release_state, which uses saferm for an audit trail), then commits the deletions so the working tree stays clean.
Returns the list of removed (or would-be-removed) paths.
#verify_minimal_rlsbl
def verify_minimal_rlsbl(project_path)Return unexpected files/dirs in .rlsbl/ for a releasable member package.
After cleanup, a per-package .rlsbl/ should contain only:
managed-files.json(scaffold metadata)config.json(only if it has overrides differing from releasable config)lint/(only if it has overrides differing from releasable lint config)hooks/(per-package script hooks are a live feature)
Args:
project_path: absolute or relative path to the project directory.
Returns:
- A list of unexpected file/directory names found in
.rlsbl/. - Empty list means the directory is clean.
#_lint_dirs_identical
def _lint_dirs_identical(member_lint_dir, releasable_lint_dir)Return True when member_lint_dir is byte-identical to the releasable lint dir.
Both directories must contain the same set of regular files, and every file must match byte-for-byte. Returns False when the releasable-level lint dir does not exist (nothing to fall back to, so the member copy must be preserved).
#_get_project_releasable
def _get_project_releasable(proj)Extract the releasable value from a project.
Returns str, False, or None.
#_saferm_dir
def _saferm_dir(path, project_name, subdir_name)Remove a directory using saferm with an audit trail.
Raises RuntimeError if saferm is not on PATH. Raises subprocess.CalledProcessError if saferm exits non-zero.
#_saferm_file
def _saferm_file(path, project_name, file_name)Remove a single file using saferm with an audit trail.
Raises RuntimeError if saferm is not on PATH. Raises subprocess.CalledProcessError if saferm exits non-zero.