From c5d2e4608b94ed1560ec22471e63e01248938b47 Mon Sep 17 00:00:00 2001 From: Ramesh Padmanabhaiah Date: Tue, 21 Jul 2026 06:26:07 -0700 Subject: [PATCH] Align doctor fix continuations --- .../basectl/subcommands/setup_common.sh | 10 +++-- cli/python/base_setup/checks.py | 6 ++- .../tests/test_check_text_output.py | 43 +++++++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/cli/bash/commands/basectl/subcommands/setup_common.sh b/cli/bash/commands/basectl/subcommands/setup_common.sh index 37091ccf..b0403d26 100644 --- a/cli/bash/commands/basectl/subcommands/setup_common.sh +++ b/cli/bash/commands/basectl/subcommands/setup_common.sh @@ -845,16 +845,18 @@ setup_print_doctor_finding() { local name="$3" local message="$4" local fix="${5:-}" - local color fix_indent label padding reset + local color fix_indent label padding reset status_prefix if setup_doctor_visual_status_enabled; then IFS=$'\t' read -r label color padding <<<"$(setup_doctor_status_visual_parts "$status")" reset=$'\033[0m' + status_prefix="${label}${padding} " printf '%b%s%b%s %-9s %-26s %s\n' "$color" "$label" "$reset" "$padding" "$finding_id" "$name" "$message" - fix_indent=9 + fix_indent=${#status_prefix} else - printf '%-5s %-9s %-26s %s\n' "$status" "$finding_id" "$name" "$message" - fix_indent=7 + status_prefix="$(printf '%-5s ' "$status")" + printf '%s%-9s %-26s %s\n' "$status_prefix" "$finding_id" "$name" "$message" + fix_indent=${#status_prefix} fi if [[ -n "$fix" ]]; then printf '%*sFix: %s\n' "$fix_indent" '' "$fix" diff --git a/cli/python/base_setup/checks.py b/cli/python/base_setup/checks.py index c1b3927d..16b0b810 100644 --- a/cli/python/base_setup/checks.py +++ b/cli/python/base_setup/checks.py @@ -82,8 +82,10 @@ def print_doctor_finding(status: str, finding_id: str, name: str, message: str, stream = sys.stderr if status in {"error", "warn"} else sys.stdout if _doctor_visual_status_enabled(stream): label, color, padding = _doctor_visual_status_parts(status) + status_prefix = f"{label}{padding} " print(f"{color}{label}\033[0m{padding} {finding_id:<9} {name:<26} {message}", file=stream) else: - print(f"{status:<5} {finding_id:<9} {name:<26} {message}", file=stream) + status_prefix = f"{status:<5} " + print(f"{status_prefix}{finding_id:<9} {name:<26} {message}", file=stream) if fix: - print(f" Fix: {fix}", file=stream) + print(f"{' ' * len(status_prefix)}Fix: {fix}", file=stream) diff --git a/cli/python/base_setup/tests/test_check_text_output.py b/cli/python/base_setup/tests/test_check_text_output.py index 2c525369..6511eded 100644 --- a/cli/python/base_setup/tests/test_check_text_output.py +++ b/cli/python/base_setup/tests/test_check_text_output.py @@ -2,7 +2,9 @@ import io import os +import re import unittest +from contextlib import redirect_stderr from contextlib import redirect_stdout from pathlib import Path from unittest import mock @@ -34,6 +36,47 @@ def isatty(self) -> bool: "Project artifact check passed.\n", ) + def test_doctor_finding_aligns_visual_fix_under_finding_id(self) -> None: + class TtyBuffer(io.StringIO): + def isatty(self) -> bool: + return True + + stderr = TtyBuffer() + with ( + mock.patch.dict(os.environ, {"TERM": "xterm-256color"}, clear=True), + redirect_stderr(stderr), + ): + setup_checks.print_doctor_finding( + "error", + "BASE-H001", + "BASE_DEMO_ENV", + "Environment variable is not set or is empty.", + "Set BASE_DEMO_ENV in your shell.", + ) + + finding_line, fix_line = stderr.getvalue().splitlines() + visible_finding_prefix = re.sub(r"\033\[[0-9;]*m", "", finding_line.split("BASE-H001", 1)[0]) + fix_prefix = fix_line.split("Fix:", 1)[0] + self.assertEqual(len(visible_finding_prefix), len(fix_prefix)) + self.assertTrue(fix_line.endswith("Fix: Set BASE_DEMO_ENV in your shell.")) + + def test_doctor_finding_aligns_plain_fix_under_finding_id(self) -> None: + stderr = io.StringIO() + with mock.patch.dict(os.environ, {}, clear=True), redirect_stderr(stderr): + setup_checks.print_doctor_finding( + "error", + "BASE-H001", + "BASE_DEMO_ENV", + "Environment variable is not set or is empty.", + "Set BASE_DEMO_ENV in your shell.", + ) + + finding_line, fix_line = stderr.getvalue().splitlines() + self.assertEqual( + len(finding_line.split("BASE-H001", 1)[0]), + len(fix_line.split("Fix:", 1)[0]), + ) + def test_check_manifest_text_routes_findings_by_status_and_preserves_exit_status(self) -> None: default_manifest = BaseManifest( path=Path("default_manifest.yaml"),