rlsbl v0.51.0 /rlsbl.utils
On this page

Shared utilities: subprocess runner, tool detection, project root discovery, git helpers, version bumping, changelog extraction, and commit tooling.

#rlsbl.utils

#rlsbl.utils

Shared utilities: subprocess runner, git helpers, version bumping, changelog extraction, commit tooling, and GitHub API queries.

#run

python
def run(cmd, args=None, timeout=120, env=None, cwd=None)

Run a command with args, return trimmed stdout. Raise on failure.

#require_tool

python
def require_tool(name, purpose=None, fatal=True)

Check that a CLI tool is available on PATH.

Args:

  • name: command name (e.g., "uv", "npm", "go").
  • purpose: optional human-readable reason ("for editable install"),

included in the error message when fatal.

  • fatal: if True, raise FileNotFoundError on missing tool; if False,

return None silently.

Returns the resolved path to the tool, or None if missing and not fatal.

#find_project_root

python
def find_project_root(start=None)

Walk up from start (default: cwd) to find .rlsbl/ or .rlsbl-monorepo/.

Returns the directory path containing the marker, or None if not found. Prefers the nearest ancestor with either marker.

#is_clean_tree

python
def is_clean_tree()

Returns True if the git working tree is clean (no uncommitted changes).

#get_current_branch

python
def get_current_branch()

Returns the current git branch name.

#get_push_timeout

python
def get_push_timeout(config)

Return the push timeout in seconds.

Precedence: RLSBL_PUSH_TIMEOUT env var > config dict push_timeout. Raises ValueError if neither is set (no implicit default).

config is the project config dict (already loaded).

#get_hook_timeout

python
def get_hook_timeout()

Return the hook timeout in seconds, from RLSBL_HOOK_TIMEOUT or default None.

If not set, returns None (no timeout — hooks run to completion). If set, parses as a positive integer. On invalid value, prints a warning and returns None.

#push_if_needed

python
def push_if_needed(branch, env=None, *, config)

Push the branch to origin if local is ahead of remote.

Args:

  • branch: branch name to push.
  • env: optional environment dict passed to the push subprocess (e.g. to

set RLSBL_RELEASE_PUSH=1 so the pre-push hook recognises the push as release-authorized). Defaults to None (inherit current env).

  • config: project config dict forwarded to get_push_timeout.

#extract_changelog_entry_from_text

python
def extract_changelog_entry_from_text(content, version)

Extract a changelog entry for a specific version from a markdown string.

Looks for a heading like '## 1.2.3' and captures everything until the next heading or EOF.

#extract_changelog_entry

python
def extract_changelog_entry(changelog_path, version)

Extract a changelog entry for a specific version.

Looks for a heading like '## 1.2.3' and captures everything until the next heading or EOF.

#check_gh_installed

python
def check_gh_installed()

Check that the gh CLI is installed.

#check_gh_auth

python
def check_gh_auth()

Check that the gh CLI is authenticated.

#find_commit_tool

python
def find_commit_tool()

Detect safegit or fall back to git for committing.

Returns "safegit" if available on PATH, otherwise "git". Prints a one-time warning to stderr when falling back to git.

#has_staged_or_modified

python
def has_staged_or_modified(paths: list[str], cwd: str | None=None) -> bool

Check if any of the given paths have staged or unstaged changes.

When cwd is set, git commands run from that directory and os.path.exists checks are resolved relative to it. Paths must be relative to cwd (or absolute).

#commit_files

python
def commit_files(message: str, files: list[str], allow_failure: bool=False, autogenerated: bool=True, cwd: str | None=None) -> bool

Commit specific files using safegit (preferred) or git.

When autogenerated is True, passes --trailer "Autogenerated: true" to the commit command (supported by git 2.32+ and safegit 0.10.0+).

When cwd is set, the commit tool runs from that directory. File paths must be relative to cwd (or absolute). This is needed in monorepo mode where paths are relative to the repo root but the process CWD is a sub-project directory.

Returns True on success. When allow_failure is True, catches errors and returns False with a warning to stderr. When False, exceptions propagate.

#commit_files_if_changed

python
def commit_files_if_changed(message: str, files: list[str], skip_message: str='No changes to commit.', autogenerated: bool=True, cwd: str | None=None) -> bool

Commit files only if they have actual changes, otherwise print skip_message.

Returns True if a commit was made, False if nothing changed. Raises on commit failure (never uses allow_failure=True).

#bump_version

python
def bump_version(version, bump_type)

Bump a semver version string by the given type (patch, minor, major).

Handles pre-release suffixes (e.g. "1.0.0-beta.1"): the suffix is stripped and the bump is applied to the base version.

Returns the new version string (always clean, no pre-release suffix).

#is_private_repo

python
def is_private_repo()

Detect if the current repo is private via GitHub API.

Returns True if private, False if public, None if detection fails.