summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.gitlab-ci/lava/lava_job_submitter.py8
-rw-r--r--.gitlab-ci/lava/utils/lava_log.py82
-rw-r--r--.gitlab-ci/tests/utils/__init__.py0
-rw-r--r--.gitlab-ci/tests/utils/test_lava_log.py60
4 files changed, 149 insertions, 1 deletions
diff --git a/.gitlab-ci/lava/lava_job_submitter.py b/.gitlab-ci/lava/lava_job_submitter.py
index 9eba34c8820..3f5a7f3a816 100755
--- a/.gitlab-ci/lava/lava_job_submitter.py
+++ b/.gitlab-ci/lava/lava_job_submitter.py
@@ -46,6 +46,7 @@ from lava.exceptions import (
MesaCIRetryError,
MesaCITimeoutError,
)
+from lava.utils.lava_log import GitlabSection
from lavacli.utils import loader
# Timeout in seconds to decide if the device from the dispatched LAVA job has
@@ -140,7 +141,10 @@ def generate_lava_yaml(args):
# skeleton test definition: only declaring each job as a single 'test'
# since LAVA's test parsing is not useful to us
- run_steps = []
+ setup_section = GitlabSection(
+ id="lava_setup", header="LAVA setup log", start_collapsed=True
+ )
+ run_steps = [f"printf '{setup_section.start()}'"]
test = {
'timeout': { 'minutes': args.job_timeout },
'failure_retry': 1,
@@ -191,6 +195,8 @@ def generate_lava_yaml(args):
'mkdir -p {}'.format(args.ci_project_dir),
'wget -S --progress=dot:giga -O- {} | tar -xz -C {}'.format(args.build_url, args.ci_project_dir),
'wget -S --progress=dot:giga -O- {} | tar -xz -C /'.format(args.job_rootfs_overlay_url),
+ f"printf '{setup_section.end()}'",
+
# Putting CI_JOB name as the testcase name, it may help LAVA farm
# maintainers with monitoring
f"lava-test-case 'mesa-ci_{args.mesa_job_name}' --shell /init-stage2.sh",
diff --git a/.gitlab-ci/lava/utils/lava_log.py b/.gitlab-ci/lava/utils/lava_log.py
new file mode 100644
index 00000000000..655ca4def19
--- /dev/null
+++ b/.gitlab-ci/lava/utils/lava_log.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Collabora Limited
+# Author: Guilherme Gallo <guilherme.gallo@collabora.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""
+Some utilities to analyse logs, create gitlab sections and other quality of life
+improvements
+"""
+
+from dataclasses import dataclass
+from datetime import datetime
+
+# Helper constants to colorize the job output
+CONSOLE_LOG = {
+ "COLOR_GREEN": "\x1b[1;32;5;197m",
+ "COLOR_RED": "\x1b[1;38;5;197m",
+ "RESET": "\x1b[0m",
+ "UNDERLINED": "\x1b[3m",
+ "BOLD": "\x1b[1m",
+ "DIM": "\x1b[2m",
+}
+
+
+@dataclass
+class GitlabSection:
+ id: str
+ header: str
+ start_collapsed: bool = False
+ escape: str = "\x1b[0K"
+ colour: str = f"{CONSOLE_LOG['BOLD']}{CONSOLE_LOG['COLOR_GREEN']}"
+
+ def get_timestamp(self) -> str:
+ unix_ts = datetime.timestamp(datetime.now())
+ return str(int(unix_ts))
+
+ def section(self, marker: str, header: str) -> str:
+ preamble = f"{self.escape}section_{marker}"
+ collapse = marker == "start" and self.start_collapsed
+ collapsed = "[collapsed=true]" if collapse else ""
+ section_id = f"{self.id}{collapsed}"
+
+ timestamp = self.get_timestamp()
+ before_header = ":".join([preamble, timestamp, section_id])
+ colored_header = (
+ f"{self.colour}{header}{CONSOLE_LOG['RESET']}" if header else ""
+ )
+ header_wrapper = "\r" + f"{self.escape}{colored_header}"
+
+ return f"{before_header}{header_wrapper}"
+
+ def __enter__(self):
+ print(self.start())
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ print(self.end())
+
+ def start(self) -> str:
+ return self.section(marker="start", header=self.header)
+
+ def end(self) -> str:
+ return self.section(marker="end", header="")
diff --git a/.gitlab-ci/tests/utils/__init__.py b/.gitlab-ci/tests/utils/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/.gitlab-ci/tests/utils/__init__.py
diff --git a/.gitlab-ci/tests/utils/test_lava_log.py b/.gitlab-ci/tests/utils/test_lava_log.py
new file mode 100644
index 00000000000..f81c49f5d5d
--- /dev/null
+++ b/.gitlab-ci/tests/utils/test_lava_log.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Collabora Limited
+# Author: Guilherme Gallo <guilherme.gallo@collabora.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import pytest
+from lava.utils.lava_log import GitlabSection
+
+GITLAB_SECTION_SCENARIOS = {
+ "start collapsed": (
+ "start",
+ True,
+ f"\x1b[0Ksection_start:mock_date:my_first_section[collapsed=true]\r\x1b[0K{GitlabSection.colour}my_header\x1b[0m",
+ ),
+ "start non_collapsed": (
+ "start",
+ False,
+ f"\x1b[0Ksection_start:mock_date:my_first_section\r\x1b[0K{GitlabSection.colour}my_header\x1b[0m",
+ ),
+ "end collapsed": (
+ "end",
+ True,
+ "\x1b[0Ksection_end:mock_date:my_first_section\r\x1b[0K",
+ ),
+ "end non_collapsed": (
+ "end",
+ False,
+ "\x1b[0Ksection_end:mock_date:my_first_section\r\x1b[0K",
+ ),
+}
+
+@pytest.mark.parametrize(
+ "method, collapsed, expectation",
+ GITLAB_SECTION_SCENARIOS.values(),
+ ids=GITLAB_SECTION_SCENARIOS.keys(),
+)
+def test_gitlab_section(method, collapsed, expectation):
+ gs = GitlabSection(id="my_first_section", header="my_header", start_collapsed=collapsed)
+ gs.get_timestamp = lambda: "mock_date"
+ result = getattr(gs, method)()
+ assert result == expectation