From e504d226ce3f7166e29774f3d77349ab74b93d08 Mon Sep 17 00:00:00 2001 From: Sergi Blanch Torne Date: Tue, 6 May 2025 11:23:02 +0200 Subject: [PATCH] bin/ci: crnm: format in columns when listing When we are printing a long list, and it needs more than one line, it gets hard to review the content. This is an idea to group the elements to be printed in columns to make it easier to identify individual elements in the output. Signed-off-by: Sergi Blanch Torne Part-of: --- bin/ci/ci_run_n_monitor.py | 19 +++++++++---------- bin/ci/gitlab_gql.py | 39 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/bin/ci/ci_run_n_monitor.py b/bin/ci/ci_run_n_monitor.py index a131b383089..e2c07969f7f 100755 --- a/bin/ci/ci_run_n_monitor.py +++ b/bin/ci/ci_run_n_monitor.py @@ -13,6 +13,7 @@ and show the job(s) logs. """ import argparse +import os import re import sys import time @@ -37,7 +38,7 @@ from gitlab_common import ( read_token, wait_for_pipeline, ) -from gitlab_gql import GitlabGQL, create_job_needs_dag, filter_dag, print_dag +from gitlab_gql import GitlabGQL, create_job_needs_dag, filter_dag, print_dag, print_formatted_list if TYPE_CHECKING: from gitlab_gql import Dag @@ -494,16 +495,14 @@ def print_detected_jobs( target_jobs: Iterable[str], ) -> None: def print_job_set(color: str, kind: str, job_set: Iterable[str]): - print( - color + f"Running {len(job_set)} {kind} jobs: ", - "\n\t", - ", ".join(sorted(job_set)), - Fore.RESET, - "\n", - ) + job_list = list(job_set) + print(color + f"Running {len(job_list)} {kind} jobs:") + print_formatted_list(job_list, indentation=8) + print(Style.RESET_ALL) - print(Fore.YELLOW + "Detected target job and its dependencies:", "\n") - print_dag(target_dep_dag) + print(Fore.YELLOW + "Detected target job and its dependencies:") + print_dag(target_dep_dag, indentation=8) + print(Style.RESET_ALL) print_job_set(Fore.MAGENTA, "dependency", dependency_jobs) print_job_set(Fore.BLUE, "target", target_jobs) diff --git a/bin/ci/gitlab_gql.py b/bin/ci/gitlab_gql.py index 144e3c31d7b..25fc7ba7873 100755 --- a/bin/ci/gitlab_gql.py +++ b/bin/ci/gitlab_gql.py @@ -3,12 +3,14 @@ import logging import re +import sys import traceback from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace from collections import OrderedDict from copy import deepcopy from dataclasses import dataclass, field from itertools import accumulate +from os import get_terminal_size from pathlib import Path from subprocess import check_output from textwrap import dedent @@ -21,6 +23,8 @@ from gql import Client, gql from gql.transport.requests import RequestsHTTPTransport from graphql import DocumentNode +DEFAULT_TERMINAL_SIZE: int = 80 # columns + class DagNode(TypedDict): needs: set[str] @@ -340,9 +344,40 @@ def filter_dag( return filtered_jobs -def print_dag(dag: Dag) -> None: +def print_dag(dag: Dag, indentation: int = 0) -> None: for job, data in sorted(dag.items()): - print(f"{job}:\n\t{' '.join(data['needs'])}\n") + print(f"{' '*indentation}{job}:") + print_formatted_list(list(data['needs']), indentation=indentation+8) + + +def print_formatted_list(elements: list[str], indentation: int = 0) -> None: + """ + When a list of elements is going to be printed, if it is longer than one line, reformat it to be multiple + lines with a 'ls' command style. + :param elements: list of elements to be printed + :param indentation: number of spaces to be injected in front of each line + """ + if len(elements) == 0: + return + elements.sort() + try: + h_size = get_terminal_size().columns if sys.stdin.isatty() else DEFAULT_TERMINAL_SIZE + except OSError: + h_size = DEFAULT_TERMINAL_SIZE + if indentation + sum(len(element) for element in elements) + (len(elements)*2) < h_size: # fits in one line + print(f"{' '*indentation}{', '.join([element for element in elements])}") + return + column_separator_size = 2 + column_width: int = len(max(elements, key=len)) + column_separator_size + n_columns: int = (h_size - indentation) // column_width + step = (len(elements) // n_columns) + 1 + rows = [elements[i::step] for i in range(step)] + for line in rows: + print(' '*indentation, end='') + for column in range(len(line)): + if line[column] is not None: + print(f"{line[column]:<{column_width}}", end='') + print() def fetch_merged_yaml(gl_gql: GitlabGQL, params) -> dict[str, Any]: