On this page
Shared utilities: subprocess runner, tool discovery, git helpers, version bumping, changelog extraction, commit tooling, and GitHub API queries.
#rlsbl.utils
#rlsbl.utils
Shared utilities: subprocess runner, git helpers, version bumping, changelog extraction, commit tooling, and GitHub API queries.
#run
def run(cmd, args=None, timeout=120, env=None, cwd=None)Run a command with args, return trimmed stdout. Raise on failure.
#require_tool
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
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
def is_clean_tree()Returns True if the git working tree is clean (no uncommitted changes).
#get_current_branch
def get_current_branch()Returns the current git branch name.
#get_push_timeout
def get_push_timeout()Return the push timeout in seconds, from RLSBL_PUSH_TIMEOUT or default 120.
#get_hook_timeout
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
def push_if_needed(branch, env=None)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).
#extract_changelog_entry_from_text
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
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
def check_gh_installed()Check that the gh CLI is installed.
#check_gh_auth
def check_gh_auth()Check that the gh CLI is authenticated.
#find_commit_tool
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
def has_staged_or_modified(paths: list[str]) -> boolCheck if any of the given paths have staged or unstaged changes.
#commit_files
def commit_files(message: str, files: list[str], allow_failure: bool=False, autogenerated: bool=True) -> boolCommit 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+).
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
def commit_files_if_changed(message: str, files: list[str], skip_message: str='No changes to commit.', autogenerated: bool=True) -> boolCommit 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
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
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.