bazel: Extract ResultStore links from Bazel output
Bug: b/363338443
Change-Id: Ie7a308b7da56d13a477454b9b20c8977a3192665
Reviewed-on: https://pigweed-review.googlesource.com/c/infra/recipes/+/234973
Reviewed-by: Ted Pudlik <tpudlik@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Pigweed-Auto-Submit: Rob Mohr <mohrr@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed-service-accounts.iam.gserviceaccount.com>
diff --git a/recipe_modules/bazel/__init__.py b/recipe_modules/bazel/__init__.py
index 0b3cf54..8b84c4a 100644
--- a/recipe_modules/bazel/__init__.py
+++ b/recipe_modules/bazel/__init__.py
@@ -25,6 +25,7 @@
'recipe_engine/file',
'recipe_engine/path',
'recipe_engine/properties',
+ 'recipe_engine/raw_io',
'recipe_engine/step',
'recipe_engine/time',
]
diff --git a/recipe_modules/bazel/api.py b/recipe_modules/bazel/api.py
index 6243fef..97ceb53 100644
--- a/recipe_modules/bazel/api.py
+++ b/recipe_modules/bazel/api.py
@@ -139,13 +139,42 @@
assert program in programs, f'{program} not in {programs}'
assert programs[program]
for args in programs[program]:
- cmd = [self.ensure(), *args, *base_args]
- defer(
- self.api.step,
- shlex.join(args),
- cmd,
- **kwargs,
- )
+ with self.api.step.nest(shlex.join(args)) as pres:
+ temp = self.api.path.mkdtemp()
+ stdout = temp / 'stdout-copy'
+ defer(
+ self.api.step,
+ 'bazel',
+ [self.ensure(), *args, *base_args],
+ stderr=self.api.raw_io.output_text(
+ leak_to=stdout,
+ ),
+ **kwargs,
+ )
+
+ with self.api.step.nest(
+ 'find resultstore link from stdout'
+ ):
+ link = None
+ rx = re.compile(
+ r'Streaming build results to:\s*'
+ '(https?://.*?)\s*$'
+ )
+ test_data = (
+ '\nStreaming build results to: '
+ 'https://foo.bar.baz/results\n'
+ )
+ for line in self.api.file.read_text(
+ 'read',
+ stdout,
+ test_data=test_data,
+ ).splitlines():
+ if match := rx.search(line):
+ link = match.group(1)
+ break
+
+ if link:
+ pres.links['resultstore'] = link
def nwise(iterable, n):
diff --git a/recipe_modules/bazel/tests/full.py b/recipe_modules/bazel/tests/full.py
index e784b83..8be8186 100644
--- a/recipe_modules/bazel/tests/full.py
+++ b/recipe_modules/bazel/tests/full.py
@@ -71,7 +71,7 @@
check = post_process.StepCommandContains
if invert:
check = post_process.StepCommandDoesNotContain
- return api.post_process(check, step, pattern)
+ return api.post_process(check, f'{step}.bazel', pattern)
def lacks_override(step: str, name: str, bzlmod=False):
return contains_override(
diff --git a/recipes/bazel.expected/simple.json b/recipes/bazel.expected/simple.json
index cedbc89..e235b0d 100644
--- a/recipes/bazel.expected/simple.json
+++ b/recipes/bazel.expected/simple.json
@@ -1201,6 +1201,14 @@
"name": "default"
},
{
+ "cmd": [],
+ "name": "default.build //...",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_LINK@resultstore@https://foo.bar.baz/results@@@"
+ ]
+ },
+ {
"cmd": [
"[CLEANUP]/tmp_tmp_2/bazelisk",
"build",
@@ -1229,9 +1237,65 @@
"TEST_TMPDIR": "[CACHE]/bazel",
"TRIGGERING_CHANGES_JSON": "[CLEANUP]/tmp_tmp_1"
},
- "name": "default.build //...",
+ "name": "default.build //....bazel",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "default.build //....find resultstore link from stdout",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[CLEANUP]/tmp_tmp_3/stdout-copy",
+ "/path/to/tmp/"
+ ],
+ "cwd": "[START_DIR]/co",
+ "env": {
+ "BUILDBUCKET_ID": "0",
+ "BUILDBUCKET_NAME": "project:bucket:builder",
+ "BUILD_NUMBER": "0",
+ "CCACHE_DIR": "[CACHE]/ccache",
+ "CLICOLOR": "0",
+ "CLICOLOR_FORCE": "0",
+ "CTCACHE_DIR": "[CACHE]/clang_tidy",
+ "GCC_COLORS": "",
+ "GOCACHE": "[CACHE]/go",
+ "NO_COLOR": "1",
+ "PIP_CACHE_DIR": "[CACHE]/pip",
+ "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
+ "PW_ENVSETUP_DISABLE_SPINNER": "1",
+ "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
+ "PW_TEST_VAR": "test_value",
+ "PW_USE_COLOR": "",
+ "TEST_TMPDIR": "[CACHE]/bazel",
+ "TRIGGERING_CHANGES_JSON": "[CLEANUP]/tmp_tmp_1"
+ },
+ "infra_step": true,
+ "name": "default.build //....find resultstore link from stdout.read",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_LINE@stdout-copy@@@@",
+ "@@@STEP_LOG_LINE@stdout-copy@Streaming build results to: https://foo.bar.baz/results@@@",
+ "@@@STEP_LOG_END@stdout-copy@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "default.test //...",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_LINK@resultstore@https://foo.bar.baz/results@@@"
]
},
{
@@ -1263,9 +1327,57 @@
"TEST_TMPDIR": "[CACHE]/bazel",
"TRIGGERING_CHANGES_JSON": "[CLEANUP]/tmp_tmp_1"
},
- "name": "default.test //...",
+ "name": "default.test //....bazel",
"~followup_annotations": [
- "@@@STEP_NEST_LEVEL@1@@@"
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "default.test //....find resultstore link from stdout",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[CLEANUP]/tmp_tmp_4/stdout-copy",
+ "/path/to/tmp/"
+ ],
+ "cwd": "[START_DIR]/co",
+ "env": {
+ "BUILDBUCKET_ID": "0",
+ "BUILDBUCKET_NAME": "project:bucket:builder",
+ "BUILD_NUMBER": "0",
+ "CCACHE_DIR": "[CACHE]/ccache",
+ "CLICOLOR": "0",
+ "CLICOLOR_FORCE": "0",
+ "CTCACHE_DIR": "[CACHE]/clang_tidy",
+ "GCC_COLORS": "",
+ "GOCACHE": "[CACHE]/go",
+ "NO_COLOR": "1",
+ "PIP_CACHE_DIR": "[CACHE]/pip",
+ "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
+ "PW_ENVSETUP_DISABLE_SPINNER": "1",
+ "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
+ "PW_TEST_VAR": "test_value",
+ "PW_USE_COLOR": "",
+ "TEST_TMPDIR": "[CACHE]/bazel",
+ "TRIGGERING_CHANGES_JSON": "[CLEANUP]/tmp_tmp_1"
+ },
+ "infra_step": true,
+ "name": "default.test //....find resultstore link from stdout.read",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_LINE@stdout-copy@@@@",
+ "@@@STEP_LOG_LINE@stdout-copy@Streaming build results to: https://foo.bar.baz/results@@@",
+ "@@@STEP_LOG_END@stdout-copy@@@"
]
},
{