Skip to content

Commit da2aad9

Browse files
committed
feat(bitrisescript): scan bitrise.log for PERFHERDER_DATA and dump it to stdout
Perfherder is hardcoded to scan `public/live.log` for PERFHERDER_DATA. Since this shows up in `<workflow>/bitrise.log`, we need logic to forward these lines over to the main log.
1 parent d43ac3c commit da2aad9

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

bitrisescript/src/bitrisescript/bitrise.py

+26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22
import logging
33
import os
4+
from pathlib import Path
45
from pprint import pformat
56
from typing import Any
67

@@ -183,6 +184,30 @@ async def download_log(build_slug: str, artifacts_dir: str, poll_interval: int =
183184
log.error(f"Bitrise has no log for build '{build_slug}'. Please check https://app.bitrise.io/build/{build_slug}")
184185

185186

187+
async def dump_perfherder_data(artifacts_dir: str) -> None:
188+
"""Dumps any detected PERFHERDER_DATA log lines to stdout.
189+
190+
Perfherder is hardcoded to parse `public/live_backing.log` for lines that
191+
start with PERFHERDER_DATA. Scan the bitrise log and forward any such lines
192+
to stdout so Perfherder can find them.
193+
194+
Once bug 1646502 is fixed and all tasks relying on this function have been
195+
migrated over to the new ingestion format, we can remove this.
196+
197+
Args:
198+
artifacts_dir (str): Path to the artifact directory.
199+
"""
200+
path = Path(artifacts_dir) / "bitrise.log"
201+
if not path.is_file():
202+
log.warning(f"Not scanning for Perfherder data, {path} does not exist!")
203+
return
204+
205+
perfherder_data_lines = [line for line in path.read_text().splitlines() if line.startswith("PERFHERDER_DATA")]
206+
if perfherder_data_lines:
207+
perfherder_data_str = "\n".join(perfherder_data_lines)
208+
log.info(f"Found Perfherder data in {path}:\n{perfherder_data_str}")
209+
210+
186211
async def download_file(download_url: str, file_destination: str, chunk_size: int = 512) -> None:
187212
"""Download a file.
188213
@@ -240,3 +265,4 @@ async def run_build(artifacts_dir: str, workflow_id: str, **build_params: Any) -
240265
finally:
241266
log.info(f"Retrieving bitrise log for '{build_slug}'...")
242267
await download_log(build_slug, artifacts_dir)
268+
await dump_perfherder_data(artifacts_dir)

bitrisescript/tests/test_bitrise.py

+52-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
from asyncio import Future
21
import inspect
2+
import logging
3+
from asyncio import Future
34
from contextlib import nullcontext as does_not_raise
5+
from textwrap import dedent
46

57
import pytest
68
import pytest_asyncio
@@ -228,6 +230,55 @@ async def test_download_log(mocker, client):
228230
assert m_download.call_args == ((log_url, f"{artifacts_dir}/bitrise.log"),)
229231

230232

233+
@pytest.mark.asyncio
234+
async def test_dump_perfherder_data(mocker, caplog):
235+
caplog.set_level(logging.INFO)
236+
artifacts_dir = "artifacts"
237+
238+
# bitrise.log doesn't exist
239+
mock_is_file = mocker.patch.object(bitrise.Path, "is_file")
240+
mock_is_file.return_value = False
241+
await bitrise.dump_perfherder_data(artifacts_dir)
242+
assert "Not scanning for Perfherder data" in caplog.text
243+
244+
# bitrise.log doesn't contain Perfherder data
245+
caplog.clear()
246+
mock_is_file.return_value = True
247+
mock_read_text = mocker.patch.object(bitrise.Path, "read_text")
248+
mock_read_text.return_value = dedent(
249+
"""
250+
INFO does not contain
251+
DEBUG any perfherder data
252+
"""
253+
).strip()
254+
await bitrise.dump_perfherder_data(artifacts_dir)
255+
assert "Not scanning for Perfherder data" not in caplog.text
256+
assert "Found Perfherder data in" not in caplog.text
257+
258+
# bitrise.log contains Perfherder data
259+
caplog.clear()
260+
mock_read_text.return_value = dedent(
261+
"""
262+
INFO does contain
263+
PERFHERDER_DATA {"foo": "bar"}
264+
DEBUG perfherder data
265+
PERFHERDER_DATA {"baz": 1}
266+
"""
267+
).strip()
268+
await bitrise.dump_perfherder_data(artifacts_dir)
269+
assert "Not scanning for Perfherder data" not in caplog.text
270+
assert (
271+
dedent(
272+
"""
273+
Found Perfherder data in artifacts/bitrise.log:
274+
PERFHERDER_DATA {"foo": "bar"}
275+
PERFHERDER_DATA {"baz": 1}
276+
"""
277+
).strip()
278+
in caplog.text
279+
)
280+
281+
231282
@pytest.mark.asyncio
232283
async def test_download_file(responses, tmp_path):
233284
url = "https://example.com/log.txt"

0 commit comments

Comments
 (0)