From 93f39c9169efc674e8efc70162d2d1536fbc66d2 Mon Sep 17 00:00:00 2001 From: Jakub Kocka Date: Mon, 7 Sep 2026 10:27:48 +0200 Subject: [PATCH] ci(tools): Avoid live-log the hints test failure on Windows --- .gitlab/ci/test-win.yml | 7 +-- .../test_build_system_helpers/idf_utils.py | 46 +++++++++++++++---- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/.gitlab/ci/test-win.yml b/.gitlab/ci/test-win.yml index 62e7639690e..04b272a7993 100644 --- a/.gitlab/ci/test-win.yml +++ b/.gitlab/ci/test-win.yml @@ -55,7 +55,7 @@ test_tools_win: # Build tests .test_build_system_template_win: extends: .host_test_win_template - timeout: 4 hours + timeout: 2 hours artifacts: paths: - XUNIT_RESULT.xml @@ -67,7 +67,7 @@ test_tools_win: script: - cd tools\test_build_system - idf-ci gitlab download-known-failure-cases-file ${KNOWN_FAILURE_CASES_FILE_NAME} - - pytest --parallel-count ${CI_NODE_TOTAL} --parallel-index ${CI_NODE_INDEX} --junitxml=${CI_PROJECT_DIR}\XUNIT_RESULT.xml --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} --durations=10 + - pytest --parallel-count ${CI_NODE_TOTAL} --parallel-index ${CI_NODE_INDEX} --work-dir ${CI_PROJECT_DIR}\test_build_system --junitxml=${CI_PROJECT_DIR}\XUNIT_RESULT.xml --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} --durations=10 pytest_build_system_win: extends: @@ -93,7 +93,7 @@ pytest_build_system_win_minimal_cmake: } - cd tools\test_build_system - idf-ci gitlab download-known-failure-cases-file ${KNOWN_FAILURE_CASES_FILE_NAME} - - pytest -k cmake --junitxml=${CI_PROJECT_DIR}\XUNIT_RESULT.xml --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} --durations=10 + - pytest -k cmake --work-dir ${CI_PROJECT_DIR}\test_build_system --junitxml=${CI_PROJECT_DIR}\XUNIT_RESULT.xml --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} --durations=10 pytest_buildv2_system_win: extends: @@ -107,5 +107,6 @@ pytest_buildv2_system_win: --buildv2 --parallel-count ${CI_NODE_TOTAL} --parallel-index ${CI_NODE_INDEX} + --work-dir ${CI_PROJECT_DIR}\test_build_system --junitxml=${CI_PROJECT_DIR}\XUNIT_RESULT.xml --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} diff --git a/tools/test_build_system/test_build_system_helpers/idf_utils.py b/tools/test_build_system/test_build_system_helpers/idf_utils.py index 357c0c5faa9..63e1bd2a006 100644 --- a/tools/test_build_system/test_build_system_helpers/idf_utils.py +++ b/tools/test_build_system/test_build_system_helpers/idf_utils.py @@ -6,6 +6,7 @@ import shutil import subprocess import sys import typing +import uuid from pathlib import Path try: @@ -68,6 +69,41 @@ def _clip_log_output(text: str | None, max_lines: int = 80, max_line_len: int = return '\n'.join(parts) +def _log_process_failure( + command_name: str, + cmd: list[str], + workdir: Path | str, + error: subprocess.CalledProcessError, +) -> None: + """Save the untouched output to files, then log one clipped record. + + The files keep the whole output available whatever the failure is, so the + clipped record no longer has to carry everything needed to debug it. Writing + them before logging also means the output survives a stalled live log. + """ + log_dir = Path(workdir) / 'failed_command_logs' + saved_paths: dict[str, Path] = {} + try: + log_dir.mkdir(parents=True, exist_ok=True) + prefix = f'{command_name}_{uuid.uuid4().hex}' + for stream_name, output in (('stdout', error.stdout), ('stderr', error.stderr)): + output_path = log_dir / f'{prefix}.{stream_name}.txt' + output_path.write_text(output or '', encoding='utf-8') + saved_paths[stream_name] = output_path + except OSError as write_error: + logging.error('Full output of the failed command could not be saved: %s', write_error) + + message = [ + f'The following {command_name} command has failed: {" ".join(cmd)}', + f'Working directory: {workdir}', + ] + for stream_name, output_path in saved_paths.items(): + message.append(f'Full {stream_name}: {output_path}') + message.append(f'Stdout: {_clip_log_output(error.stdout)}') + message.append(f'Stderr: {_clip_log_output(error.stderr)}') + logging.error('\n'.join(message)) + + def normalize_output(text: str) -> str: """Collapse all whitespace runs to a single space. @@ -155,10 +191,7 @@ def run_idf_py( input=input_str, ) except subprocess.CalledProcessError as e: - logging.error('The following idf.py command has failed: {}'.format(' '.join(cmd))) - logging.error(f'Working directory: {workdir}') - logging.error(f'Stdout: {_clip_log_output(e.stdout)}') - logging.error(f'Stderr: {_clip_log_output(e.stderr)}') + _log_process_failure('idf.py', cmd, workdir, e) raise @@ -200,10 +233,7 @@ def run_cmake( errors='backslashreplace', ) except subprocess.CalledProcessError as e: - logging.error('The following cmake command has failed: {}'.format(' '.join(cmd))) - logging.error(f'Working directory: {workdir}') - logging.error(f'Stdout: {_clip_log_output(e.stdout)}') - logging.error(f'Stderr: {_clip_log_output(e.stderr)}') + _log_process_failure('cmake', cmd, build_dir, e) raise