rlsbl v0.92.0 /rlsbl.commands.release.validate
On this page

Validation helpers: tests, lint, selfdoc, scaffold conflicts, strictcli schema, blog body.

#rlsbl.commands.release.validate

#rlsbl.commands.release.validate

Validation helpers: tests, lint, selfdoc, scaffold conflicts, strictcli schema, blog body.

Also contains extracted validation steps from run_cmd: target validation, OTA mode, config integrity, pipeline config, gh CLI, clean tree, branch/remote, monorepo context, version/tag computation, and changelog state validation.

#ReleaseValidationError

Raised when a pre-release validation check fails.

#HookError

Raised when a built-in hook (tests, lint, selfdoc) fails.

#validate_release_targets

python
def validate_release_targets(release_config, project_root, *, member_dirs=None, releasable_config_dir=None)

Validate include/exclude targets in the release config.

Checks:

  • include list is non-empty
  • all named targets are known
  • include + exclude exhaustively covers detected targets

When member_dirs is provided (releasable mode), detected targets are the union of targets across all member directories instead of the single project root. If releasable_config_dir is also set, its config.json targets key takes precedence (the releasable is the source of truth in explicit mode).

Returns the primary registry name (first item in include). Raises ReleaseValidationError on failure.

#validate_ota_mode

python
def validate_ota_mode(release_config, project_root, config)

Validate Flutter OTA mode: check for native changes since last build release.

Raises ReleaseValidationError if OTA is requested but native files changed.

#validate_config_integrity

python
def validate_config_integrity(config)

Validate the 'private' key exists and private repos don't have local pipelines.

Raises ReleaseValidationError on failure.

#validate_pipeline_config

python
def validate_pipeline_config(config)

Validate pipeline configuration and required env vars.

Returns loaded pipelines dict. Raises ReleaseValidationError on failure.

#validate_gh_cli

python
def validate_gh_cli()

Validate that gh CLI is installed and authenticated.

Raises ReleaseValidationError on failure.

#validate_gh_push_access

python
def validate_gh_push_access(config=None)

Validate that the authenticated gh user has push access to the repo.

Uses the GitHub API to check push permissions. If push access is denied, raises ReleaseValidationError with a diagnostic message that includes the authenticated user, repo slug, and a suggestion to unset GH_TOKEN/GITHUB_TOKEN if either is set in the environment.

Gracefully skips (warning only) on network/API errors. Silently returns if the repo cannot be determined.

#validate_clean_tree

python
def validate_clean_tree(flags)

Validate working tree is clean (or record pre-existing dirty files).

Returns set of pre-existing dirty file paths. Raises ReleaseValidationError if tree is dirty and --allow-dirty not set.

#validate_branch_and_remote

python
def validate_branch_and_remote(flags, *, release_mode='imperative')

Validate branch is main/master and not behind origin.

