Skip to content
rlsbl.releasable_cleanup
On this page

Removes the per-package .rlsbl/ changelog and release state a member is left holding under an older layout. Run only by rlsbl monorepo cleanup.

#rlsbl.releasable_cleanup

#rlsbl.releasable_cleanup

Cleanup utilities for per-package .rlsbl/ directories, removing orphaned changelog and release state files left over from an older layout.

Changelog and release state belongs to the releasable, under .rlsbl-monorepo/releasables/{name}/. A member package's own .rlsbl/changes/ and .rlsbl/releases/ directories are dead state that should be removed.

These functions run from rlsbl monorepo cleanup, never automatically 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 that belong to a releasable.

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.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • selfdoc Static Site Generator that builds a project's documentation site directly from its source code, so the docs can never drift from the code they describe, with SEO/AEO, first-class blog, search, and cross-project linking built in
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search