rlsbl v0.113.0 /rlsbl.releasable_cleanup
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

python
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 file
  • CHANGELOG.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

python
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

python
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

python
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

python
def _get_project_releasable(proj)

Extract the releasable value from a project.

Returns str, False, or None.

#_saferm_dir

python
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

python
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.

Search