On this page
External check providers: subprocess checks with a mandatory kind -- freeform runs a shell command, structured composes argv for known tools like mypy.
#rlsbl.external_checks
#rlsbl.external_checks
External check providers: config-declared subprocess checks.
Projects declare external checks in .rlsbl/config.json under the external_checks key. Every entry declares kind = "freeform": an opaque shell command. rlsbl does not understand its scope -- the command runs verbatim through a shell.
The mandatory kind marker exists so that unmanaged scope (a freeform shell command whose target directories rlsbl cannot see) is always a visible, deliberate declaration rather than an accident.
kind = "structured" is RETIRED. It named a known tool plus a path list and had rlsbl compose the argv; that invocation shape is now three built-in checks (lint, format, type-check) configured under the top-level checks key -- see :mod:rlsbl.tool_checks. A config that still declares it is a hard error naming the replacement.
External checks are registered via a strictcli check provider (app.register_check_provider). The provider reads the project config at materialization time (keyed on cwd) and returns a list of check specs. strictcli handles memoization and re-materialization when the cwd changes.
#ExternalCheckError
Raised when external check config is invalid.
#_retired_structured_message
def _retired_structured_message(index, entry)The hard error a retired kind = "structured" entry gets.
#validate_external_checks
def validate_external_checks(config, *, project_root=None)Validate the external_checks section of a project config.
Every entry must declare kind = "freeform" plus name, tag and command; depends_on and cwd are optional. Any unrecognized key is a hard error, and so is the retired kind = "structured" (the message names the built-in check that replaced it).
Binary existence is validated eagerly, at registration time: the command's first token must resolve on PATH or at an absolute path.
Returns the validated list of external check dicts, or an empty list if the key is absent.
#_validate_freeform_entry
def _validate_freeform_entry(i, entry)Validate the command field of a freeform entry and probe its binary.
#_make_external_check_fn
def _make_external_check_fn(command, cwd, name)Build a check function that runs a freeform command through a shell.
The returned function has the (ctx, reporter) signature expected by strictcli's check system. The timeout is resolved per run from the live context (see :func:_resolve_check_budget). The subprocess env carries the release context (see :func:_release_context_env).
#_entry_specs
def _entry_specs(entry)Build the check spec for a single validated external-check entry.
One impure subprocess check per entry. No timeout is bound here: the budget is resolved per run from the live check context (see :func:resolve_check_budget).
#make_external_check_provider
def make_external_check_provider(config_reader)Build a check provider that reads external checks from config.
config_reader is a callable that returns the project config dict for the current working directory. The provider is called lazily by strictcli at materialization time (memoized by cwd).
Returns a provider function suitable for app.register_check_provider().
#run_external_preflight_checks
def run_external_preflight_checks(app, ctx, config, *, tag_expr='preflight', pure_only=False)Run ONLY the config-declared external checks matching tag_expr.
Used when the pre-release hook is customized: built-in preflight checks (test-suite, lint, maven-central-metadata) are the hook's responsibility and must be skipped, but config-declared external checks must still run.
Selection mechanism: each external check is selected by its exact name intersected with tag_expr (strictcli's run_checks ANDs name_glob with tag_expr). This runs exactly the config-declared external checks that carry the preflight tag and never selects a built-in check.
pure_only is the rehearsal's partition, and it is what makes this entry point usable under --dry-run: pure checks EXECUTE and report real findings, while impure ones are listed rather than run. The non-customized-hook branch has always previewed that way; passing this through is what stops the customized-hook branch from being the one place a preview silently skips a check it could have run.
The check provider must have already been registered on app (via app.register_check_provider).
Returns (results, impure_listed, exit_code): the executed checks, the names withheld by the purity partition (empty unless pure_only), and a non-zero exit code if any executed check failed.