When release_mode is "pr":

  • Requires the current branch to be main/master (we branch FROM main).
  • Skips the "not on main/master" warning (replaced with hard error).
  • Skips the behind-origin check (the release branch doesn't exist remotely yet).

Returns the current branch name. Raises ReleaseValidationError if local branch is behind origin.

#resolve_monorepo_context

python
def resolve_monorepo_context(monorepo_root, project_root, log)

Resolve monorepo project context if inside a monorepo.

Returns (monorepo_name, monorepo_project_path, is_library, is_non_releasable, releasable_name). All values are None/False/None when not in a monorepo. releasable_name is a string when the project explicitly belongs to a named releasable (releasable = "name"), or None in implicit mode. Raises ReleaseValidationError if inside a monorepo but not a recognized project, or if the project is non-releasable.

#_format_releasable_tag

python
def _format_releasable_tag(releasable_tag_format, releasable_name, version)

Format a tag using the releasable's tag_format template.

Supports {name} and {version} placeholders. E.g.::

"{name}@v{version}" -> "[email protected]" "v{version}" -> "v2.0.0"

#_releasable_tag_glob

python
def _releasable_tag_glob(releasable_tag_format, releasable_name)

Derive a glob pattern from a releasable's tag_format.

Replaces {version} with * and fills in {name} with the literal releasable name so git tag -l can match all versions.

#compute_release_version

python
def compute_release_version(target, primary_path, bump_arg, monorepo_name, monorepo_project_path, log, *, workspace_root=None, releasable_name=None, releasable_tag_fmt=None, preid='')

Compute current and new version, bump type, and tag.

In explicit releasable mode (when workspace_root and releasable_name are both provided), the version is read from the releasable's version file at .rlsbl-monorepo/releasables//version instead of from the target's manifest file. This is the canonical version source for multi-package releasables.

When releasable_tag_fmt is provided (explicit mode), tags are constructed from the releasable's tag format instead of the target's monorepo tag format.

In implicit mode (the default, when either parameter is None), the version is read from the target's manifest as before.

Returns (current_version, new_version, bump_type, tag). Raises ReleaseValidationError on invalid bump type or duplicate tag.

#resolve_changes_dir

python
def resolve_changes_dir(project_dir, releasable_name=None, workspace_root=None)

Resolve the JSONL changelog changes directory path.

In explicit releasable mode (when both releasable_name and workspace_root are provided), returns the releasable-level changes directory. Otherwise returns the per-project .rlsbl/changes/ directory.

Returns the changes_dir path. Raises ReleaseValidationError if the directory does not exist.

#validate_changelog_state

python
def validate_changelog_state(project_dir, target, monorepo_name, monorepo_project_path, config, monorepo_project=None, releasable_name=None, releasable_tag_fmt=None, workspace_root=None, bump_type=None)

Resolve the JSONL changelog changes directory path.

Thin wrapper around :func:resolve_changes_dir that preserves the existing call signature for backward compatibility. Changelog validation is now handled by the preflight-changelog check tag in the release flow.

Returns the changes_dir path. Raises ReleaseValidationError if the directory does not exist.

python
def print_dry_run_summary(log, registry, monorepo_name, monorepo_project_path, bump_type, current_version, new_version, tag, commit_msg, branch, target_paths, project_dir, changelog_entry, monorepo_root=None, member_package_paths=None)

Print dry-run summary and return (caller should exit after this).

#parse_porcelain_paths

python
def parse_porcelain_paths(porcelain_output)

Parse file paths from git status --porcelain output.

Handles the case where run() strips stdout, potentially removing a leading space from the first line. Uses lstrip().split(None, 1) to robustly extract the status code and path regardless.

Returns a set of file paths found in the output.

#_run_selfdoc_gen

python
def _run_selfdoc_gen(flags, project_dir=None)

Run selfdoc gen if selfdoc.json exists in the project directory.

Regenerates documentation pages from source before the selfdoc check step, ensuring the check validates fresh content rather than stale pages.

#_run_selfdoc_check

python
def _run_selfdoc_check(flags, project_dir=None)

Run selfdoc check if selfdoc.json exists in the project directory.

Checks documentation consistency before releasing. Non-fatal if selfdoc is not installed; fatal if it is installed and the check fails. When project_dir is set (monorepo mode), checks are resolved relative to it.

#_abort_on_scaffold_conflicts

python
def _abort_on_scaffold_conflicts(project_dir)

Abort the release if scaffold-managed files contain unresolved merge conflict markers.

Scaffold's three-way merge (git merge-file) intentionally leaves conflict markers for manual resolution; releasing with them would publish corrupted workflows/hooks. Runs PRE-MUTATION: nothing has been modified yet when this aborts.

#_schema_dump_command

python
def _schema_dump_command(entry_point: str, lang: str) -> list[str]

Build the command list for running --dump-schema based on language.

#_run_strictcli_schema_dump

python
def _run_strictcli_schema_dump(flags, log, project_dir='.')

Run --dump-schema for strictcli projects to regenerate .strictcli/schema.json.

Detects strictcli usage via pyproject.toml or go.mod, runs the entry point with --dump-schema, and logs the result. The generated file is picked up by the hook-generated file mechanism (pre/post hook dirty snapshots).

Non-fatal: a failing dump command prints a warning but does not abort.

#validate_blog_body

python
def validate_blog_body(project_dir, blog_enabled)

Validate the blog body file for a release.

Returns (body_path, warning_message) where body_path is the path if it exists and warning_message is set if the file is missing. Raises ReleaseValidationError if blog_enabled and file is empty.