Skip to content
rlsbl.checks._common
On this page

Shared helpers for rlsbl check modules: version and tag resolution, changelog context, sibling directory exclusion, and reporter text hygiene.

#rlsbl.checks._common

#rlsbl.checks._common

Shared helpers for rlsbl check modules: version and tag resolution, changelog context, sibling directory exclusion, and reporter text hygiene.

#reportable_lines

python
def reportable_lines(text, *, limit=None)

Return the non-blank lines of text, right-stripped, optionally capped.

Tool output is not safe to feed to a reporter line by line: linters like ruff separate findings with blank lines, and an empty problem text is a hard error that aborts the entire check run with no attribution to the check that produced it. Blank lines carry no finding, so they are dropped before the reporter ever sees them. limit caps the number of lines returned (applied after filtering, so a cap of 20 yields 20 real findings).

#summary_line

python
def summary_line(text, *, limit=200, fallback=_NO_TEXT)

Return the first non-blank line of text, truncated to limit chars.

Used for the one-line outcome message that accompanies a set of problems. Never returns an empty string: text that is empty or entirely blank yields fallback, because the reporter rejects an empty outcome message.

#exception_text

python
def exception_text(exc, *, fallback=None)

Return a non-empty description of exc suitable for a reporter call.

An exception raised with no message (or a whitespace-only one) stringifies to "", which the reporter rejects. Falling back to the exception's class name keeps the failure attributable to the check that hit it instead of aborting the run with an internal error.

#_resolve_version_and_tag

python
def _resolve_version_and_tag(ctx)

Detect version and tag from project targets rooted at ctx.

In explicit releasable mode, uses the releasable's version file and tag_format instead of the per-target version and tag format.

Returns (version, tag); either may be None.

#_get_changelog_context

python
def _get_changelog_context(ctx)

Resolve changes_dir, tag_glob, scope, and entries for changelog checks.

Memoized on the check-run context object, which is what makes the answer cacheable at all: every input -- the workspace root, the project root, the member list, the releasable list -- is fixed for the life of one context, so within one context the resolution is a constant. A FRESH context resolves fresh, so nothing here can serve an answer across a tree that moved; the cache never outlives the run that built it.

Returns (changes_dir, tag_glob, scope, entries) or None when the changes directory does not exist (caller should return skip).

The scope value is an :class:~rlsbl.ownership.OwnershipScope -- the whole workspace member list plus the names of the members whose files this changelog covers -- or None for a standalone project with no workspace. Attribution needs the whole list even when only some members are in scope, because a file's owner is decided against every member. A releasable's scope also claims its own state directory, which no member's path does.

In explicit mode, changes_dir points to the releasable's changes directory (.rlsbl-monorepo/releasables/{name}/changes/) and tag_glob is derived from the releasable's tag_format.

#_resolve_changelog_context

python
def _resolve_changelog_context(ctx)

Do the work :func:_get_changelog_context memoizes. Never call directly.

#_resolve_tag_glob

python
def _resolve_tag_glob(ctx)

Return the git tag glob that scopes ctx's project to its own releases.

The single derivation used by the changelog checks (:func:_get_changelog_context): the releasable's tag_format in a monorepo, the target's monorepo_tag_glob for a member that belongs to no releasable, and the plain v* for a standalone repo. Reused by the external-check release-context env so a consumer check resolves the same last tag rlsbl itself would.

#_resolve_release_record_dir

python
def _resolve_release_record_dir(ctx)

Return the release-archive directory that is ctx's project's release record.

Derived from the same context resolution :func:_resolve_tag_glob uses, so the range a check computes and the archives it computes it from always describe the same project. Falls back to the project's own .rlsbl/releases/ when there is no changelog context at all -- a project with no changes dir still has a releases dir, and an empty one honestly reports "nothing released here".

#_resolve_release_identity

python
def _resolve_release_identity(ctx)

Return (target, ref_context, releases_dir) for ctx's project.

The one resolution the ref checks work from: which target answers ref questions, the context expected_refs reads, and the release record whose archives say which versions exist. All three describe the SAME project by construction -- the releases dir comes from :func:_resolve_release_record_dir, and the context is built from the same branch that resolved it.

Returns None when the project has no detectable target, so there is nothing to name refs for.

#_get_all_changelog_contexts

python
def _get_all_changelog_contexts(ctx)

Return changelog contexts for ALL releasables when CWD is the workspace root.

When CWD is inside a specific project, delegates to _get_changelog_context and wraps the result in a list. When CWD is the workspace root, iterates all releasables and returns a context tuple for each one that has a changes directory.

Returns a list of (changes_dir, tag_glob, scope, entries) tuples, or an empty list when no contexts are available (caller should skip).

Memoized on the check-run context for the same reason :func:_get_changelog_context is: every changelog check asks for this same list, and re-deriving it per check re-walked the workspace and re-read every releasable's unreleased.jsonl from disk once per check.

#_resolve_all_changelog_contexts

python
def _resolve_all_changelog_contexts(ctx)

Do the work :func:_get_all_changelog_contexts memoizes. Never call directly.

#_sibling_exclude_dirs

python
def _sibling_exclude_dirs(root, project_path, all_projects)

Compute sibling project directories to exclude from a scan.

For a project at project_path, returns a list of other workspace project directories that are subdirectories of this project's path. This prevents walk_source_files from descending into sibling projects when the current project is at a parent path (e.g. path = ".").

#_build_dep_import_cache

python
def _build_dep_import_cache(ctx)

Build per-project import scan cache for dependency checks.

Returns a dict mapping project name to (lib_imports, test_imports, guarded_imports). All dep checks (unused, undeclared, runtime-test-only, dev-in-lib) share one scan pass via this cache. The result is memoized on the context object so that multiple checks in the same run reuse a single scan instead of re-walking every project's source tree.

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