Skip to content

Commit

Permalink
When configuring fails in Github Actions, print folded logs
Browse files Browse the repository at this point in the history
A common, and challenging, issue in CI runners is debugging issues when
you know the information you want to check, but it's in the log file
which you don't have because remote CI machines.

There are various edge cases where this is especially hard to solve,
such as inside of `pip install` where the build directory with the log
file is automatically cleaned up. But it's never really *easy* when you
don't expect it, and the best case scenario is your iteration time gets
cut in half as you hurriedly go add some `cat`s to your CI scripts.

Meson can, at least sometimes, detect platforms where text can be
emitted inside of "folds", which are auto-collapsed and don't obscure
the general output, but when clicked will expand the logfile contents.
Hook this up.

We start off with a Github Actions implementation. We had some internal
code used by our own project tests runner, which can be utilized.

Also permit forcing it via an environment variable, in case
autodetection fails and you just want to force *something*, especially
when meson is called a couple layers deep inside some other tool.

(cherry picked from commit 2b80d4c)
  • Loading branch information
eli-schwartz committed Sep 16, 2024
1 parent c726ca4 commit f1b7f52
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 9 deletions.
3 changes: 3 additions & 0 deletions mesonbuild/mesonmain.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ def errorhandler(e: Exception, command: str) -> int:
logfile = mlog.shutdown()
if logfile is not None:
mlog.log("\nA full log can be found at", mlog.bold(logfile))
contents = mlog.ci_fold_file(logfile, f'CI platform detected, click here for {os.path.basename(logfile)} contents.')
if contents:
print(contents)
if os.environ.get('MESON_FORCE_BACKTRACE'):
raise e
return 1
Expand Down
31 changes: 30 additions & 1 deletion mesonbuild/mlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
from pathlib import Path

if T.TYPE_CHECKING:
from ._typing import StringProtocol, SizedStringProtocol
from typing_extensions import Literal

from ._typing import StringProtocol, SizedStringProtocol
from .mparser import BaseNode

TV_Loggable = T.Union[str, 'AnsiDecorator', StringProtocol]
Expand Down Expand Up @@ -75,6 +76,7 @@ def setup_console() -> None:
pass

_in_ci = 'CI' in os.environ
_ci_is_github = 'GITHUB_ACTIONS' in os.environ


class _Severity(enum.Enum):
Expand Down Expand Up @@ -540,3 +542,30 @@ def code_line(text: str, line: str, colno: int) -> str:
:return: A formatted string of the text, line, and a caret
"""
return f'{text}\n{line}\n{" " * colno}^'

@T.overload
def ci_fold_file(fname: T.Union[str, os.PathLike], banner: str, force: Literal[True] = True) -> str: ...

@T.overload
def ci_fold_file(fname: T.Union[str, os.PathLike], banner: str, force: Literal[False] = False) -> T.Optional[str]: ...

def ci_fold_file(fname: T.Union[str, os.PathLike], banner: str, force: bool = False) -> T.Optional[str]:
if not _in_ci and not force:
return None

if _ci_is_github:
header = f'::group::==== {banner} ===='
footer = '::endgroup::'
elif force:
header = banner
footer = ''
elif 'MESON_FORCE_SHOW_LOGS' in os.environ:
header = f'==== Forcing display of logs for {os.path.basename(fname)} ===='
footer = ''
else:
# only github is implemented
return None

with open(fname, 'r', encoding='utf-8') as f:
data = f.read()
return f'{header}\n{data}\n{footer}\n'
11 changes: 3 additions & 8 deletions run_project_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ def __lt__(self, other: object) -> bool:
failing_logs: T.List[str] = []
print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
under_ci = 'CI' in os.environ
ci_is_github = 'GITHUB_ACTIONS' in os.environ
raw_ci_jobname = os.environ.get('MESON_CI_JOBNAME', None)
ci_jobname = raw_ci_jobname if raw_ci_jobname != 'thirdparty' else None
do_debug = under_ci or print_debug
Expand Down Expand Up @@ -437,16 +436,12 @@ def log_text_file(logfile: T.TextIO, testdir: Path, result: TestResult) -> None:


def _run_ci_include(args: T.List[str]) -> str:
header = f'Included file {args[0]}:'
footer = ''
if ci_is_github:
header = f'::group::==== {header} ===='
footer = '::endgroup::'
if not args:
return 'At least one parameter required'

header = f'Included file {args[0]}:'
try:
data = Path(args[0]).read_text(errors='ignore', encoding='utf-8')
return f'{header}\n{data}\n{footer}\n'
return mlog.ci_fold_file(args[0], header, force=True)
except Exception:
return 'Failed to open {}\n'.format(args[0])

Expand Down

0 comments on commit f1b7f52

Please sign in to comment.