You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2022/04/28 15:35:25 UTC

[airflow] branch main updated: Unify style of communication with the users for Breeze. (#23311)

This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 505af06303 Unify style of communication with the users for Breeze. (#23311)
505af06303 is described below

commit 505af06303d8160c71f6a7abe4792746f640083d
Author: Jarek Potiuk <ja...@polidea.com>
AuthorDate: Thu Apr 28 17:35:05 2022 +0200

    Unify style of communication with the users for Breeze. (#23311)
    
    Fixes: #22906
---
 BREEZE.rst                                         |  11 ++
 .../0011-unified-communication-with-the-users.md   |  94 ++++++++++++++++
 .../build_image/ci/build_ci_image.py               |  35 +++---
 .../build_image/ci/build_ci_params.py              |   4 +-
 .../build_image/prod/build_prod_image.py           |  30 ++---
 .../build_image/prod/build_prod_params.py          |  10 +-
 .../src/airflow_breeze/commands/ci_image_tools.py  |   8 +-
 .../commands/configuration_and_maintenance.py      | 125 ++++++++++++---------
 .../commands/configure_rich_click.py               |   2 +-
 .../airflow_breeze/commands/custom_param_types.py  |  10 +-
 .../airflow_breeze/commands/developer_commands.py  |  10 +-
 .../commands/production_image_tools.py             |   8 +-
 .../airflow_breeze/commands/release_management.py  |  12 +-
 dev/breeze/src/airflow_breeze/commands/testing.py  |   4 +-
 dev/breeze/src/airflow_breeze/shell/enter_shell.py |  18 +--
 .../src/airflow_breeze/shell/shell_params.py       |  16 +--
 dev/breeze/src/airflow_breeze/utils/cache.py       |   8 +-
 dev/breeze/src/airflow_breeze/utils/console.py     |  51 ++++++---
 dev/breeze/src/airflow_breeze/utils/constraints.py |   6 +-
 .../airflow_breeze/utils/docker_command_utils.py   |  41 +++----
 .../utils/find_newer_dependencies.py               |  23 ++--
 .../src/airflow_breeze/utils/md5_build_check.py    |  14 ++-
 dev/breeze/src/airflow_breeze/utils/parallel.py    |  22 ++--
 dev/breeze/src/airflow_breeze/utils/path_utils.py  |   8 +-
 dev/breeze/src/airflow_breeze/utils/pulll_image.py |  26 +++--
 .../src/airflow_breeze/utils/python_versions.py    |   8 +-
 dev/breeze/src/airflow_breeze/utils/registry.py    |  10 +-
 dev/breeze/src/airflow_breeze/utils/reinstall.py   |  30 ++---
 dev/breeze/src/airflow_breeze/utils/run_tests.py   |   8 +-
 dev/breeze/src/airflow_breeze/utils/run_utils.py   |  61 +++++-----
 dev/breeze/src/airflow_breeze/utils/visuals.py     |   8 +-
 dev/breeze/tests/test_docker_command_utils.py      |  68 ++++++-----
 dev/provider_packages/prepare_provider_packages.py |   2 +-
 docs/build_docs.py                                 |  32 +++---
 docs/exts/docs_build/docs_builder.py               |  18 +--
 docs/exts/docs_build/errors.py                     |   4 +-
 docs/exts/docs_build/spelling_checks.py            |   4 +-
 images/breeze/output-config.svg                    |   3 +-
 .../ci/pre_commit/pre_commit_check_order_setup.py  |  10 +-
 39 files changed, 520 insertions(+), 342 deletions(-)

diff --git a/BREEZE.rst b/BREEZE.rst
index 64ae2ea346..37b47f29cf 100644
--- a/BREEZE.rst
+++ b/BREEZE.rst
@@ -378,6 +378,17 @@ default settings.
 You can see which value of the parameters that can be stored persistently in cache marked with >VALUE<
 in the help of the commands.
 
+Another part of configuration is enabling/disabling cheatsheet, asciiart. The cheatsheet and asciiart can
+be disabled - they are "nice looking" and cheatsheet
+contains useful information for first time users but eventually you might want to disable both if you
+find it repetitive and annoying.
+
+With the config setting colour-blind-friendly communication for Breeze messages. By default we communicate
+with the users about information/errors/warnings/successes via colour-coded messages, but we can switch
+it off by passing ``--no-colour`` to config in which case the messages to the user printed by Breeze
+will be printed using different schemes (italic/bold/underline) to indicate different kind of messages
+rather than colours.
+
 Here is the part of Breeze video which is relevant (note that it refers to the old ``./breeze-legacy``
 command but it is very similar to current ``breeze`` command):
 
diff --git a/dev/breeze/doc/adr/0011-unified-communication-with-the-users.md b/dev/breeze/doc/adr/0011-unified-communication-with-the-users.md
new file mode 100644
index 0000000000..89f967e350
--- /dev/null
+++ b/dev/breeze/doc/adr/0011-unified-communication-with-the-users.md
@@ -0,0 +1,94 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ -->
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*
+
+- [11. Unified communication with the users](#11-unified-communication-with-the-users)
+  - [Status](#status)
+  - [Context](#context)
+  - [Decision](#decision)
+  - [Consequences](#consequences)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+# 11. Unified communication with the users
+
+Date: 2022-04-27
+
+## Status
+
+Accepted
+
+## Context
+
+We communicate with the user via messages printed in get_console() And we should
+make sure we communicate the msssages in a consistent way so that the users would
+understand:
+
+* whether verification of a condition succeeded
+* whether a message is just informational that might be used to understand what's going on
+* whether there is some important warning to potentially act on
+* whether there is a definite error that the user should fix
+* instructions how to proceed
+
+The messages should be:
+
+* short
+* informative
+* readable
+* actionable
+
+## Decision
+
+We are using rich and colours to communicate the type of messages:
+
+* [success] - to show verification success (green)
+* [info] - to present inform users (bright_blue)
+* [warning] - to print warning that the user probably should read and act on (bright_yellow)
+* [error] - when there is an error that the user should fix (red)
+* instructions should be printed without style and default rich rendering should be used
+
+By default, we map those styles to those colors, but we can change configuration of Breeze to
+be colour-blind-friendly by disabling colours in communication via `breeze config --no-colour`.
+
+When signalling warning or error The communication should not be confusing and
+should not contain "noise". It should contain simple - usually one-liner -
+information on what's wrong or what the user is warned against, possibly
+followed by instructions telling the user what to do. When we are able to
+foresee that error will happen, we should print the message only with
+explanation, and we should suppress any stack-traces as they are not really
+useful for the users. When an error is unexpected, full stack trace should
+be written to allow easier investigation of the problem.
+
+We should also support `--verbose` flag to display all the commands being executed, and
+the --dry-run flag to only display commands and not execute the commands. This will allow to
+diagnose any problems that the user might have.
+
+Whenever we print a logically separated message we should add EOL to separate the logical part of the
+message as well as when you want to separate the header description from bullet lists (very similar to
+what .rst rules are for readability). Whitespace improves readability of communication and messages
+separated in sections separated by whitespace and marked with colors are much more readable than the
+wall of text without visible structure.
+
+## Consequences
+
+Users will get consistent approach when it comes to context and expectations of their reaction for the
+messages. Developers will use consistent styles.
diff --git a/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_image.py b/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_image.py
index 7c1bca1eb1..f511c7ac55 100644
--- a/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_image.py
+++ b/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_image.py
@@ -28,7 +28,7 @@ from airflow_breeze.build_image.ci.build_ci_params import (
 from airflow_breeze.utils.cache import touch_cache_file
 from airflow_breeze.utils.ci_group import ci_group
 from airflow_breeze.utils.confirm import Answer, user_confirm
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.docker_command_utils import (
     construct_docker_build_command,
     construct_empty_docker_build_command,
@@ -71,9 +71,8 @@ def should_we_run_the_build(build_ci_params: BuildCiParams) -> bool:
             if is_repo_rebased(build_ci_params.github_repository, build_ci_params.airflow_branch):
                 return True
             else:
-                console.print(
-                    "\n[bright_yellow]This might take a lot of time, w"
-                    "e think you should rebase first.[/]\n"
+                get_console().print(
+                    "\n[warning]This might take a lot of time, w" "e think you should rebase first.[/]\n"
                 )
                 answer = user_confirm(
                     "But if you really, really want - you can do it", timeout=5, default_answer=Answer.NO
@@ -81,25 +80,25 @@ def should_we_run_the_build(build_ci_params: BuildCiParams) -> bool:
                 if answer == Answer.YES:
                     return True
                 else:
-                    console.print(
-                        "[bright_blue]Please rebase your code before continuing.[/]\n"
+                    get_console().print(
+                        "[info]Please rebase your code before continuing.[/]\n"
                         "Check this link to know more "
                         "https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst#id15\n"
                     )
-                    console.print('[red]Exiting the process[/]\n')
+                    get_console().print('[error]Exiting the process[/]\n')
                     sys.exit(1)
         elif answer == Answer.NO:
             instruct_build_image(build_ci_params.python)
             return False
         else:  # users_status == Answer.QUIT:
-            console.print('\n[bright_yellow]Quitting the process[/]\n')
+            get_console().print('\n[warning]Quitting the process[/]\n')
             sys.exit()
     except TimeoutOccurred:
-        console.print('\nTimeout. Considering your response as No\n')
+        get_console().print('\nTimeout. Considering your response as No\n')
         instruct_build_image(build_ci_params.python)
         return False
     except Exception as e:
-        console.print(f'\nTerminating the process on {e}')
+        get_console().print(f'\nTerminating the process on {e}')
         sys.exit(1)
 
 
@@ -126,8 +125,8 @@ def build_ci_image(
     """
     fix_group_permissions()
     if verbose or dry_run:
-        console.print(
-            f"\n[bright_blue]Building CI image of airflow from {AIRFLOW_SOURCES_ROOT} "
+        get_console().print(
+            f"\n[info]Building CI image of airflow from {AIRFLOW_SOURCES_ROOT} "
             f"python version: {ci_image_params.python}[/]\n"
         )
     with ci_group(
@@ -158,7 +157,7 @@ def build_ci_image(
         if ci_image_params.empty_image:
             env = os.environ.copy()
             env['DOCKER_BUILDKIT'] = "1"
-            console.print(f"\n[blue]Building empty CI Image for Python {ci_image_params.python}\n")
+            get_console().print(f"\n[info]Building empty CI Image for Python {ci_image_params.python}\n")
             cmd = construct_empty_docker_build_command(image_params=ci_image_params)
             build_result = run_command(
                 cmd,
@@ -170,7 +169,7 @@ def build_ci_image(
                 env=env,
             )
         else:
-            console.print(f"\n[blue]Building CI Image for Python {ci_image_params.python}\n")
+            get_console().print(f"\n[info]Building CI Image for Python {ci_image_params.python}\n")
             build_result = run_command(
                 cmd, verbose=verbose, dry_run=dry_run, cwd=AIRFLOW_SOURCES_ROOT, text=True, check=False
             )
@@ -181,13 +180,13 @@ def build_ci_image(
                 touch_cache_file(f"built_{ci_image_params.python}", root_dir=ci_image_cache_dir)
                 calculate_md5_checksum_for_files(ci_image_params.md5sum_cache_dir, update=True)
             else:
-                console.print("[red]Error when building image![/]")
+                get_console().print("[error]Error when building image![/]")
                 return (
                     build_result.returncode,
                     f"Image build: {ci_image_params.python}",
                 )
         else:
-            console.print("[blue]Not updating build cache because we are in `dry_run` mode.[/]")
+            get_console().print("[info]Not updating build cache because we are in `dry_run` mode.[/]")
         if ci_image_params.push_image:
             return tag_and_push_image(image_params=ci_image_params, dry_run=dry_run, verbose=verbose)
         return build_result.returncode, f"Image build: {ci_image_params.python}"
@@ -197,8 +196,8 @@ def build_ci_image_in_parallel(
     verbose: bool, dry_run: bool, parallelism: int, python_version_list: List[str], **kwargs
 ):
     """Run CI image builds in parallel."""
-    console.print(
-        f"\n[bright_blue]Running with parallelism = {parallelism} for the images: {python_version_list}:"
+    get_console().print(
+        f"\n[info]Running with parallelism = {parallelism} for the images: {python_version_list}:"
     )
     pool = mp.Pool(parallelism)
     results = [pool.apply_async(build_ci_image, args=(verbose, dry_run, False), kwds=kwargs)]
diff --git a/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_params.py b/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_params.py
index f726b000f7..da5364d087 100644
--- a/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_params.py
+++ b/dev/breeze/src/airflow_breeze/build_image/ci/build_ci_params.py
@@ -23,7 +23,7 @@ from typing import List, Optional
 
 from airflow_breeze.branch_defaults import AIRFLOW_BRANCH, DEFAULT_AIRFLOW_CONSTRAINTS_BRANCH
 from airflow_breeze.global_constants import get_airflow_version
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.path_utils import BUILD_CACHE_DIR
 
 
@@ -149,7 +149,7 @@ class BuildCiParams:
         return Path(BUILD_CACHE_DIR, self.airflow_branch, self.python, "CI")
 
     def print_info(self):
-        console.print(f"CI Image: {self.airflow_version} Python: {self.python}.")
+        get_console().print(f"CI Image: {self.airflow_version} Python: {self.python}.")
 
 
 REQUIRED_CI_IMAGE_ARGS = [
diff --git a/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_image.py b/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_image.py
index 2caeeb7ef5..967a655899 100644
--- a/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_image.py
+++ b/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_image.py
@@ -22,7 +22,7 @@ from typing import Tuple
 
 from airflow_breeze.build_image.prod.build_prod_params import BuildProdParams
 from airflow_breeze.utils.ci_group import ci_group
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.docker_command_utils import (
     construct_docker_build_command,
     construct_empty_docker_build_command,
@@ -76,7 +76,7 @@ def clean_docker_context_files(verbose: bool, dry_run: bool):
     Cleans up docker context files folder - leaving only .README.md there.
     """
     if verbose or dry_run:
-        console.print("[bright_blue]Cleaning docker-context-files[/]")
+        get_console().print("[info]Cleaning docker-context-files[/]")
     if dry_run:
         return
     with contextlib.suppress(FileNotFoundError):
@@ -101,20 +101,20 @@ def check_docker_context_files(install_packages_from_context: bool):
     )
     if number_of_context_files == 0:
         if install_packages_from_context:
-            console.print('[bright_yellow]\nERROR! You want to install packages from docker-context-files')
-            console.print('[bright_yellow]\n but there are no packages to install in this folder.')
+            get_console().print('[warning]\nERROR! You want to install packages from docker-context-files')
+            get_console().print('[warning]\n but there are no packages to install in this folder.')
             sys.exit(1)
     else:
         if not install_packages_from_context:
-            console.print(
-                '[bright_yellow]\n ERROR! There are some extra files in docker-context-files except README.md'
+            get_console().print(
+                '[warning]\n ERROR! There are some extra files in docker-context-files except README.md'
             )
-            console.print('[bright_yellow]\nAnd you did not choose --install-packages-from-context flag')
-            console.print(
-                '[bright_yellow]\nThis might result in unnecessary cache invalidation and long build times'
+            get_console().print('[warning]\nAnd you did not choose --install-packages-from-context flag')
+            get_console().print(
+                '[warning]\nThis might result in unnecessary cache invalidation and long build times'
             )
-            console.print(
-                '[bright_yellow]\nExiting now \
+            get_console().print(
+                '[warning]\nExiting now \
                     - please restart the command with --cleanup-context switch'
             )
             sys.exit(1)
@@ -145,8 +145,8 @@ def build_production_image(
     """
     fix_group_permissions()
     if verbose or dry_run:
-        console.print(
-            f"\n[bright_blue]Building PROD image of airflow from {AIRFLOW_SOURCES_ROOT} "
+        get_console().print(
+            f"\n[info]Building PROD image of airflow from {AIRFLOW_SOURCES_ROOT} "
             f"python version: {prod_image_params.python}[/]\n"
         )
     with ci_group(
@@ -168,11 +168,11 @@ def build_production_image(
             text=True,
             check=False,
         )
-        console.print(f"\n[blue]Building PROD Image for Python {prod_image_params.python}\n")
+        get_console().print(f"\n[info]Building PROD Image for Python {prod_image_params.python}\n")
         if prod_image_params.empty_image:
             env = os.environ.copy()
             env['DOCKER_BUILDKIT'] = "1"
-            console.print(f"\n[blue]Building empty PROD Image for Python {prod_image_params.python}\n")
+            get_console().print(f"\n[info]Building empty PROD Image for Python {prod_image_params.python}\n")
             cmd = construct_empty_docker_build_command(image_params=prod_image_params)
             build_command_result = run_command(
                 cmd,
diff --git a/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_params.py b/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_params.py
index 50eeca452b..116fae9333 100644
--- a/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_params.py
+++ b/dev/breeze/src/airflow_breeze/build_image/prod/build_prod_params.py
@@ -31,7 +31,7 @@ from airflow_breeze.global_constants import (
     get_airflow_extras,
     get_airflow_version,
 )
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 
 
 @dataclass
@@ -173,10 +173,10 @@ class BuildProdParams:
             self.airflow_version = self.install_airflow_reference
         elif len(self.install_airflow_version) > 0:
             if not re.match(r'^[0-9\.]+((a|b|rc|alpha|beta|pre)[0-9]+)?$', self.install_airflow_version):
-                console.print(
-                    f'\n[red]ERROR: Bad value for install-airflow-version:{self.install_airflow_version}'
+                get_console().print(
+                    f'\n[error]ERROR: Bad value for install-airflow-version:{self.install_airflow_version}'
                 )
-                console.print('[red]Only numerical versions allowed for PROD image here !')
+                get_console().print('[error]Only numerical versions allowed for PROD image here !')
                 sys.exit()
             extra_build_flags.extend(["--build-arg", "AIRFLOW_INSTALLATION_METHOD=apache-airflow"])
             extra_build_flags.extend(
@@ -239,7 +239,7 @@ class BuildProdParams:
         return "https://raw.githubusercontent.com/apache/airflow/main/docs/docker-stack/README.md"
 
     def print_info(self):
-        console.print(f"CI Image: {self.airflow_version} Python: {self.python}.")
+        get_console().print(f"CI Image: {self.airflow_version} Python: {self.python}.")
 
     @property
     def airflow_pre_cached_pip_packages(self) -> str:
diff --git a/dev/breeze/src/airflow_breeze/commands/ci_image_tools.py b/dev/breeze/src/airflow_breeze/commands/ci_image_tools.py
index eb7ec5f667..15fd2d52f5 100644
--- a/dev/breeze/src/airflow_breeze/commands/ci_image_tools.py
+++ b/dev/breeze/src/airflow_breeze/commands/ci_image_tools.py
@@ -66,7 +66,7 @@ from airflow_breeze.commands.common_options import (
 from airflow_breeze.commands.main import main
 from airflow_breeze.utils.ci_group import ci_group
 from airflow_breeze.utils.confirm import set_forced_answer
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.pulll_image import run_pull_image, run_pull_in_parallel
 from airflow_breeze.utils.python_versions import get_python_version_list
 from airflow_breeze.utils.run_tests import verify_an_image
@@ -216,7 +216,7 @@ def build_image(
             verbose=verbose, dry_run=dry_run, with_ci_group=with_ci_group, ci_image_params=ci_image_params
         )
         if return_code != 0:
-            console.print(f"[red]Error when building image! {info}")
+            get_console().print(f"[error]Error when building image! {info}")
             sys.exit(return_code)
 
     set_forced_answer(answer)
@@ -290,7 +290,7 @@ def pull_image(
             poll_time=10.0,
         )
         if return_code != 0:
-            console.print(f"[red]There was an error when pulling CI image: {info}[/]")
+            get_console().print(f"[error]There was an error when pulling CI image: {info}[/]")
             sys.exit(return_code)
 
 
@@ -321,7 +321,7 @@ def verify_image(
     if image_name is None:
         build_params = BuildCiParams(python=python, image_tag=image_tag, github_repository=github_repository)
         image_name = build_params.airflow_image_name_with_tag
-    console.print(f"[bright_blue]Verifying CI image: {image_name}[/]")
+    get_console().print(f"[info]Verifying CI image: {image_name}[/]")
     return_code, info = verify_an_image(
         image_name=image_name,
         verbose=verbose,
diff --git a/dev/breeze/src/airflow_breeze/commands/configuration_and_maintenance.py b/dev/breeze/src/airflow_breeze/commands/configuration_and_maintenance.py
index 153a11b208..a83d24c921 100644
--- a/dev/breeze/src/airflow_breeze/commands/configuration_and_maintenance.py
+++ b/dev/breeze/src/airflow_breeze/commands/configuration_and_maintenance.py
@@ -41,7 +41,7 @@ from airflow_breeze.global_constants import DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
 from airflow_breeze.shell.shell_params import ShellParams
 from airflow_breeze.utils.cache import check_if_cache_exists, delete_cache, touch_cache_file
 from airflow_breeze.utils.confirm import Answer, set_forced_answer, user_confirm
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.docker_command_utils import (
     check_docker_resources,
     construct_env_variables_docker_compose_command,
@@ -109,6 +109,7 @@ CONFIGURATION_AND_MAINTENANCE_PARAMETERS = {
                 "--backend",
                 "--cheatsheet",
                 "--asciiart",
+                "--colour",
             ],
         },
     ],
@@ -131,12 +132,12 @@ CONFIGURATION_AND_MAINTENANCE_PARAMETERS = {
 def cleanup(verbose: bool, dry_run: bool, github_repository: str, all: bool, answer: Optional[str]):
     set_forced_answer(answer)
     if all:
-        console.print(
-            "\n[bright_yellow]Removing cache of parameters, clean up docker cache "
+        get_console().print(
+            "\n[info]Removing cache of parameters, clean up docker cache "
             "and remove locally downloaded images[/]"
         )
     else:
-        console.print("\n[bright_yellow]Removing cache of parameters, and cleans up docker cache[/]")
+        get_console().print("[info]Removing cache of parameters, and cleans up docker cache[/]")
     if all:
         docker_images_command_to_execute = [
             'docker',
@@ -151,10 +152,10 @@ def cleanup(verbose: bool, dry_run: bool, github_repository: str, all: bool, ans
         )
         images = command_result.stdout.splitlines() if command_result and command_result.stdout else []
         if images:
-            console.print("[light_blue]Removing images:[/]")
+            get_console().print("[light_blue]Removing images:[/]")
             for image in images:
-                console.print(f"[light_blue] * {image}[/]")
-            console.print()
+                get_console().print(f"[light_blue] * {image}[/]")
+            get_console().print()
             docker_rmi_command_to_execute = [
                 'docker',
                 'rmi',
@@ -167,15 +168,15 @@ def cleanup(verbose: bool, dry_run: bool, github_repository: str, all: bool, ans
             elif given_answer == Answer.QUIT:
                 sys.exit(0)
         else:
-            console.print("[light_blue]No locally downloaded images to remove[/]\n")
-    console.print("Pruning docker images")
+            get_console().print("[light_blue]No locally downloaded images to remove[/]\n")
+    get_console().print("Pruning docker images")
     given_answer = user_confirm("Are you sure?", timeout=None)
     if given_answer == Answer.YES:
         system_prune_command_to_execute = ['docker', 'system', 'prune']
         run_command(system_prune_command_to_execute, verbose=verbose, dry_run=dry_run, check=False)
     elif given_answer == Answer.QUIT:
         sys.exit(0)
-    console.print(f"Removing build cache dir ${BUILD_CACHE_DIR}")
+    get_console().print(f"Removing build cache dir ${BUILD_CACHE_DIR}")
     given_answer = user_confirm("Are you sure?", timeout=None)
     if given_answer == Answer.YES:
         if not dry_run:
@@ -239,14 +240,14 @@ def setup_autocomplete(verbose: bool, dry_run: bool, force: bool, answer: Option
     detected_shell = os.environ.get('SHELL')
     detected_shell = None if detected_shell is None else detected_shell.split(os.sep)[-1]
     if detected_shell not in ['bash', 'zsh', 'fish']:
-        console.print(f"\n[red] The shell {detected_shell} is not supported for autocomplete![/]\n")
+        get_console().print(f"\n[error] The shell {detected_shell} is not supported for autocomplete![/]\n")
         sys.exit(1)
-    console.print(f"Installing {detected_shell} completion for local user")
+    get_console().print(f"Installing {detected_shell} completion for local user")
     autocomplete_path = (
         AIRFLOW_SOURCES_ROOT / "dev" / "breeze" / "autocomplete" / f"{NAME}-complete-{detected_shell}.sh"
     )
-    console.print(f"[bright_blue]Activation command script is available here: {autocomplete_path}[/]\n")
-    console.print(f"[bright_yellow]We need to add above script to your {detected_shell} profile.[/]\n")
+    get_console().print(f"[info]Activation command script is available here: {autocomplete_path}[/]\n")
+    get_console().print(f"[info]We need to add above script to your {detected_shell} profile.[/]\n")
     given_answer = user_confirm("Should we proceed ?", default_answer=Answer.NO, timeout=3)
     if given_answer == Answer.YES:
         if detected_shell == 'bash':
@@ -261,8 +262,8 @@ def setup_autocomplete(verbose: bool, dry_run: bool, force: bool, answer: Option
             # Include steps for fish shell
             script_path = str(Path('~').expanduser() / f'.config/fish/completions/{NAME}.fish')
             if os.path.exists(script_path) and not force:
-                console.print(
-                    "\n[bright_yellow]Autocompletion is already setup. Skipping. "
+                get_console().print(
+                    "\n[warning]Autocompletion is already setup. Skipping. "
                     "You can force autocomplete installation by adding --force/]\n"
                 )
             else:
@@ -278,7 +279,7 @@ def setup_autocomplete(verbose: bool, dry_run: bool, force: bool, answer: Option
             command_to_execute = f". {autocomplete_path}"
             write_to_shell(command_to_execute, dry_run, script_path, force)
     elif given_answer == Answer.NO:
-        console.print(
+        get_console().print(
             "\nPlease follow the https://click.palletsprojects.com/en/8.1.x/shell-completion/ "
             "to setup autocompletion for breeze manually if you want to use it.\n"
         )
@@ -290,20 +291,21 @@ def setup_autocomplete(verbose: bool, dry_run: bool, force: bool, answer: Option
 @main.command()
 def version(verbose: bool, python: str):
     """Print information about version of apache-airflow-breeze."""
-    console.print(ASCIIART, style=ASCIIART_STYLE)
-    console.print(f"\n[bright_blue]Breeze version: {VERSION}[/]")
-    console.print(f"[bright_blue]Breeze installed from: {get_installation_airflow_sources()}[/]")
-    console.print(f"[bright_blue]Used Airflow sources : {get_used_airflow_sources()}[/]\n")
+
+    get_console().print(ASCIIART, style=ASCIIART_STYLE)
+    get_console().print(f"\n[info]Breeze version: {VERSION}[/]")
+    get_console().print(f"[info]Breeze installed from: {get_installation_airflow_sources()}[/]")
+    get_console().print(f"[info]Used Airflow sources : {get_used_airflow_sources()}[/]\n")
     if verbose:
-        console.print(
-            f"[bright_blue]Installation sources config hash : "
+        get_console().print(
+            f"[info]Installation sources config hash : "
             f"{get_installation_sources_config_metadata_hash()}[/]"
         )
-        console.print(
-            f"[bright_blue]Used sources config hash         : " f"{get_used_sources_setup_metadata_hash()}[/]"
+        get_console().print(
+            f"[info]Used sources config hash         : " f"{get_used_sources_setup_metadata_hash()}[/]"
         )
-        console.print(
-            f"[bright_blue]Package config hash              : " f"{(get_package_setup_metadata_hash())}[/]\n"
+        get_console().print(
+            f"[info]Package config hash              : " f"{(get_package_setup_metadata_hash())}[/]\n"
         )
 
 
@@ -315,6 +317,12 @@ def version(verbose: bool, python: str):
 @option_mssql_version
 @click.option('-C/-c', '--cheatsheet/--no-cheatsheet', help="Enable/disable cheatsheet.", default=None)
 @click.option('-A/-a', '--asciiart/--no-asciiart', help="Enable/disable ASCIIart.", default=None)
+@click.option(
+    '-B/-b',
+    '--colour/--no-colour',
+    help="Enable/disable Colour mode (useful for colour blind-friendly communication).",
+    default=None,
+)
 def change_config(
     python: str,
     backend: str,
@@ -323,44 +331,56 @@ def change_config(
     mssql_version: str,
     cheatsheet: bool,
     asciiart: bool,
+    colour: bool,
 ):
     """
     Show/update configuration (Python, Backend, Cheatsheet, ASCIIART).
     """
     asciiart_file = "suppress_asciiart"
     cheatsheet_file = "suppress_cheatsheet"
+    colour_file = "suppress_colour"
 
     if asciiart is not None:
         if asciiart:
             delete_cache(asciiart_file)
-            console.print('[bright_blue]Enable ASCIIART![/]')
+            get_console().print('[info]Enable ASCIIART![/]')
         else:
             touch_cache_file(asciiart_file)
-            console.print('[bright_blue]Disable ASCIIART![/]')
+            get_console().print('[info]Disable ASCIIART![/]')
     if cheatsheet is not None:
         if cheatsheet:
             delete_cache(cheatsheet_file)
-            console.print('[bright_blue]Enable Cheatsheet[/]')
+            get_console().print('[info]Enable Cheatsheet[/]')
         elif cheatsheet is not None:
             touch_cache_file(cheatsheet_file)
-            console.print('[bright_blue]Disable Cheatsheet[/]')
+            get_console().print('[info]Disable Cheatsheet[/]')
+    if colour is not None:
+        if colour:
+            delete_cache(colour_file)
+            get_console().print('[info]Enable Colour[/]')
+        elif colour is not None:
+            touch_cache_file(colour_file)
+            get_console().print('[info]Disable Colour[/]')
 
     def get_status(file: str):
         return "disabled" if check_if_cache_exists(file) else "enabled"
 
-    console.print()
-    console.print("[bright_blue]Current configuration:[/]")
-    console.print()
-    console.print(f"[bright_blue]* Python: {python}[/]")
-    console.print(f"[bright_blue]* Backend: {backend}[/]")
-    console.print()
-    console.print(f"[bright_blue]* Postgres version: {postgres_version}[/]")
-    console.print(f"[bright_blue]* MySQL version: {mysql_version}[/]")
-    console.print(f"[bright_blue]* MsSQL version: {mssql_version}[/]")
-    console.print()
-    console.print(f"[bright_blue]* ASCIIART: {get_status(asciiart_file)}[/]")
-    console.print(f"[bright_blue]* Cheatsheet: {get_status(cheatsheet_file)}[/]")
-    console.print()
+    get_console().print()
+    get_console().print("[info]Current configuration:[/]")
+    get_console().print()
+    get_console().print(f"[info]* Python: {python}[/]")
+    get_console().print(f"[info]* Backend: {backend}[/]")
+    get_console().print()
+    get_console().print(f"[info]* Postgres version: {postgres_version}[/]")
+    get_console().print(f"[info]* MySQL version: {mysql_version}[/]")
+    get_console().print(f"[info]* MsSQL version: {mssql_version}[/]")
+    get_console().print()
+    get_console().print(f"[info]* ASCIIART: {get_status(asciiart_file)}[/]")
+    get_console().print(f"[info]* Cheatsheet: {get_status(cheatsheet_file)}[/]")
+    get_console().print()
+    get_console().print()
+    get_console().print(f"[info]* Colour: {get_status(colour_file)}[/]")
+    get_console().print()
 
 
 @main.command(name="free-space", help="Free space for jobs run in CI.")
@@ -426,8 +446,8 @@ def write_to_shell(command_to_execute: str, dry_run: bool, script_path: str, for
     if not skip_check:
         if BREEZE_COMMENT in script_path_file.read_text():
             if not force_setup:
-                console.print(
-                    "\n[bright_yellow]Autocompletion is already setup. Skipping. "
+                get_console().print(
+                    "\n[warning]Autocompletion is already setup. Skipping. "
                     "You can force autocomplete installation by adding --force[/]\n"
                 )
                 return False
@@ -436,13 +456,13 @@ def write_to_shell(command_to_execute: str, dry_run: bool, script_path: str, for
                 remove_autogenerated_code(script_path)
     text = ''
     if script_path_file.exists():
-        console.print(f"\nModifying the {script_path} file!\n")
-        console.print(f"\nCopy of the original file is held in {script_path}.bak !\n")
+        get_console().print(f"\nModifying the {script_path} file!\n")
+        get_console().print(f"\nCopy of the original file is held in {script_path}.bak !\n")
         if not dry_run:
             backup(script_path_file)
             text = script_path_file.read_text()
     else:
-        console.print(f"\nCreating the {script_path} file!\n")
+        get_console().print(f"\nCreating the {script_path} file!\n")
     if not dry_run:
         script_path_file.write_text(
             text
@@ -453,10 +473,9 @@ def write_to_shell(command_to_execute: str, dry_run: bool, script_path: str, for
             + END_LINE
         )
     else:
-        console.print(f"[bright_blue]The autocomplete script would be added to {script_path}[/]")
-    console.print(
-        f"\n[bright_yellow]IMPORTANT!!!! Please exit and re-enter your shell or run:[/]"
-        f"\n\n   source {script_path}\n"
+        get_console().print(f"[info]The autocomplete script would be added to {script_path}[/]")
+    get_console().print(
+        f"\n[warning]Please exit and re-enter your shell or run:[/]" f"\n\n   source {script_path}\n"
     )
     return True
 
diff --git a/dev/breeze/src/airflow_breeze/commands/configure_rich_click.py b/dev/breeze/src/airflow_breeze/commands/configure_rich_click.py
index 2eeac20db0..1807ad3fb0 100644
--- a/dev/breeze/src/airflow_breeze/commands/configure_rich_click.py
+++ b/dev/breeze/src/airflow_breeze/commands/configure_rich_click.py
@@ -44,7 +44,7 @@ try:
     click.rich_click.STYLE_ERRORS_SUGGESTION = "bright_blue italic"
     click.rich_click.ERRORS_SUGGESTION = "\nTry running the '--help' flag for more information.\n"
     click.rich_click.ERRORS_EPILOGUE = (
-        "\nTo find out more, visit [bright_blue]https://github.com/apache/airflow/blob/main/BREEZE.rst[/]\n"
+        "\nTo find out more, visit [info]https://github.com/apache/airflow/blob/main/BREEZE.rst[/]\n"
     )
     click.rich_click.OPTION_GROUPS = {
         **DEVELOPER_PARAMETERS,
diff --git a/dev/breeze/src/airflow_breeze/commands/custom_param_types.py b/dev/breeze/src/airflow_breeze/commands/custom_param_types.py
index 7a779865f6..4737aa2737 100644
--- a/dev/breeze/src/airflow_breeze/commands/custom_param_types.py
+++ b/dev/breeze/src/airflow_breeze/commands/custom_param_types.py
@@ -26,7 +26,7 @@ from airflow_breeze.utils.cache import (
     read_from_cache_file,
     write_to_cache_file,
 )
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.recording import output_file_for_recording
 
 
@@ -71,8 +71,8 @@ class CacheableChoice(click.Choice):
         if isinstance(value, CacheableDefault):
             is_cached, new_value = read_and_validate_value_from_cache(param_name, value.value)
             if not is_cached:
-                console.print(
-                    f"\n[bright_blue]Default value of {param.name} " f"parameter {new_value} used.[/]\n"
+                get_console().print(
+                    f"\n[info]Default value of {param.name} " f"parameter {new_value} used.[/]\n"
                 )
         else:
             allowed, allowed_values = check_if_values_allowed(param_name, value)
@@ -81,8 +81,8 @@ class CacheableChoice(click.Choice):
                 write_to_cache_file(param_name, new_value, check_allowed_values=False)
             else:
                 new_value = allowed_values[0]
-                console.print(
-                    f"\n[yellow]The value {value} is not allowed for parameter {param.name}. "
+                get_console().print(
+                    f"\n[warning]The value {value} is not allowed for parameter {param.name}. "
                     f"Setting default value to {new_value}"
                 )
                 write_to_cache_file(param_name, new_value, check_allowed_values=False)
diff --git a/dev/breeze/src/airflow_breeze/commands/developer_commands.py b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
index c909821d38..e44c360b6c 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
@@ -53,7 +53,7 @@ from airflow_breeze.pre_commit_ids import PRE_COMMIT_LIST
 from airflow_breeze.shell.enter_shell import enter_shell
 from airflow_breeze.shell.shell_params import ShellParams
 from airflow_breeze.utils.confirm import set_forced_answer
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.docker_command_utils import (
     construct_env_variables_docker_compose_command,
     get_extra_docker_flags,
@@ -221,8 +221,8 @@ def shell(
     """Enter breeze.py environment. this is the default command use when no other is selected."""
     set_forced_answer(answer)
     if verbose or dry_run:
-        console.print("\n[green]Welcome to breeze.py[/]\n")
-        console.print(f"\n[green]Root of Airflow Sources = {AIRFLOW_SOURCES_ROOT}[/]\n")
+        get_console().print("\n[success]Welcome to breeze.py[/]\n")
+        get_console().print(f"\n[success]Root of Airflow Sources = {AIRFLOW_SOURCES_ROOT}[/]\n")
     enter_shell(
         verbose=verbose,
         dry_run=dry_run,
@@ -409,7 +409,7 @@ def static_checks(
     assert_pre_commit_installed(verbose=verbose)
     command_to_execute = [sys.executable, "-m", "pre_commit", 'run']
     if last_commit and commit_ref:
-        console.print("\n[red]You cannot specify both --last-commit and --commit-ref[/]\n")
+        get_console().print("\n[error]You cannot specify both --last-commit and --commit-ref[/]\n")
         sys.exit(1)
     for single_check in type:
         command_to_execute.append(single_check)
@@ -439,7 +439,7 @@ def static_checks(
         env=env,
     )
     if static_checks_result.returncode != 0:
-        console.print("[red]There were errors during pre-commit check. They should be fixed[/]")
+        get_console().print("[error]There were errors during pre-commit check. They should be fixed[/]")
     sys.exit(static_checks_result.returncode)
 
 
diff --git a/dev/breeze/src/airflow_breeze/commands/production_image_tools.py b/dev/breeze/src/airflow_breeze/commands/production_image_tools.py
index 06ba3142da..52fd3ec2a3 100644
--- a/dev/breeze/src/airflow_breeze/commands/production_image_tools.py
+++ b/dev/breeze/src/airflow_breeze/commands/production_image_tools.py
@@ -67,7 +67,7 @@ from airflow_breeze.commands.main import main
 from airflow_breeze.global_constants import ALLOWED_INSTALLATION_METHODS, DEFAULT_EXTRAS
 from airflow_breeze.utils.ci_group import ci_group
 from airflow_breeze.utils.confirm import set_forced_answer
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.pulll_image import run_pull_image, run_pull_in_parallel
 from airflow_breeze.utils.python_versions import get_python_version_list
 from airflow_breeze.utils.run_tests import verify_an_image
@@ -268,7 +268,7 @@ def build_prod_image(
             verbose=verbose, dry_run=dry_run, with_ci_group=with_ci_group, prod_image_params=prod_image_params
         )
         if return_code != 0:
-            console.print(f"[red]Error when building image! {info}")
+            get_console().print(f"[error]Error when building image! {info}")
             sys.exit(return_code)
 
     set_forced_answer(answer)
@@ -344,7 +344,7 @@ def pull_prod_image(
             poll_time=10.0,
         )
         if return_code != 0:
-            console.print(f"[red]There was an error when pulling PROD image: {info}[/]")
+            get_console().print(f"[error]There was an error when pulling PROD image: {info}[/]")
             sys.exit(return_code)
 
 
@@ -377,7 +377,7 @@ def verify_prod_image(
             python=python, image_tag=image_tag, github_repository=github_repository
         )
         image_name = build_params.airflow_image_name_with_tag
-    console.print(f"[bright_blue]Verifying PROD image: {image_name}[/]")
+    get_console().print(f"[info]Verifying PROD image: {image_name}[/]")
     return_code, info = verify_an_image(
         image_name=image_name,
         verbose=verbose,
diff --git a/dev/breeze/src/airflow_breeze/commands/release_management.py b/dev/breeze/src/airflow_breeze/commands/release_management.py
index f9fe3a3948..72e2756878 100644
--- a/dev/breeze/src/airflow_breeze/commands/release_management.py
+++ b/dev/breeze/src/airflow_breeze/commands/release_management.py
@@ -49,7 +49,7 @@ from airflow_breeze.global_constants import (
 from airflow_breeze.shell.shell_params import ShellParams
 from airflow_breeze.utils.ci_group import ci_group
 from airflow_breeze.utils.confirm import Answer, set_forced_answer, user_confirm
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.constraints import run_generate_constraints, run_generate_constraints_in_parallel
 from airflow_breeze.utils.docker_command_utils import (
     construct_env_variables_docker_compose_command,
@@ -331,8 +331,8 @@ def generate_constraints(
         )
     if given_answer != Answer.YES:
         if run_in_parallel:
-            console.print("\n[yellow]Use this command to build the images:[/]\n")
-            console.print(
+            get_console().print("\n[info]Use this command to build the images:[/]\n")
+            get_console().print(
                 f"     breeze build-image --run-in-parallel --python-versions '{python_versions}' "
                 f"--upgrade-to-newer-dependencies true\n"
             )
@@ -340,8 +340,8 @@ def generate_constraints(
             shell_params = ShellParams(
                 image_tag=image_tag, python=python, github_repository=github_repository, answer=answer
             )
-            console.print("\n[yellow]Use this command to build the image:[/]\n")
-            console.print(
+            get_console().print("\n[info]Use this command to build the image:[/]\n")
+            get_console().print(
                 f"     breeze build-image --python'{shell_params.python}' "
                 f"--upgrade-to-newer-dependencies true\n"
             )
@@ -375,7 +375,7 @@ def generate_constraints(
                 generate_constraints_mode=generate_constraints_mode,
             )
         if return_code != 0:
-            console.print(f"[red]There was an error when generating constraints: {info}[/]")
+            get_console().print(f"[error]There was an error when generating constraints: {info}[/]")
             sys.exit(return_code)
 
 
diff --git a/dev/breeze/src/airflow_breeze/commands/testing.py b/dev/breeze/src/airflow_breeze/commands/testing.py
index df124749c4..456544b57f 100644
--- a/dev/breeze/src/airflow_breeze/commands/testing.py
+++ b/dev/breeze/src/airflow_breeze/commands/testing.py
@@ -30,7 +30,7 @@ from airflow_breeze.commands.common_options import (
     option_verbose,
 )
 from airflow_breeze.commands.main import main
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.run_tests import run_docker_compose_tests
 
 TESTING_COMMANDS = {
@@ -83,7 +83,7 @@ def docker_compose_tests(
             python=python, image_tag=image_tag, github_repository=github_repository
         )
         image_name = build_params.airflow_image_name_with_tag
-    console.print(f"[bright_blue]Running docker-compose with PROD image: {image_name}[/]")
+    get_console().print(f"[info]Running docker-compose with PROD image: {image_name}[/]")
     return_code, info = run_docker_compose_tests(
         image_name=image_name,
         verbose=verbose,
diff --git a/dev/breeze/src/airflow_breeze/shell/enter_shell.py b/dev/breeze/src/airflow_breeze/shell/enter_shell.py
index 933f85ca4d..51294d55bb 100644
--- a/dev/breeze/src/airflow_breeze/shell/enter_shell.py
+++ b/dev/breeze/src/airflow_breeze/shell/enter_shell.py
@@ -29,7 +29,7 @@ from airflow_breeze.utils.cache import (
     read_from_cache_file,
     write_to_cache_file,
 )
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.docker_command_utils import (
     SOURCE_OF_DEFAULT_VALUES_FOR_VARIABLES,
     VARIABLES_IN_CACHE,
@@ -83,18 +83,18 @@ def enter_shell(**kwargs) -> Union[subprocess.CompletedProcess, subprocess.Calle
     verbose = kwargs['verbose']
     dry_run = kwargs['dry_run']
     if not check_docker_is_running(verbose):
-        console.print(
-            '[red]Docker is not running.[/]\n'
-            '[bright_yellow]Please make sure Docker is installed and running.[/]'
+        get_console().print(
+            '[error]Docker is not running.[/]\n'
+            '[warning]Please make sure Docker is installed and running.[/]'
         )
         sys.exit(1)
     check_docker_version(verbose)
     check_docker_compose_version(verbose)
     updated_kwargs = synchronize_cached_params(kwargs)
     if read_from_cache_file('suppress_asciiart') is None:
-        console.print(ASCIIART, style=ASCIIART_STYLE)
+        get_console().print(ASCIIART, style=ASCIIART_STYLE)
     if read_from_cache_file('suppress_cheatsheet') is None:
-        console.print(CHEATSHEET, style=CHEATSHEET_STYLE)
+        get_console().print(CHEATSHEET, style=CHEATSHEET_STYLE)
     enter_shell_params = ShellParams(**filter_out_none(**updated_kwargs))
     return run_shell_with_build_image_checks(verbose, dry_run, enter_shell_params)
 
@@ -122,10 +122,10 @@ def run_shell_with_build_image_checks(
     )
     ci_image_params = BuildCiParams(python=shell_params.python, upgrade_to_newer_dependencies="false")
     if build_ci_image_check_cache.exists():
-        console.print(f'[bright_blue]{shell_params.the_image_type} image already built locally.[/]')
+        get_console().print(f'[info]{shell_params.the_image_type} image already built locally.[/]')
     else:
-        console.print(
-            f'[bright_yellow]{shell_params.the_image_type} image not built locally. ' f'Forcing build.[/]'
+        get_console().print(
+            f'[warning]{shell_params.the_image_type} image not built locally. Forcing build.[/]'
         )
         ci_image_params.force_build = True
 
diff --git a/dev/breeze/src/airflow_breeze/shell/shell_params.py b/dev/breeze/src/airflow_breeze/shell/shell_params.py
index eb4ae34a7a..7d7f1daf53 100644
--- a/dev/breeze/src/airflow_breeze/shell/shell_params.py
+++ b/dev/breeze/src/airflow_breeze/shell/shell_params.py
@@ -31,7 +31,7 @@ from airflow_breeze.global_constants import (
     MOUNT_SELECTED,
     get_airflow_version,
 )
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.path_utils import AIRFLOW_SOURCES_ROOT, BUILD_CACHE_DIR, SCRIPTS_CI_DIR
 from airflow_breeze.utils.run_utils import get_filesystem_type, run_command
 
@@ -143,13 +143,13 @@ class ShellParams:
         return sqlite_url
 
     def print_badge_info(self):
-        console.print(f'Use {self.the_image_type} image')
-        console.print(f'Branch Name: {self.airflow_branch}')
-        console.print(f'Docker Image: {self.airflow_image_name_with_tag}')
-        console.print(f'Airflow source version:{self.airflow_version}')
-        console.print(f'Python Version: {self.python}')
-        console.print(f'Backend: {self.backend} {self.backend_version}')
-        console.print(f'Airflow used at runtime: {self.use_airflow_version}')
+        get_console().print(f'Use {self.the_image_type} image')
+        get_console().print(f'Branch Name: {self.airflow_branch}')
+        get_console().print(f'Docker Image: {self.airflow_image_name_with_tag}')
+        get_console().print(f'Airflow source version:{self.airflow_version}')
+        get_console().print(f'Python Version: {self.python}')
+        get_console().print(f'Backend: {self.backend} {self.backend_version}')
+        get_console().print(f'Airflow used at runtime: {self.use_airflow_version}')
 
     @property
     def compose_files(self):
diff --git a/dev/breeze/src/airflow_breeze/utils/cache.py b/dev/breeze/src/airflow_breeze/utils/cache.py
index 2319ee4505..19b0fae0bd 100644
--- a/dev/breeze/src/airflow_breeze/utils/cache.py
+++ b/dev/breeze/src/airflow_breeze/utils/cache.py
@@ -27,7 +27,7 @@ from pathlib import Path
 from typing import Any, List, Optional, Tuple
 
 from airflow_breeze import global_constants
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.path_utils import BUILD_CACHE_DIR
 
 
@@ -64,9 +64,9 @@ def write_to_cache_file(param_name: str, param_value: str, check_allowed_values:
         cache_path.parent.mkdir(parents=True, exist_ok=True)
         cache_path.write_text(param_value)
     else:
-        console.print(f'[cyan]You have sent the {param_value} for {param_name}')
-        console.print(f'[cyan]Allowed value for the {param_name} are {allowed_values}')
-        console.print('[cyan]Provide one of the supported params. Write to cache dir failed')
+        get_console().print(f'[cyan]You have sent the {param_value} for {param_name}')
+        get_console().print(f'[cyan]Allowed value for the {param_name} are {allowed_values}')
+        get_console().print('[cyan]Provide one of the supported params. Write to cache dir failed')
         sys.exit(1)
 
 
diff --git a/dev/breeze/src/airflow_breeze/utils/console.py b/dev/breeze/src/airflow_breeze/utils/console.py
index ca5a4a3096..9a14d91eae 100644
--- a/dev/breeze/src/airflow_breeze/utils/console.py
+++ b/dev/breeze/src/airflow_breeze/utils/console.py
@@ -19,24 +19,49 @@ Console used by all processes. We are forcing colors and terminal output as Bree
 to be only run in CI or real development terminal - in both cases we want to have colors on.
 """
 import os
+from functools import lru_cache
 
-try:
-    from rich.console import Console
-    from rich.theme import Theme
+from rich.console import Console
+from rich.theme import Theme
 
-    recording_width = os.environ.get("RECORD_BREEZE_WIDTH")
-    recording_file = os.environ.get("RECORD_BREEZE_OUTPUT_FILE")
+recording_width = os.environ.get("RECORD_BREEZE_WIDTH")
+recording_file = os.environ.get("RECORD_BREEZE_OUTPUT_FILE")
 
-    custom_theme = Theme({"info": "blue", "warning": "magenta", "error": "red"})
-    console = Console(
+
+def get_theme() -> Theme:
+    try:
+        from airflow_breeze.utils.cache import read_from_cache_file
+
+        if read_from_cache_file('suppress_colour') is not None:
+            return Theme(
+                {
+                    "success": "bold italic",
+                    "info": "bold",
+                    "warning": "italic",
+                    "error": "italic underline",
+                }
+            )
+    except ImportError:
+        # sometimes we might want to use console before the cache folder is determined
+        # and in this case we will get an import error due to partial initialization.
+        # in this case we switch to default theme
+        pass
+    return Theme(
+        {
+            "success": "green",
+            "info": "bright_blue",
+            "warning": "bright_yellow",
+            "error": "red",
+        }
+    )
+
+
+@lru_cache(maxsize=None)
+def get_console() -> Console:
+    return Console(
         force_terminal=True,
         color_system="standard",
         width=180 if not recording_width else int(recording_width),
-        theme=custom_theme,
+        theme=get_theme(),
         record=True if recording_file else False,
     )
-
-except ImportError:
-    # We handle the ImportError so that autocomplete works with just click installed
-    custom_theme = None  # type: ignore[assignment]
-    console = None  # type: ignore[assignment]
diff --git a/dev/breeze/src/airflow_breeze/utils/constraints.py b/dev/breeze/src/airflow_breeze/utils/constraints.py
index e8b28ca7dd..779b0d4924 100644
--- a/dev/breeze/src/airflow_breeze/utils/constraints.py
+++ b/dev/breeze/src/airflow_breeze/utils/constraints.py
@@ -19,7 +19,7 @@ import multiprocessing as mp
 from typing import List, Tuple
 
 from airflow_breeze.shell.shell_params import ShellParams
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.docker_command_utils import (
     construct_env_variables_docker_compose_command,
     get_extra_docker_flags,
@@ -63,8 +63,8 @@ def run_generate_constraints_in_parallel(
     verbose: bool,
 ):
     """Run generate constraints in parallel"""
-    console.print(
-        f"\n[bright_blue]Generating constraints with parallelism = {parallelism} "
+    get_console().print(
+        f"\n[info]Generating constraints with parallelism = {parallelism} "
         f"for the constraints: {python_version_list}[/]"
     )
     pool = mp.Pool(parallelism)
diff --git a/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py b/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
index b6a0c7f20f..4598a6ce97 100644
--- a/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
+++ b/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
@@ -51,7 +51,7 @@ from airflow_breeze.global_constants import (
     SSH_PORT,
     WEBSERVER_HOST_PORT,
 )
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.run_utils import commit_sha, prepare_build_command, run_command
 
 NECESSARY_HOST_VOLUMES = [
@@ -101,7 +101,7 @@ def get_extra_docker_flags(mount_sources: str) -> List[str]:
         for flag in NECESSARY_HOST_VOLUMES:
             extra_docker_flags.extend(["-v", str(AIRFLOW_SOURCES_ROOT) + flag])
     else:  # none
-        console.print('[bright_blue]Skip mounting host volumes to Docker[/]')
+        get_console().print('[info]Skip mounting host volumes to Docker[/]')
     extra_docker_flags.extend(["-v", f"{AIRFLOW_SOURCES_ROOT}/files:/files"])
     extra_docker_flags.extend(["-v", f"{AIRFLOW_SOURCES_ROOT}/dist:/dist"])
     extra_docker_flags.extend(["--rm"])
@@ -159,8 +159,10 @@ def check_docker_permission_denied(verbose) -> bool:
     if command_result.returncode != 0:
         permission_denied = True
         if command_result.stdout and 'Got permission denied while trying to connect' in command_result.stdout:
-            console.print('ERROR: You have `permission denied` error when trying to communicate with docker.')
-            console.print(
+            get_console().print(
+                'ERROR: You have `permission denied` error when trying to communicate with docker.'
+            )
+            get_console().print(
                 'Most likely you need to add your user to `docker` group: \
                 https://docs.docker.com/ engine/install/linux-postinstall/ .'
             )
@@ -215,20 +217,21 @@ def check_docker_version(verbose: bool):
         if docker_version_result.returncode == 0:
             docker_version = docker_version_result.stdout.strip()
         if docker_version == '':
-            console.print(
+            get_console().print(
                 f"""
-[yellow]Your version of docker is unknown. If the scripts fail, please make sure to[/]
-[yellow]install docker at least: {MIN_DOCKER_VERSION} version.[/]
+[warning]Your version of docker is unknown. If the scripts fail, please make sure to[/]
+[warning]install docker at least: {MIN_DOCKER_VERSION} version.[/]
 """
             )
         else:
             good_version = compare_version(docker_version, MIN_DOCKER_VERSION)
             if good_version:
-                console.print(f'[green]Good version of Docker: {docker_version}.[/]')
+                get_console().print(f'[success]Good version of Docker: {docker_version}.[/]')
             else:
-                console.print(
+                get_console().print(
                     f"""
-[yellow]Your version of docker is too old:{docker_version}. Please upgrade to at least {MIN_DOCKER_VERSION}[/]
+[warning]Your version of docker is too old:{docker_version}.
+Please upgrade to at least {MIN_DOCKER_VERSION}[/]
 """
                 )
 
@@ -257,24 +260,24 @@ def check_docker_compose_version(verbose: bool):
             version = '.'.join(version_extracted.groups())
             good_version = compare_version(version, MIN_DOCKER_COMPOSE_VERSION)
             if good_version:
-                console.print(f'[green]Good version of docker-compose: {version}[/]')
+                get_console().print(f'[success]Good version of docker-compose: {version}[/]')
             else:
-                console.print(
+                get_console().print(
                     f"""
-[yellow]You have too old version of docker-compose: {version}! At least 1.29 is needed! Please upgrade!
+[warning]You have too old version of docker-compose: {version}! At least 1.29 is needed! Please upgrade!
 """
                 )
-                console.print(
+                get_console().print(
                     """
 See https://docs.docker.com/compose/install/ for instructions.
 Make sure docker-compose you install is first on the PATH variable of yours.
 """
                 )
     else:
-        console.print(
+        get_console().print(
             """
-[yellow]Unknown docker-compose version. At least 1.29 is needed![/]
-[yellow]If Breeze fails upgrade to latest available docker-compose version.[/]
+[warning]Unknown docker-compose version. At least 1.29 is needed![/]
+[warning]If Breeze fails upgrade to latest available docker-compose version.[/]
 """
         )
 
@@ -376,8 +379,8 @@ def tag_and_push_image(
     :param verbose: whethere we produce verbose output
     :return:
     """
-    console.print(
-        f"[blue]Tagging and pushing the {image_params.airflow_image_name} as "
+    get_console().print(
+        f"[info]Tagging and pushing the {image_params.airflow_image_name} as "
         f"{image_params.airflow_image_name_with_tag}.[/]"
     )
     cmd = construct_docker_tag_command(image_params)
diff --git a/dev/breeze/src/airflow_breeze/utils/find_newer_dependencies.py b/dev/breeze/src/airflow_breeze/utils/find_newer_dependencies.py
index 17d577a090..f4c37d9f22 100644
--- a/dev/breeze/src/airflow_breeze/utils/find_newer_dependencies.py
+++ b/dev/breeze/src/airflow_breeze/utils/find_newer_dependencies.py
@@ -32,10 +32,9 @@ import json
 from datetime import timedelta
 from typing import Any, Dict, List, Tuple
 
-from rich.console import Console
 from rich.progress import Progress
 
-console = Console(width=400, color_system="standard")
+from airflow_breeze.utils.console import get_console
 
 
 def find_newer_dependencies(
@@ -58,12 +57,12 @@ def find_newer_dependencies(
         min_date = (pendulum.now(tz=tz) - timedelta(days=max_age)).replace(
             hour=0, minute=0, second=0, microsecond=0
         )
-    console.print(
-        "\n[bright_yellow]Those are possible candidates that broke current "
+    get_console().print(
+        "\n[info]Those are possible candidates that broke current "
         "`pip` resolution mechanisms by falling back to long backtracking[/]\n"
     )
-    console.print(f"\n[bright_yellow]We are limiting to packages updated after {min_date} ({timezone})[/]\n")
-    with Progress(console=console) as progress:
+    get_console().print(f"\n[info]We are limiting to packages updated after {min_date} ({timezone})[/]\n")
+    with Progress(console=get_console()) as progress:
         task = progress.add_task(f"Processing {count_packages} packages.", total=count_packages)
         for package_line in package_lines:
             package, _, constraints_package_version_string = package_line.split("=")
@@ -79,17 +78,17 @@ def find_newer_dependencies(
                 constrained_packages[package] = constraints_package_version
             progress.advance(task)
             progress.refresh()
-    console.print(
-        "\n[bright_yellow]If you see long running builds with `pip` backtracking, you should follow[/]"
+    get_console().print(
+        "\n[warning]If you see long running builds with `pip` backtracking, you should follow[/]"
     )
-    console.print(
-        "[bright_yellow]https://github.com/apache/airflow/blob/main/dev/TRACKING_BACKTRACKING_ISSUES.md[/]\n"
+    get_console().print(
+        "[warning]https://github.com/apache/airflow/blob/main/dev/TRACKING_BACKTRACKING_ISSUES.md[/]\n"
     )
     constraint_string = ""
     for package, constrained_version in constrained_packages.items():
         constraint_string += f' "{package}=={constrained_version}"'
-    console.print("[bright_yellow]Use the following pip install command (see the doc above for details)\n")
-    console.print(
+    get_console().print("[info]Use the following pip install command (see the doc above for details)\n")
+    get_console().print(
         'pip install ".[devel_all]" --upgrade --upgrade-strategy eager '
         '"dill<0.3.3" "certifi<2021.0.0" "google-ads<14.0.1"' + constraint_string,
         markup=False,
diff --git a/dev/breeze/src/airflow_breeze/utils/md5_build_check.py b/dev/breeze/src/airflow_breeze/utils/md5_build_check.py
index 5d445a207f..d0933e3c2c 100644
--- a/dev/breeze/src/airflow_breeze/utils/md5_build_check.py
+++ b/dev/breeze/src/airflow_breeze/utils/md5_build_check.py
@@ -22,7 +22,7 @@ from pathlib import Path
 from typing import List, Tuple
 
 from airflow_breeze.global_constants import FILES_FOR_REBUILD_CHECK
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.path_utils import AIRFLOW_SOURCES_ROOT
 
 
@@ -96,15 +96,17 @@ def md5sum_check_if_build_is_needed(md5sum_cache_dir: Path) -> bool:
     build_needed = False
     modified_files, not_modified_files = calculate_md5_checksum_for_files(md5sum_cache_dir, update=False)
     if len(modified_files) > 0:
-        console.print(
-            '[bright_yellow]The following files are modified since last time image was built: [/]\n\n'
+        get_console().print(
+            '[warning]The following files are modified since last time image was built: [/]\n\n'
         )
         for file in modified_files:
-            console.print(f" * [bright_blue]{file}[/]")
-        console.print('\n[bright_yellow]Likely CI image needs rebuild[/]\n')
+            get_console().print(f" * [info]{file}[/]")
+        get_console().print('\n[warning]Likely CI image needs rebuild[/]\n')
         build_needed = True
     else:
-        console.print('Docker image build is not needed for CI build as no important files are changed!')
+        get_console().print(
+            'Docker image build is not needed for CI build as no important files are changed!'
+        )
     return build_needed
 
 
diff --git a/dev/breeze/src/airflow_breeze/utils/parallel.py b/dev/breeze/src/airflow_breeze/utils/parallel.py
index 565a1a52c9..211824d019 100644
--- a/dev/breeze/src/airflow_breeze/utils/parallel.py
+++ b/dev/breeze/src/airflow_breeze/utils/parallel.py
@@ -20,7 +20,7 @@ import time
 from multiprocessing.pool import ApplyResult
 from typing import List
 
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 
 
 def print_async_summary(completed_list: List[ApplyResult]) -> None:
@@ -29,14 +29,14 @@ def print_async_summary(completed_list: List[ApplyResult]) -> None:
     :param completed_list: list of completed async results.
     """
     completed_list.sort(key=lambda x: x.get()[1])
-    console.print()
+    get_console().print()
     for result in completed_list:
         return_code, info = result.get()
         if return_code != 0:
-            console.print(f"[red]NOK[/] for {info}: Return code: {return_code}.")
+            get_console().print(f"[error]NOK[/] for {info}: Return code: {return_code}.")
         else:
-            console.print(f"[green]OK [/] for {info}.")
-    console.print()
+            get_console().print(f"[success]OK [/] for {info}.")
+    get_console().print()
 
 
 def get_completed_result_list(results: List[ApplyResult]) -> List[ApplyResult]:
@@ -57,16 +57,16 @@ def check_async_run_results(results: List[ApplyResult], poll_time: float = 0.2):
         current_completed_number = len(completed_list)
         if current_completed_number != completed_number:
             completed_number = current_completed_number
-            console.print(
-                f"\n[bright_blue]Completed {completed_number} out of {total_number_of_results} "
+            get_console().print(
+                f"\n[info]Completed {completed_number} out of {total_number_of_results} "
                 f"({int(100*completed_number/total_number_of_results)}%).[/]\n"
             )
             print_async_summary(completed_list)
         time.sleep(poll_time)
         completed_list = get_completed_result_list(results)
     completed_number = len(completed_list)
-    console.print(
-        f"\n[bright_blue]Completed {completed_number} out of {total_number_of_results} "
+    get_console().print(
+        f"\n[info]Completed {completed_number} out of {total_number_of_results} "
         f"({int(100*completed_number/total_number_of_results)}%).[/]\n"
     )
     print_async_summary(completed_list)
@@ -75,7 +75,7 @@ def check_async_run_results(results: List[ApplyResult], poll_time: float = 0.2):
         if result.get()[0] != 0:
             errors = True
     if errors:
-        console.print("\n[red]There were errors when running some tasks. Quitting.[/]\n")
+        get_console().print("\n[error]There were errors when running some tasks. Quitting.[/]\n")
         sys.exit(1)
     else:
-        console.print("\n[green]All images are OK.[/]\n")
+        get_console().print("\n[success]All images are OK.[/]\n")
diff --git a/dev/breeze/src/airflow_breeze/utils/path_utils.py b/dev/breeze/src/airflow_breeze/utils/path_utils.py
index b61fb59e20..d3003305f8 100644
--- a/dev/breeze/src/airflow_breeze/utils/path_utils.py
+++ b/dev/breeze/src/airflow_breeze/utils/path_utils.py
@@ -26,7 +26,7 @@ from pathlib import Path
 from typing import Optional
 
 from airflow_breeze import NAME
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.reinstall import (
     ask_to_reinstall_breeze,
     warn_dependencies_changed,
@@ -200,9 +200,9 @@ def find_airflow_sources_root_to_operate_on() -> Path:
     """
     installation_airflow_sources = get_installation_airflow_sources()
     if installation_airflow_sources is None and not skip_upgrade_check():
-        console.print(
-            "\n[red]Breeze should only be installed with -e flag[/]\n\n"
-            "[bright_yellow]Please go to Airflow sources and run[/]\n\n"
+        get_console().print(
+            "\n[error]Breeze should only be installed with -e flag[/]\n\n"
+            "[warning]Please go to Airflow sources and run[/]\n\n"
             f"     {NAME} self-upgrade --force\n"
         )
         sys.exit(1)
diff --git a/dev/breeze/src/airflow_breeze/utils/pulll_image.py b/dev/breeze/src/airflow_breeze/utils/pulll_image.py
index a60a3b15e2..357fa1b77e 100644
--- a/dev/breeze/src/airflow_breeze/utils/pulll_image.py
+++ b/dev/breeze/src/airflow_breeze/utils/pulll_image.py
@@ -21,7 +21,7 @@ from typing import List, Tuple, Union
 
 from airflow_breeze.build_image.ci.build_ci_params import BuildCiParams
 from airflow_breeze.build_image.prod.build_prod_params import BuildProdParams
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.parallel import check_async_run_results
 from airflow_breeze.utils.run_tests import verify_an_image
 from airflow_breeze.utils.run_utils import run_command
@@ -39,8 +39,8 @@ def run_pull_in_parallel(
     extra_pytest_args: Tuple,
 ):
     """Run image pull in parallel"""
-    console.print(
-        f"\n[bright_blue]Pulling with parallelism = {parallelism} for the images: {python_version_list}:"
+    get_console().print(
+        f"\n[info]Pulling with parallelism = {parallelism} for the images: {python_version_list}:"
     )
     pool = mp.Pool(parallelism)
     poll_time = 10.0
@@ -89,8 +89,8 @@ def run_pull_image(
     :param poll_time: what's the polling time between checks if images are there
     :return: Tuple of return code and description of the image pulled
     """
-    console.print(
-        f"\n[bright_blue]Pulling {image_params.the_image_type} image of airflow python version: "
+    get_console().print(
+        f"\n[info]Pulling {image_params.the_image_type} image of airflow python version: "
         f"{image_params.python} image: {image_params.airflow_image_name_with_tag} "
         f"with wait for image: {wait_for_image}[/]\n"
     )
@@ -115,10 +115,12 @@ def run_pull_image(
                 if command_result.returncode == 0:
                     image_size = int(command_result.stdout.strip())
                     if image_size == 0:
-                        console.print("\n[red]The image size was 0 - image creation failed.[/]\n")
+                        get_console().print("\n[error]The image size was 0 - image creation failed.[/]\n")
                         return 1, f"Image Python {image_params.python}"
                 else:
-                    console.print("\n[red]There was an error pulling the size of the image. Failing.[/]\n")
+                    get_console().print(
+                        "\n[error]There was an error pulling the size of the image. Failing.[/]\n"
+                    )
                     return (
                         command_result.returncode,
                         f"Image Python {image_params.python}",
@@ -139,11 +141,13 @@ def run_pull_image(
             return command_result.returncode, f"Image Python {image_params.python}"
         if wait_for_image:
             if verbose or dry_run:
-                console.print(f"\n[bright_blue]Waiting for {poll_time} seconds.[/]\n")
+                get_console().print(f"\n[info]Waiting for {poll_time} seconds.[/]\n")
             time.sleep(poll_time)
             continue
         else:
-            console.print(f"\n[red]There was an error pulling the image {image_params.python}. Failing.[/]\n")
+            get_console().print(
+                f"\n[error]There was an error pulling the image {image_params.python}. Failing.[/]\n"
+            )
             return command_result.returncode, f"Image Python {image_params.python}"
 
 
@@ -160,7 +164,9 @@ def run_pull_and_verify_image(
         image_params, dry_run, verbose, wait_for_image, tag_as_latest, poll_time
     )
     if return_code != 0:
-        console.print(f"\n[red]Not running verification for {image_params.python} as pulling failed.[/]\n")
+        get_console().print(
+            f"\n[error]Not running verification for {image_params.python} as pulling failed.[/]\n"
+        )
     return verify_an_image(
         image_name=image_params.airflow_image_name_with_tag,
         image_type=image_params.the_image_type,
diff --git a/dev/breeze/src/airflow_breeze/utils/python_versions.py b/dev/breeze/src/airflow_breeze/utils/python_versions.py
index e3e7523454..658d2a6958 100644
--- a/dev/breeze/src/airflow_breeze/utils/python_versions.py
+++ b/dev/breeze/src/airflow_breeze/utils/python_versions.py
@@ -19,7 +19,7 @@ import sys
 from typing import List
 
 from airflow_breeze.global_constants import ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 
 
 def get_python_version_list(python_versions: str) -> List[str]:
@@ -32,10 +32,12 @@ def get_python_version_list(python_versions: str) -> List[str]:
     errors = False
     for python in python_version_list:
         if python not in ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS:
-            console.print(f"[red]The Python version {python} passed in {python_versions} is wrong.[/]")
+            get_console().print(
+                f"[error]The Python version {python} passed in {python_versions} is wrong.[/]"
+            )
             errors = True
     if errors:
-        console.print(
+        get_console().print(
             f"\nSome of the Python versions passed are not in the "
             f"list: {ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS}. Quitting.\n"
         )
diff --git a/dev/breeze/src/airflow_breeze/utils/registry.py b/dev/breeze/src/airflow_breeze/utils/registry.py
index 4eac7be01a..7c2e8a6fdb 100644
--- a/dev/breeze/src/airflow_breeze/utils/registry.py
+++ b/dev/breeze/src/airflow_breeze/utils/registry.py
@@ -20,7 +20,7 @@ from typing import Tuple, Union
 
 from airflow_breeze.build_image.ci.build_ci_params import BuildCiParams
 from airflow_breeze.build_image.prod.build_prod_params import BuildProdParams
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.run_utils import run_command
 
 
@@ -36,10 +36,10 @@ def login_to_docker_registry(
     """
     if os.environ.get("CI"):
         if len(image_params.github_token) == 0:
-            console.print("\n[bright_blue]Skip logging in to GitHub Registry. No Token available!")
+            get_console().print("\n[info]Skip logging in to GitHub Registry. No Token available!")
         elif image_params.login_to_github_registry != "true":
-            console.print(
-                "\n[bright_blue]Skip logging in to GitHub Registry.\
+            get_console().print(
+                "\n[info]Skip logging in to GitHub Registry.\
                     LOGIN_TO_GITHUB_REGISTRY is set as false"
             )
         elif len(image_params.github_token) > 0:
@@ -60,5 +60,5 @@ def login_to_docker_registry(
             )
             return command_result.returncode, "Docker login"
         else:
-            console.print('\n[bright_blue]Skip Login to GitHub Container Registry as token is missing')
+            get_console().print('\n[info]Skip Login to GitHub Container Registry as token is missing')
     return 0, "Docker login skipped"
diff --git a/dev/breeze/src/airflow_breeze/utils/reinstall.py b/dev/breeze/src/airflow_breeze/utils/reinstall.py
index 7854fc9474..ca869fd643 100644
--- a/dev/breeze/src/airflow_breeze/utils/reinstall.py
+++ b/dev/breeze/src/airflow_breeze/utils/reinstall.py
@@ -21,7 +21,7 @@ from pathlib import Path
 
 from airflow_breeze import NAME
 from airflow_breeze.utils.confirm import Answer, user_confirm
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 
 
 def reinstall_breeze(breeze_sources: Path):
@@ -32,11 +32,11 @@ def reinstall_breeze(breeze_sources: Path):
     # Note that we cannot use `pipx upgrade` here because we sometimes install
     # Breeze from different sources than originally installed (i.e. when we reinstall airflow
     # From the current directory.
-    console.print(f"\n[bright_blue]Reinstalling Breeze from {breeze_sources}\n")
+    get_console().print(f"\n[info]Reinstalling Breeze from {breeze_sources}\n")
     subprocess.check_call(["pipx", "install", "-e", str(breeze_sources), "--force"])
-    console.print(
-        f"\n[bright_blue]Breeze has been reinstalled from {breeze_sources}. Exiting now.[/]\n\n"
-        f"[bright_yellow]Please run your command again[/]\n"
+    get_console().print(
+        f"\n[info]Breeze has been reinstalled from {breeze_sources}. Exiting now.[/]\n\n"
+        f"[warning]Please run your command again[/]\n"
     )
     sys.exit(0)
 
@@ -58,30 +58,30 @@ def ask_to_reinstall_breeze(breeze_sources: Path):
 
 
 def warn_non_editable():
-    console.print(
-        "\n[red]Breeze is installed in a wrong way.[/]\n"
-        "\n[red]It should only be installed in editable mode[/]\n\n"
-        "[bright_yellow]Please go to Airflow sources and run[/]\n\n"
+    get_console().print(
+        "\n[error]Breeze is installed in a wrong way.[/]\n"
+        "\n[error]It should only be installed in editable mode[/]\n\n"
+        "[info]Please go to Airflow sources and run[/]\n\n"
         f"     {NAME} self-upgrade --force --use-current-airflow-sources\n"
     )
 
 
 def warn_different_location(installation_airflow_sources: Path, current_airflow_sources: Path):
-    console.print(
-        f"\n[bright_yellow]WARNING! Breeze was installed from "
+    get_console().print(
+        f"\n[warning]Breeze was installed from "
         f"different location![/]\n\n"
         f"Breeze installed from   : {installation_airflow_sources}\n"
         f"Current Airflow sources : {current_airflow_sources}\n\n"
-        f"[bright_yellow]This might cause various problems!![/]\n\n"
+        f"[warning]This might cause various problems!![/]\n\n"
         f"If you experience problems - reinstall Breeze with:\n\n"
         f"    {NAME} self-upgrade --force --use-current-airflow-sources\n\n"
     )
 
 
 def warn_dependencies_changed():
-    console.print(
-        f"\n[bright_yellow]WARNING! Breeze dependencies changed since the installation![/]\n\n"
-        f"[bright_yellow]This might cause various problems!![/]\n\n"
+    get_console().print(
+        f"\n[warning]Breeze dependencies changed since the installation![/]\n\n"
+        f"[warning]This might cause various problems!![/]\n\n"
         f"If you experience problems - reinstall Breeze with:\n\n"
         f"    {NAME} self-upgrade --force\n\n"
     )
diff --git a/dev/breeze/src/airflow_breeze/utils/run_tests.py b/dev/breeze/src/airflow_breeze/utils/run_tests.py
index b8b0a2276f..63c507afe4 100644
--- a/dev/breeze/src/airflow_breeze/utils/run_tests.py
+++ b/dev/breeze/src/airflow_breeze/utils/run_tests.py
@@ -20,7 +20,7 @@ import sys
 from subprocess import DEVNULL
 from typing import Tuple
 
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.path_utils import AIRFLOW_SOURCES_ROOT
 from airflow_breeze.utils.run_utils import run_command
 
@@ -32,7 +32,9 @@ def verify_an_image(
         ["docker", "inspect", image_name], dry_run=dry_run, verbose=verbose, check=False, stdout=DEVNULL
     )
     if command_result.returncode != 0:
-        console.print(f"[red]Error when inspecting {image_type} image: {command_result.returncode}[/]")
+        get_console().print(
+            f"[error]Error when inspecting {image_type} image: {command_result.returncode}[/]"
+        )
         return command_result.returncode, f"Testing {image_type} python {image_name}"
     pytest_args = ("-n", "auto", "--color=yes")
     if image_type == 'PROD':
@@ -58,7 +60,7 @@ def run_docker_compose_tests(
         ["docker", "inspect", image_name], dry_run=dry_run, verbose=verbose, check=False, stdout=DEVNULL
     )
     if command_result.returncode != 0:
-        console.print(f"[red]Error when inspecting PROD image: {command_result.returncode}[/]")
+        get_console().print(f"[error]Error when inspecting PROD image: {command_result.returncode}[/]")
         return command_result.returncode, f"Testing docker-compose python with {image_name}"
     pytest_args = ("-n", "auto", "--color=yes")
     test_path = AIRFLOW_SOURCES_ROOT / "docker_tests" / "test_docker_compose_quick_start.py"
diff --git a/dev/breeze/src/airflow_breeze/utils/run_utils.py b/dev/breeze/src/airflow_breeze/utils/run_utils.py
index 6ef639862a..cc2d679584 100644
--- a/dev/breeze/src/airflow_breeze/utils/run_utils.py
+++ b/dev/breeze/src/airflow_breeze/utils/run_utils.py
@@ -26,7 +26,7 @@ from functools import lru_cache
 from pathlib import Path
 from typing import List, Mapping, Optional, Union
 
-from airflow_breeze.utils.console import console
+from airflow_breeze.utils.console import get_console
 from airflow_breeze.utils.path_utils import AIRFLOW_SOURCES_ROOT
 
 
@@ -70,9 +70,9 @@ def run_command(
         env_to_print = ' '.join(f'{key}="{val}"' for (key, val) in env.items()) if env else ''
         if env_to_print:
             env_to_print += ' '
-        console.print(f"\n[bright_blue]Working directory {workdir} [/]\n")
+        get_console().print(f"\n[info]Working directory {workdir} [/]\n")
         # Soft wrap allows to copy&paste and run resulting output as it has no hard EOL
-        console.print(f"\n[bright_blue]{env_to_print}{command_to_print}[/]\n", soft_wrap=True)
+        get_console().print(f"\n[info]{env_to_print}{command_to_print}[/]\n", soft_wrap=True)
         if dry_run:
             return subprocess.CompletedProcess(cmd, returncode=0)
     try:
@@ -83,13 +83,21 @@ def run_command(
     except subprocess.CalledProcessError as ex:
         if not no_output_dump_on_exception:
             if ex.stdout:
-                console.print("[blue]========================= OUTPUT start ============================[/]")
-                console.print(ex.stdout)
-                console.print("[blue]========================= OUTPUT end ==============================[/]")
+                get_console().print(
+                    "[info]========================= OUTPUT start ============================[/]"
+                )
+                get_console().print(ex.stdout)
+                get_console().print(
+                    "[info]========================= OUTPUT end ==============================[/]"
+                )
             if ex.stderr:
-                console.print("[red]========================= STDERR start ============================[/]")
-                console.print(ex.stderr)
-                console.print("[red]========================= STDERR end ==============================[/]")
+                get_console().print(
+                    "[error]========================= STDERR start ============================[/]"
+                )
+                get_console().print(ex.stderr)
+                get_console().print(
+                    "[error]========================= STDERR end ==============================[/]"
+                )
         if check:
             raise
         return ex
@@ -108,7 +116,7 @@ def assert_pre_commit_installed(verbose: bool):
     min_pre_commit_version = pre_commit_config["minimum_pre_commit_version"]
 
     python_executable = sys.executable
-    console.print(f"[bright_blue]Checking pre-commit installed for {python_executable}[/]")
+    get_console().print(f"[info]Checking pre-commit installed for {python_executable}[/]")
     command_result = run_command(
         [python_executable, "-m", "pre_commit", "--version"],
         verbose=verbose,
@@ -120,25 +128,24 @@ def assert_pre_commit_installed(verbose: bool):
         if command_result.stdout:
             pre_commit_version = command_result.stdout.split(" ")[-1].strip()
             if StrictVersion(pre_commit_version) >= StrictVersion(min_pre_commit_version):
-                console.print(
-                    f"\n[green]Package pre_commit is installed. "
+                get_console().print(
+                    f"\n[success]Package pre_commit is installed. "
                     f"Good version {pre_commit_version} (>= {min_pre_commit_version})[/]\n"
                 )
             else:
-                console.print(
-                    f"\n[red]Package name pre_commit version is wrong. It should be"
+                get_console().print(
+                    f"\n[error]Package name pre_commit version is wrong. It should be"
                     f"aat least {min_pre_commit_version} and is {pre_commit_version}.[/]\n\n"
                 )
                 sys.exit(1)
         else:
-            console.print(
-                "\n[bright_yellow]Could not determine version of pre-commit. "
-                "You might need to update it![/]\n"
+            get_console().print(
+                "\n[warning]Could not determine version of pre-commit. " "You might need to update it![/]\n"
             )
     else:
-        console.print("\n[red]Error checking for pre-commit-installation:[/]\n")
-        console.print(command_result.stderr)
-        console.print("\nMake sure to run:\n      breeze self-upgrade\n\n")
+        get_console().print("\n[error]Error checking for pre-commit-installation:[/]\n")
+        get_console().print(command_result.stderr)
+        get_console().print("\nMake sure to run:\n      breeze self-upgrade\n\n")
         sys.exit(1)
 
 
@@ -164,8 +171,8 @@ def get_filesystem_type(filepath):
 
 def instruct_build_image(python: str):
     """Print instructions to the user that they should build the image"""
-    console.print(f'[bright_yellow]\nThe CI image for ' f'python version {python} may be outdated[/]\n')
-    print(f"\n[yellow]Please run at the earliest convenience:[/]\n\nbreeze build-image --python {python}\n\n")
+    get_console().print(f'[warning]\nThe CI image for ' f'python version {python} may be outdated[/]\n')
+    print(f"\n[info]Please run at the earliest convenience:[/]\n\nbreeze build-image --python {python}\n\n")
 
 
 @contextlib.contextmanager
@@ -206,7 +213,7 @@ def change_directory_permission(directory_to_fix: Path):
 @working_directory(AIRFLOW_SOURCES_ROOT)
 def fix_group_permissions():
     """Fixes permissions of all the files and directories that have group-write access."""
-    console.print("[bright_blue]Fixing group permissions[/]")
+    get_console().print("[info]Fixing group permissions[/]")
     files_to_fix_result = run_command(['git', 'ls-files', './'], capture_output=True, text=True)
     if files_to_fix_result.returncode == 0:
         files_to_fix = files_to_fix_result.stdout.strip().split('\n')
@@ -288,11 +295,11 @@ def prepare_build_command(prepare_buildx_cache: bool, verbose: bool) -> List[str
             build_command_param.extend(["buildx", "build", "--builder", "default", "--progress=tty"])
     else:
         if prepare_buildx_cache:
-            console.print(
-                '\n[red] Buildx cli plugin is not available and you need it to prepare buildx cache. \n'
+            get_console().print(
+                '\n[error] Buildx cli plugin is not available and you need it to prepare buildx cache. \n'
             )
-            console.print(
-                '[red] Please install it following https://docs.docker.com/buildx/working-with-buildx/ \n'
+            get_console().print(
+                '[error] Please install it following https://docs.docker.com/buildx/working-with-buildx/ \n'
             )
             sys.exit(1)
         build_command_param.append("build")
diff --git a/dev/breeze/src/airflow_breeze/utils/visuals.py b/dev/breeze/src/airflow_breeze/utils/visuals.py
index effbdd27ae..b5db534514 100644
--- a/dev/breeze/src/airflow_breeze/utils/visuals.py
+++ b/dev/breeze/src/airflow_breeze/utils/visuals.py
@@ -74,9 +74,9 @@ ASCIIART = """
 """
 CHEATSHEET = f"""
 
-                       [bold][bright_blue]Airflow Breeze Cheatsheet[/][/]
+                       [bold][info]Airflow Breeze Cheatsheet[/][/]
 
-    [bright_blue]* Port forwarding:[/]
+    [info]* Port forwarding:[/]
 
         Ports are forwarded to the running docker containers for webserver and database
           * {SSH_PORT} -> forwarded to Airflow ssh server -> airflow:22
@@ -98,7 +98,7 @@ CHEATSHEET = f"""
                        Airflow123
           * Redis:     redis://127.0.0.1:{REDIS_HOST_PORT}/0
 
-    [bright_blue]* How can I add my stuff in Breeze:[/]
+    [info]* How can I add my stuff in Breeze:[/]
 
         * Your dags for webserver and scheduler are read from `/files/dags` directory
           which is mounted from folder in Airflow sources:
@@ -115,7 +115,7 @@ CHEATSHEET = f"""
           `{AIRFLOW_SOURCES_ROOT}/files` folder
           and they will be visible in `/files/` folder inside the container
 
-        [bright_blue]* Other options[/]
+        [info]* Other options[/]
 
         Check out `--help` for ./breeze commands. It will show you other options, such as running
         integration or starting complete Airflow using `start-airflow` command as well as ways
diff --git a/dev/breeze/tests/test_docker_command_utils.py b/dev/breeze/tests/test_docker_command_utils.py
index 8d168844b9..5be489c65e 100644
--- a/dev/breeze/tests/test_docker_command_utils.py
+++ b/dev/breeze/tests/test_docker_command_utils.py
@@ -23,8 +23,10 @@ from airflow_breeze.utils.docker_command_utils import check_docker_compose_versi
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.check_docker_permission_denied')
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_version_unknown(mock_console, mock_run_command, mock_check_docker_permission_denied):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_version_unknown(
+    mock_get_console, mock_run_command, mock_check_docker_permission_denied
+):
     mock_check_docker_permission_denied.return_value = False
     check_docker_version(verbose=True)
     expected_run_command_calls = [
@@ -38,18 +40,20 @@ def test_check_docker_version_unknown(mock_console, mock_run_command, mock_check
         ),
     ]
     mock_run_command.assert_has_calls(expected_run_command_calls)
-    mock_console.print.assert_called_with(
+    mock_get_console.return_value.print.assert_called_with(
         """
-[yellow]Your version of docker is unknown. If the scripts fail, please make sure to[/]
-[yellow]install docker at least: 20.10.0 version.[/]
+[warning]Your version of docker is unknown. If the scripts fail, please make sure to[/]
+[warning]install docker at least: 20.10.0 version.[/]
 """
     )
 
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.check_docker_permission_denied')
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_version_too_low(mock_console, mock_run_command, mock_check_docker_permission_denied):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_version_too_low(
+    mock_get_console, mock_run_command, mock_check_docker_permission_denied
+):
     mock_check_docker_permission_denied.return_value = False
     mock_run_command.return_value.returncode = 0
     mock_run_command.return_value.stdout = "0.9"
@@ -63,17 +67,17 @@ def test_check_docker_version_too_low(mock_console, mock_run_command, mock_check
         text=True,
         check=False,
     )
-    mock_console.print.assert_called_with(
+    mock_get_console.return_value.print.assert_called_with(
         """
-[yellow]Your version of docker is too old:0.9. Please upgrade to at least 20.10.0[/]
+[warning]Your version of docker is too old:0.9.\nPlease upgrade to at least 20.10.0[/]
 """
     )
 
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.check_docker_permission_denied')
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_version_ok(mock_console, mock_run_command, mock_check_docker_permission_denied):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_version_ok(mock_get_console, mock_run_command, mock_check_docker_permission_denied):
     mock_check_docker_permission_denied.return_value = False
     mock_run_command.return_value.returncode = 0
     mock_run_command.return_value.stdout = "20.10.0"
@@ -87,13 +91,13 @@ def test_check_docker_version_ok(mock_console, mock_run_command, mock_check_dock
         text=True,
         check=False,
     )
-    mock_console.print.assert_called_with("[green]Good version of Docker: 20.10.0.[/]")
+    mock_get_console.return_value.print.assert_called_with("[success]Good version of Docker: 20.10.0.[/]")
 
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.check_docker_permission_denied')
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_version_higher(mock_console, mock_run_command, mock_check_docker_permission_denied):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_version_higher(mock_get_console, mock_run_command, mock_check_docker_permission_denied):
     mock_check_docker_permission_denied.return_value = False
     mock_run_command.return_value.returncode = 0
     mock_run_command.return_value.stdout = "21.10.0"
@@ -107,12 +111,12 @@ def test_check_docker_version_higher(mock_console, mock_run_command, mock_check_
         text=True,
         check=False,
     )
-    mock_console.print.assert_called_with("[green]Good version of Docker: 21.10.0.[/]")
+    mock_get_console.return_value.print.assert_called_with("[success]Good version of Docker: 21.10.0.[/]")
 
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_compose_version_unknown(mock_console, mock_run_command):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_compose_version_unknown(mock_get_console, mock_run_command):
     check_docker_compose_version(verbose=True)
     expected_run_command_calls = [
         call(
@@ -124,17 +128,17 @@ def test_check_docker_compose_version_unknown(mock_console, mock_run_command):
         ),
     ]
     mock_run_command.assert_has_calls(expected_run_command_calls)
-    mock_console.print.assert_called_with(
+    mock_get_console.return_value.print.assert_called_with(
         """
-[yellow]Unknown docker-compose version. At least 1.29 is needed![/]
-[yellow]If Breeze fails upgrade to latest available docker-compose version.[/]
+[warning]Unknown docker-compose version. At least 1.29 is needed![/]
+[warning]If Breeze fails upgrade to latest available docker-compose version.[/]
 """
     )
 
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_compose_version_low(mock_console, mock_run_command):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_compose_version_low(mock_get_console, mock_run_command):
     mock_run_command.return_value.returncode = 0
     mock_run_command.return_value.stdout = "1.28.5"
     check_docker_compose_version(verbose=True)
@@ -148,7 +152,7 @@ def test_check_docker_compose_version_low(mock_console, mock_run_command):
     expected_print_calls = [
         call(
             """
-[yellow]You have too old version of docker-compose: 1.28.5! At least 1.29 is needed! Please upgrade!
+[warning]You have too old version of docker-compose: 1.28.5! At least 1.29 is needed! Please upgrade!
 """
         ),
         call(
@@ -158,12 +162,12 @@ Make sure docker-compose you install is first on the PATH variable of yours.
 """
         ),
     ]
-    mock_console.print.assert_has_calls(expected_print_calls)
+    mock_get_console.return_value.print.assert_has_calls(expected_print_calls)
 
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_compose_version_ok(mock_console, mock_run_command):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_compose_version_ok(mock_get_console, mock_run_command):
     mock_run_command.return_value.returncode = 0
     mock_run_command.return_value.stdout = "1.29.0"
     check_docker_compose_version(verbose=True)
@@ -174,12 +178,14 @@ def test_check_docker_compose_version_ok(mock_console, mock_run_command):
         capture_output=True,
         text=True,
     )
-    mock_console.print.assert_called_with("[green]Good version of docker-compose: 1.29.0[/]")
+    mock_get_console.return_value.print.assert_called_with(
+        "[success]Good version of docker-compose: 1.29.0[/]"
+    )
 
 
 @mock.patch('airflow_breeze.utils.docker_command_utils.run_command')
-@mock.patch('airflow_breeze.utils.docker_command_utils.console')
-def test_check_docker_compose_version_higher(mock_console, mock_run_command):
+@mock.patch('airflow_breeze.utils.docker_command_utils.get_console')
+def test_check_docker_compose_version_higher(mock_get_console, mock_run_command):
     mock_run_command.return_value.returncode = 0
     mock_run_command.return_value.stdout = "1.29.2"
     check_docker_compose_version(verbose=True)
@@ -190,4 +196,6 @@ def test_check_docker_compose_version_higher(mock_console, mock_run_command):
         capture_output=True,
         text=True,
     )
-    mock_console.print.assert_called_with("[green]Good version of docker-compose: 1.29.2[/]")
+    mock_get_console.return_value.print.assert_called_with(
+        "[success]Good version of docker-compose: 1.29.2[/]"
+    )
diff --git a/dev/provider_packages/prepare_provider_packages.py b/dev/provider_packages/prepare_provider_packages.py
index 1a46c7292d..319f4447fd 100755
--- a/dev/provider_packages/prepare_provider_packages.py
+++ b/dev/provider_packages/prepare_provider_packages.py
@@ -171,7 +171,7 @@ def with_group(title):
     https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#grouping-log-lines
     """
     if os.environ.get('GITHUB_ACTIONS', 'false') != "true":
-        console.print("[blue]" + "#" * 10 + ' ' + title + ' ' + "#" * 10 + "[/]")
+        console.print("[info]" + "#" * 10 + ' ' + title + ' ' + "#" * 10 + "[/]")
         yield
         return
     console.print(f"::group::{title}")
diff --git a/docs/build_docs.py b/docs/build_docs.py
index f2361f00ab..d7edad1cad 100755
--- a/docs/build_docs.py
+++ b/docs/build_docs.py
@@ -69,21 +69,21 @@ def _promote_new_flags():
     console.print()
     if ON_GITHUB_ACTIONS:
         console.print("You can quickly build documentation locally with just one command.")
-        console.print("    [blue]breeze build-docs[/]")
+        console.print("    [info]breeze build-docs[/]")
         console.print()
         console.print("[yellow]Still too slow?[/]")
         console.print()
     console.print("You can only build one documentation package:")
-    console.print("    [blue]breeze build-docs --package-filter <PACKAGE-NAME>[/]")
+    console.print("    [info]breeze build-docs --package-filter <PACKAGE-NAME>[/]")
     console.print()
     console.print("This usually takes from [yellow]20 seconds[/] to [yellow]2 minutes[/].")
     console.print()
     console.print("You can also use other extra flags to iterate faster:")
-    console.print("   [blue]--docs-only       - Only build documentation[/]")
-    console.print("   [blue]--spellcheck-only - Only perform spellchecking[/]")
+    console.print("   [info]--docs-only       - Only build documentation[/]")
+    console.print("   [info]--spellcheck-only - Only perform spellchecking[/]")
     console.print()
     console.print("For more info:")
-    console.print("   [blue]breeze build-docs --help[/]")
+    console.print("   [info]breeze build-docs --help[/]")
     console.print()
 
 
@@ -177,7 +177,7 @@ def perform_docs_build_for_single_package(build_specification: BuildSpecificatio
     builder = AirflowDocsBuilder(
         package_name=build_specification.package_name, for_production=build_specification.for_production
     )
-    console.print(f"[blue]{build_specification.package_name:60}:[/] Building documentation")
+    console.print(f"[info]{build_specification.package_name:60}:[/] Building documentation")
     result = BuildDocsResult(
         package_name=build_specification.package_name,
         errors=builder.build_sphinx_docs(
@@ -193,7 +193,7 @@ def perform_spell_check_for_single_package(build_specification: BuildSpecificati
     builder = AirflowDocsBuilder(
         package_name=build_specification.package_name, for_production=build_specification.for_production
     )
-    console.print(f"[blue]{build_specification.package_name:60}:[/] Checking spelling started")
+    console.print(f"[info]{build_specification.package_name:60}:[/] Checking spelling started")
     result = SpellCheckResult(
         package_name=build_specification.package_name,
         errors=builder.check_spelling(
@@ -201,7 +201,7 @@ def perform_spell_check_for_single_package(build_specification: BuildSpecificati
         ),
         log_file_name=builder.log_spelling_filename,
     )
-    console.print(f"[blue]{build_specification.package_name:60}:[/] Checking spelling completed")
+    console.print(f"[info]{build_specification.package_name:60}:[/] Checking spelling completed")
     return result
 
 
@@ -218,7 +218,7 @@ def build_docs_for_packages(
     all_spelling_errors: Dict[str, List[SpellingError]] = defaultdict(list)
     with with_group("Cleaning documentation files"):
         for package_name in current_packages:
-            console.print(f"[blue]{package_name:60}:[/] Cleaning files")
+            console.print(f"[info]{package_name:60}:[/] Cleaning files")
             builder = AirflowDocsBuilder(package_name=package_name, for_production=for_production)
             builder.clean_files()
     if jobs > 1:
@@ -315,11 +315,11 @@ def print_build_output(result: BuildDocsResult):
     """Prints output of docs build job."""
     with with_group(f"{TEXT_RED}Output for documentation build {result.package_name}{TEXT_RESET}"):
         console.print()
-        console.print(f"[blue]{result.package_name:60}: " + "#" * 80)
+        console.print(f"[info]{result.package_name:60}: " + "#" * 80)
         with open(result.log_file_name) as output:
             for line in output.read().splitlines():
                 console.print(f"{result.package_name:60} {line}")
-        console.print(f"[blue]{result.package_name:60}: " + "#" * 80)
+        console.print(f"[info]{result.package_name:60}: " + "#" * 80)
 
 
 def run_docs_build_in_parallel(
@@ -333,7 +333,7 @@ def run_docs_build_in_parallel(
     doc_build_specifications: List[BuildSpecification] = []
     with with_group("Scheduling documentation to build"):
         for package_name in current_packages:
-            console.print(f"[blue]{package_name:60}:[/] Scheduling documentation to build")
+            console.print(f"[info]{package_name:60}:[/] Scheduling documentation to build")
             doc_build_specifications.append(
                 BuildSpecification(
                     package_name=package_name,
@@ -354,11 +354,11 @@ def print_spelling_output(result: SpellCheckResult):
     """Prints output of spell check job."""
     with with_group(f"{TEXT_RED}Output for spelling check: {result.package_name}{TEXT_RESET}"):
         console.print()
-        console.print(f"[blue]{result.package_name:60}: " + "#" * 80)
+        console.print(f"[info]{result.package_name:60}: " + "#" * 80)
         with open(result.log_file_name) as output:
             for line in output.read().splitlines():
                 console.print(f"{result.package_name:60} {line}")
-        console.print(f"[blue]{result.package_name:60}: " + "#" * 80)
+        console.print(f"[info]{result.package_name:60}: " + "#" * 80)
         console.print()
 
 
@@ -373,7 +373,7 @@ def run_spell_check_in_parallel(
     spell_check_specifications: List[BuildSpecification] = []
     with with_group("Scheduling spell checking of documentation"):
         for package_name in current_packages:
-            console.print(f"[blue]{package_name:60}:[/] Scheduling spellchecking")
+            console.print(f"[info]{package_name:60}:[/] Scheduling spellchecking")
             spell_check_specifications.append(
                 BuildSpecification(package_name=package_name, for_production=for_production, verbose=verbose)
             )
@@ -393,7 +393,7 @@ def display_packages_summary(
     packages_names = {*build_errors.keys(), *spelling_errors.keys()}
     tabular_data = [
         {
-            "Package name": f"[blue]{package_name}[/]",
+            "Package name": f"[info]{package_name}[/]",
             "Count of doc build errors": len(build_errors.get(package_name, [])),
             "Count of spelling errors": len(spelling_errors.get(package_name, [])),
         }
diff --git a/docs/exts/docs_build/docs_builder.py b/docs/exts/docs_build/docs_builder.py
index ad343b46cf..cc65f3f170 100644
--- a/docs/exts/docs_build/docs_builder.py
+++ b/docs/exts/docs_build/docs_builder.py
@@ -157,10 +157,10 @@ class AirflowDocsBuilder:
             env['AIRFLOW_FOR_PRODUCTION'] = 'true'
         if verbose:
             console.print(
-                f"[blue]{self.package_name:60}:[/] Executing cmd: ",
+                f"[info]{self.package_name:60}:[/] Executing cmd: ",
                 " ".join(shlex.quote(c) for c in build_cmd),
             )
-            console.print(f"[blue]{self.package_name:60}:[/] The output is hidden until an error occurs.")
+            console.print(f"[info]{self.package_name:60}:[/] The output is hidden until an error occurs.")
         with open(self.log_spelling_filename, "wt") as output:
             completed_proc = run(
                 build_cmd,
@@ -189,15 +189,15 @@ class AirflowDocsBuilder:
                     warning_text += spelling_file.read()
 
             spelling_errors.extend(parse_spelling_warnings(warning_text, self._src_dir))
-            console.print(f"[blue]{self.package_name:60}:[/] [red]Finished spell-checking with errors[/]")
+            console.print(f"[info]{self.package_name:60}:[/] [red]Finished spell-checking with errors[/]")
         else:
             if spelling_errors:
                 console.print(
-                    f"[blue]{self.package_name:60}:[/] [yellow]Finished spell-checking with warnings[/]"
+                    f"[info]{self.package_name:60}:[/] [yellow]Finished spell-checking with warnings[/]"
                 )
             else:
                 console.print(
-                    f"[blue]{self.package_name:60}:[/] [green]Finished spell-checking successfully[/]"
+                    f"[info]{self.package_name:60}:[/] [green]Finished spell-checking successfully[/]"
                 )
         return spelling_errors
 
@@ -232,12 +232,12 @@ class AirflowDocsBuilder:
             env['AIRFLOW_FOR_PRODUCTION'] = 'true'
         if verbose:
             console.print(
-                f"[blue]{self.package_name:60}:[/] Executing cmd: ",
+                f"[info]{self.package_name:60}:[/] Executing cmd: ",
                 " ".join(shlex.quote(c) for c in build_cmd),
             )
         else:
             console.print(
-                f"[blue]{self.package_name:60}:[/] Running sphinx. "
+                f"[info]{self.package_name:60}:[/] Running sphinx. "
                 f"The output is hidden until an error occurs."
             )
         with open(self.log_build_filename, "wt") as output:
@@ -264,9 +264,9 @@ class AirflowDocsBuilder:
             warning_text = re.sub(r"\x1B[@-_][0-?]*[ -/]*[@-~]", "", warning_text)
             build_errors.extend(parse_sphinx_warnings(warning_text, self._src_dir))
         if build_errors:
-            console.print(f"[blue]{self.package_name:60}:[/] [red]Finished docs building with errors[/]")
+            console.print(f"[info]{self.package_name:60}:[/] [red]Finished docs building with errors[/]")
         else:
-            console.print(f"[blue]{self.package_name:60}:[/] [green]Finished docs building successfully[/]")
+            console.print(f"[info]{self.package_name:60}:[/] [green]Finished docs building successfully[/]")
         return build_errors
 
     def publish(self, override_versioned: bool):
diff --git a/docs/exts/docs_build/errors.py b/docs/exts/docs_build/errors.py
index b654fc6621..d1dc48d7cd 100644
--- a/docs/exts/docs_build/errors.py
+++ b/docs/exts/docs_build/errors.py
@@ -62,9 +62,9 @@ def display_errors_summary(build_errors: Dict[str, List[DocBuildError]]) -> None
     console.print()
     for package_name, errors in build_errors.items():
         if package_name:
-            console.print("=" * 30 + f" [blue]{package_name}[/] " + "=" * 30)
+            console.print("=" * 30 + f" [info]{package_name}[/] " + "=" * 30)
         else:
-            console.print("=" * 30, " [blue]General[/] ", "=" * 30)
+            console.print("=" * 30, " [info]General[/] ", "=" * 30)
         for warning_no, error in enumerate(sorted(errors), 1):
             console.print("-" * 30, f"[red]Error {warning_no:3}[/]", "-" * 20)
             console.print(error.message)
diff --git a/docs/exts/docs_build/spelling_checks.py b/docs/exts/docs_build/spelling_checks.py
index 62d4baeccb..5106d80e21 100644
--- a/docs/exts/docs_build/spelling_checks.py
+++ b/docs/exts/docs_build/spelling_checks.py
@@ -142,9 +142,9 @@ def display_spelling_error_summary(spelling_errors: Dict[str, List[SpellingError
 
     for package_name, errors in sorted(spelling_errors.items()):
         if package_name:
-            console.print("=" * 30, f" [blue]{package_name}[/] ", "=" * 30)
+            console.print("=" * 30, f" [info]{package_name}[/] ", "=" * 30)
         else:
-            console.print("=" * 30, " [blue]General[/] ", "=" * 30)
+            console.print("=" * 30, " [info]General[/] ", "=" * 30)
 
         for warning_no, error in enumerate(sorted(errors), 1):
             console.print("-" * 30, f"Error {warning_no:3}", "-" * 30)
diff --git a/images/breeze/output-config.svg b/images/breeze/output-config.svg
index 5d20779549..35d0962e15 100644
--- a/images/breeze/output-config.svg
+++ b/images/breeze/output-config.svg
@@ -1,4 +1,4 @@
-<svg width="1720.0" height="802" viewBox="0 0 1720.0 802"
+<svg width="1720.0" height="824" viewBox="0 0 1720.0 824"
      xmlns="http://www.w3.org/2000/svg">
     <style>
         @font-face {
@@ -128,6 +128,7 @@
 <div><span class="r4">│</span><span class="r1">                                       </span><span class="r4">[default: sqlite]       </span><span class="r1"> </span><span class="r1">                                                    </span><span class="r1">  </span><span class="r4">│</span></div>
 <div><span class="r4">│</span><span class="r1">  </span><span class="r5">--cheatsheet</span><span class="r1">/</span><span class="r5">--no-cheatsheet</span><span class="r1">  </span><span class="r6">-C</span><span class="r1">/</span><span class="r6">-c</span><span class="r1">  </span><span class="r1">Enable/disable cheatsheet.                                                   </span><span class="r1">  </span><span class="r4">│</span></div>
 <div><span class="r4">│</span><span class="r1">  </span><span class="r5">--asciiart</span><span class="r1">/</span><span class="r5">--no-asciiart</span><span class="r1">      </span><span class="r6">-A</span><span class="r1">/</span><span class="r6">-a</span><span class="r1">  </span><span class="r1">Enable/disable ASCIIart.                                                     </span><span class="r1">  </span><span class="r4">│</span></div>
+<div><span class="r4">│</span><span class="r1">  </span><span class="r5">--colour</span><span class="r1">/</span><span class="r5">--no-colour</span><span class="r1">          </span><span class="r6">-B</span><span class="r1">/</span><span class="r6">-b</span><span class="r1">  </span><span class="r1">Enable/disable Colour mode (useful for colour blind-friendly communication). </span><span class="r1">  </span><span class="r4">│</span></div>
 <div><span class="r4">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span></div>
 <div><span class="r4">╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮</span></div>
 <div><span class="r4">│</span><span class="r1">  </span><span class="r5">--postgres-version</span><span class="r1">  </span><span class="r6">-P</span><span class="r1">  </span><span class="r1">Version of Postgres used.</span><span class="r1"> </span><span class="r7">(&gt;10&lt; | 11 | 12 | 13)</span><span class="r1"> </span><span class="r4">[default: 10]</span><span class="r1">                             </span><span class="r1">  </span><span class="r4">│</span></div>
diff --git a/scripts/ci/pre_commit/pre_commit_check_order_setup.py b/scripts/ci/pre_commit/pre_commit_check_order_setup.py
index 82c5f53ba8..8e4ac563f6 100755
--- a/scripts/ci/pre_commit/pre_commit_check_order_setup.py
+++ b/scripts/ci/pre_commit/pre_commit_check_order_setup.py
@@ -65,7 +65,7 @@ def check_main_dependent_group(setup_contents: str) -> None:
     Test for an order of dependencies groups between mark
     '# Start dependencies group' and '# End dependencies group' in setup.py
     """
-    print("[blue]Checking main dependency group[/]")
+    print("[info]Checking main dependency group[/]")
     pattern_main_dependent_group = re.compile(
         '# Start dependencies group\n(.*)# End dependencies group', re.DOTALL
     )
@@ -86,7 +86,7 @@ def check_sub_dependent_group(group_name: str) -> None:
     Test for an order of each dependencies groups declare like
     `^dependent_group_name = [.*?]\n` in setup.py
     """
-    print(f"[blue]Checking dependency group {group_name}[/]")
+    print(f"[info]Checking dependency group {group_name}[/]")
     _check_list_sorted(getattr(setup, group_name), f"Order of dependency group: {group_name}")
 
 
@@ -99,13 +99,13 @@ def check_alias_dependent_group(setup_context: str) -> None:
     dependents = pattern.findall(setup_context)
 
     for dependent in dependents:
-        print(f"[blue]Checking alias-dependent group {dependent}[/]")
+        print(f"[info]Checking alias-dependent group {dependent}[/]")
         src = dependent.split(' + ')
         _check_list_sorted(src, f"Order of alias dependencies group: {dependent}")
 
 
 def check_variable_order(var_name: str) -> None:
-    print(f"[blue]Checking {var_name}[/]")
+    print(f"[info]Checking {var_name}[/]")
 
     var = getattr(setup, var_name)
 
@@ -129,7 +129,7 @@ def check_install_and_setup_requires() -> None:
     pattern_dependent_version = re.compile('[~|><=;].*')
 
     for key in ('install_requires', 'setup_requires'):
-        print(f"[blue]Checking setup.cfg group {key}[/]")
+        print(f"[info]Checking setup.cfg group {key}[/]")
         deps = config['options'][key]
         dists = [pattern_dependent_version.sub('', p) for p in deps]
         _check_list_sorted(dists, f"Order of dependencies in do_setup section: {key}")