[clang] Add resultdb support
This patch adds resultDB support for clang base bots.
Bug: 335328196
Change-Id: If55b6e1e5c26d3d0e375a89a89e7489c4c068902
Reviewed-on: https://fuchsia-review.googlesource.com/c/infra/recipes/+/1069010
Commit-Queue: Haowei Wu <haowei@google.com>
Reviewed-by: Paul Kirth <paulkirth@google.com>
diff --git a/recipes/contrib/clang.expected/ci_linux_x64.json b/recipes/contrib/clang.expected/ci_linux_x64.json
index bbef6cd..049ed4f 100644
--- a/recipes/contrib/clang.expected/ci_linux_x64.json
+++ b/recipes/contrib/clang.expected/ci_linux_x64.json
@@ -7982,6 +7982,7 @@
"-DLLVM_OVERRIDE_MODEL_HEADER_INLINERSIZEMODEL=[START_DIR]/cipd/model/InlinerSizeModel.h",
"-DLLVM_OVERRIDE_MODEL_OBJECT_INLINERSIZEMODEL=[START_DIR]/cipd/model/InlinerSizeModel.o",
"-DLLVM_RAEVICT_MODEL_PATH=none",
+ "-DLLVM_LIT_ARGS=--resultdb-output=r.j -v",
"-C",
"RECIPE[fuchsia::contrib/clang].resources/Fuchsia-toolchain.cmake"
],
@@ -8396,6 +8397,93 @@
]
},
{
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[START_DIR]/llvm_build",
+ "**/r.j"
+ ],
+ "env": {
+ "CLANG_MODULE_CACHE_PATH": "",
+ "GOMA_TMP_DIR": "[CLEANUP]/goma",
+ "GOMA_USE_LOCAL": "False"
+ },
+ "env_prefixes": {
+ "PATH": [
+ "[START_DIR]/cipd/bin"
+ ]
+ },
+ "infra_step": true,
+ "luci_context": {
+ "realm": {
+ "name": "fuchsia:ci"
+ },
+ "resultdb": {
+ "current_invocation": {
+ "name": "invocations/build:8945511751514863184",
+ "update_token": "token"
+ },
+ "hostname": "rdbhost"
+ }
+ },
+ "name": "clang.collect results.json",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_LOG_LINE@glob@[START_DIR]/llvm_build/[START_DIR]/llvm_build/r.j@@@",
+ "@@@STEP_LOG_LINE@glob@[START_DIR]/llvm_build/[START_DIR]/llvm_build/test/r.j@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "rdb",
+ "stream",
+ "-var",
+ "bucket:ci",
+ "-var",
+ "builder:builder",
+ "-new",
+ "-realm",
+ "fuchsia:ci",
+ "-include",
+ "--",
+ "vpython3",
+ "RECIPE[fuchsia::contrib/clang].resources/resultdb.py",
+ "--json=[START_DIR]/llvm_build/[START_DIR]/llvm_build/r.j",
+ "--json=[START_DIR]/llvm_build/[START_DIR]/llvm_build/test/r.j"
+ ],
+ "env": {
+ "CLANG_MODULE_CACHE_PATH": "",
+ "GOMA_TMP_DIR": "[CLEANUP]/goma",
+ "GOMA_USE_LOCAL": "False"
+ },
+ "env_prefixes": {
+ "PATH": [
+ "[START_DIR]/cipd/bin"
+ ]
+ },
+ "luci_context": {
+ "realm": {
+ "name": "fuchsia:ci"
+ },
+ "resultdb": {
+ "current_invocation": {
+ "name": "invocations/build:8945511751514863184",
+ "update_token": "token"
+ },
+ "hostname": "rdbhost"
+ }
+ },
+ "name": "clang.resultdb",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
"cmd": [],
"name": "teardown goma"
},
diff --git a/recipes/contrib/clang.py b/recipes/contrib/clang.py
index 8dd5f20..cf76320 100644
--- a/recipes/contrib/clang.py
+++ b/recipes/contrib/clang.py
@@ -3,6 +3,8 @@
# found in the LICENSE file.
"""Recipe for building Clang toolchain without any runtimes."""
+import contextlib
+
from PB.go.chromium.org.luci.common.proto.srcman.manifest import Manifest
from PB.recipes.fuchsia.contrib.clang import InputProperties
@@ -25,6 +27,7 @@
"recipe_engine/path",
"recipe_engine/platform",
"recipe_engine/properties",
+ "recipe_engine/resultdb",
"recipe_engine/step",
]
@@ -32,6 +35,10 @@
CIPD_SERVER_HOST = "chrome-infra-packages.appspot.com"
+# TODD(fxbug.dev/91157): Restore the file name once
+# path length issue is properly fixed.
+RESULTDB_JSON = "r.j"
+
def RunSteps(api, props):
# default values
@@ -163,6 +170,8 @@
]
)
+ options.append(f"-DLLVM_LIT_ARGS=--resultdb-output={RESULTDB_JSON} -v")
+
with api.step.nest("clang"), api.context(env=env):
api.cmake(
step_name="configure",
@@ -197,16 +206,51 @@
pkg_dir.joinpath("bin", hdrgen),
)
api.cas_util.upload(pkg_dir, output_property="isolated")
- api.ninja(
- "tests",
- [
- "check-clang",
- "check-llvm",
- "check-lld",
- ],
- ninja_jobs=ninja_jobs,
- build_dir=build_dir,
- )
+ with resultdb_context(api, build_dir):
+ api.ninja(
+ "tests",
+ [
+ "check-clang",
+ "check-llvm",
+ "check-lld",
+ ],
+ ninja_jobs=ninja_jobs,
+ build_dir=build_dir,
+ )
+
+
+@contextlib.contextmanager
+def resultdb_context(api, build_dir):
+ try:
+ yield
+ finally:
+ upload_to_resultdb(api, build_dir)
+
+
+def upload_to_resultdb(api, build_dir):
+ if not api.resultdb.enabled:
+ return # pragma: no cover
+ results_paths = api.file.glob_paths(
+ "collect results.json",
+ build_dir,
+ "**/%s" % RESULTDB_JSON,
+ test_data=[
+ build_dir.joinpath(RESULTDB_JSON),
+ build_dir.joinpath("test", RESULTDB_JSON),
+ ],
+ )
+ if not results_paths:
+ return # pragma: no cover
+ resultdb_base_variant = {
+ "bucket": api.buildbucket.build.builder.bucket,
+ "builder": api.buildbucket.build.builder.builder,
+ }
+ cmd = ["vpython3", api.resource("resultdb.py")]
+ cmd.extend(f"--json={p}" for p in results_paths)
+ api.step(
+ "resultdb",
+ api.resultdb.wrap(cmd, base_variant=resultdb_base_variant.copy(), include=True),
+ )
def ensure_llvm_deps_prebuilts(
diff --git a/recipes/contrib/clang.resources/resultdb.py b/recipes/contrib/clang.resources/resultdb.py
new file mode 100755
index 0000000..9f38677
--- /dev/null
+++ b/recipes/contrib/clang.resources/resultdb.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env vpython3
+
+# Copyright 2021 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# [VPYTHON:BEGIN]
+# python_version: "3.8"
+# wheel: <
+# name: "infra/python/wheels/idna-py2_py3"
+# version: "version:2.10"
+# >
+# wheel: <
+# name: "infra/python/wheels/urllib3-py2_py3"
+# version: "version:1.26.4"
+# >
+# wheel: <
+# name: "infra/python/wheels/certifi-py2_py3"
+# version: "version:2020.12.5"
+# >
+# wheel: <
+# name: "infra/python/wheels/chardet-py2_py3"
+# version: "version:4.0.0"
+# >
+# wheel: <
+# name: "infra/python/wheels/requests-py2_py3"
+# version: "version:2.25.1"
+# >
+# [VPYTHON:END]
+
+"""Read JSON output from llvm-lit and upload the data to resultDB.
+
+Usage:
+ rdb [rdb flags] -- resultdb.py --json=JSON_FILE
+"""
+
+import json
+import argparse
+import os
+import sys
+import requests
+
+
+def read_jsons(json_files):
+ test_results = []
+ for json_file in json_files:
+ with open(json_file, encoding="utf-8") as f:
+ data = json.load(f)
+ test_results.extend(data["tests"])
+ return test_results
+
+
+def upload_results(test_results, url, auth_token):
+ res = requests.post(
+ url,
+ headers={
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ "Authorization": "ResultSink %s" % auth_token,
+ },
+ data=json.dumps({"testResults": test_results}),
+ )
+ res.raise_for_status()
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--json", action="append", help="json output from llvm-lit")
+ args = parser.parse_args()
+ if not args.json:
+ print("Please specify the lit json file(s).")
+ return 1
+ sink = None
+ if "LUCI_CONTEXT" in os.environ:
+ with open(os.environ["LUCI_CONTEXT"], encoding="utf-8") as f:
+ sink = json.load(f)["result_sink"]
+ if sink is None:
+ print("result_sink not defined")
+ return 1
+ test_results = read_jsons(args.json)
+ if not test_results:
+ print("Empty test results: skipping")
+ return 0
+ url = str.format(
+ "http://{}/prpc/luci.resultsink.v1.Sink/{}",
+ sink["address"],
+ "ReportTestResults",
+ )
+ upload_results(test_results, url, sink["auth_token"])
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())