Keep cross Bazel builds test-free

This commit is contained in:
Adam Perry
2026-06-09 17:42:53 +00:00
parent 1411346ade
commit ece5d5279b
4 changed files with 245 additions and 28 deletions
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/env python3
import json
import os
import subprocess
import unittest
from pathlib import Path
from tempfile import TemporaryDirectory
REPO_ROOT = Path(__file__).resolve().parents[2]
RELEASE_SCRIPT = REPO_ROOT / "scripts" / "list-bazel-release-targets.sh"
CLIPPY_SCRIPT = REPO_ROOT / "scripts" / "list-bazel-clippy-targets.sh"
class BazelTargetListsTest(unittest.TestCase):
def run_selector(
self,
script: Path,
*args: str,
production_targets: tuple[str, ...] = (
"//codex-rs/cli:codex",
"//codex-rs/core:core",
),
test_targets: tuple[str, ...] = (
"//codex-rs/core:core-unit-tests-bin",
"//codex-rs/core:core-all-test-bin",
"//codex-rs/core:core-all-test-windows-cross-bin",
),
fail_query_containing: str = "",
) -> tuple[subprocess.CompletedProcess[str], list[list[str]]]:
with TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
query_log = temp_path / "queries.jsonl"
fake_query = temp_path / "fake-bazel-query.py"
fake_query.write_text(
"""#!/usr/bin/env python3
import json
import os
import sys
from pathlib import Path
with Path(os.environ["QUERY_LOG"]).open("a", encoding="utf-8") as query_log:
query_log.write(json.dumps(sys.argv[1:]) + "\\n")
query = sys.argv[-1]
if os.environ["FAIL_QUERY_CONTAINING"] and os.environ["FAIL_QUERY_CONTAINING"] in query:
raise SystemExit("injected query failure")
if "rust_(binary|library|proc_macro) rule" in query:
print(os.environ["PRODUCTION_TARGETS"])
elif "rust_test rule" in query:
print(os.environ["TEST_TARGETS"])
else:
raise SystemExit(f"unexpected query: {query}")
""",
encoding="utf-8",
)
fake_query.chmod(0o755)
env = os.environ.copy()
env.update(
{
"CODEX_BAZEL_QUERY_SCRIPT": str(fake_query),
"FAIL_QUERY_CONTAINING": fail_query_containing,
"PRODUCTION_TARGETS": "\n".join(production_targets),
"QUERY_LOG": str(query_log),
"TEST_TARGETS": "\n".join(test_targets),
}
)
result = subprocess.run(
["bash", str(script), *args],
cwd=REPO_ROOT,
env=env,
check=False,
capture_output=True,
text=True,
)
queries = [
json.loads(line)
for line in query_log.read_text(encoding="utf-8").splitlines()
]
return result, queries
def test_release_targets_are_sorted_explicit_production_rules(self) -> None:
result, queries = self.run_selector(
RELEASE_SCRIPT,
production_targets=(
"//codex-rs/core:core",
"//codex-rs/cli:codex",
),
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(
result.stdout.splitlines(),
["//codex-rs/cli:codex", "//codex-rs/core:core"],
)
self.assertEqual(len(queries), 1)
self.assertIn("rust_(binary|library|proc_macro) rule", queries[0][-1])
self.assertIn("//visibility:public", queries[0][-1])
self.assertNotIn("rust_test rule", queries[0][-1])
def test_release_targets_fail_when_discovery_is_empty(self) -> None:
result, _ = self.run_selector(RELEASE_SCRIPT, production_targets=())
self.assertNotEqual(result.returncode, 0)
self.assertIn("No Bazel release-build targets found.", result.stderr)
def test_native_clippy_adds_manual_native_test_binaries(self) -> None:
result, queries = self.run_selector(CLIPPY_SCRIPT)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(
result.stdout.splitlines(),
[
"//codex-rs/cli:codex",
"//codex-rs/core:core",
"//codex-rs/core:core-all-test-bin",
"//codex-rs/core:core-unit-tests-bin",
],
)
self.assertEqual(len(queries), 2)
self.assertIn("rust_test rule", queries[1][-1])
def test_cross_clippy_never_queries_or_returns_test_rules(self) -> None:
result, queries = self.run_selector(
CLIPPY_SCRIPT,
"--windows-cross-compile",
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(
result.stdout.splitlines(),
["//codex-rs/cli:codex", "//codex-rs/core:core"],
)
self.assertEqual(len(queries), 1)
self.assertNotIn("rust_test rule", queries[0][-1])
def test_native_clippy_prints_nothing_when_test_discovery_fails(self) -> None:
result, queries = self.run_selector(
CLIPPY_SCRIPT,
fail_query_containing="rust_test rule",
)
self.assertNotEqual(result.returncode, 0)
self.assertEqual(result.stdout, "")
self.assertEqual(len(queries), 2)
if __name__ == "__main__":
unittest.main()
+42
View File
@@ -84,6 +84,48 @@ jobs:
shell: bash
run: ./scripts/check-module-bazel-lock.sh
- name: Check build-only Bazel target selectors exclude tests
if: matrix.os == 'ubuntu-24.04' && matrix.target == 'x86_64-unknown-linux-gnu'
shell: bash
run: |
set -euo pipefail
check_build_only_selector() {
local selector_name="$1"
shift
local target_lines
target_lines="$("$@")"
if [[ -z "${target_lines}" ]]; then
echo "${selector_name} returned no targets." >&2
exit 1
fi
local targets=()
while IFS= read -r target; do
targets+=("${target}")
done <<< "${target_lines}"
local selected_tests
selected_tests="$(
./.github/scripts/run-bazel-query-ci.sh \
--output=label \
-- "tests(set(${targets[*]}))"
)"
if [[ -n "${selected_tests}" ]]; then
echo "${selector_name} included Bazel test rules:" >&2
printf '%s\n' "${selected_tests}" >&2
exit 1
fi
}
check_build_only_selector \
verify-release-build \
bash ./scripts/list-bazel-release-targets.sh
check_build_only_selector \
windows-cross-clippy \
./scripts/list-bazel-clippy-targets.sh --windows-cross-compile
- name: bazel test //...
env:
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
+33 -19
View File
@@ -5,6 +5,8 @@ set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${repo_root}"
query_script="${CODEX_BAZEL_QUERY_SCRIPT:-./.github/scripts/run-bazel-query-ci.sh}"
windows_cross_compile=0
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -22,31 +24,43 @@ done
# Resolve the dynamic targets before printing anything so callers do not
# continue with a partial list if `bazel query` fails. Target discovery is
# local on all platforms.
production_targets="$(
"${query_script}" \
--output=label \
-- 'attr(visibility, "//visibility:public", kind("rust_(binary|library|proc_macro) rule", //codex-rs/... except //codex-rs/v8-poc/...))' \
| LC_ALL=C sort
)"
if [[ -z "${production_targets}" ]]; then
echo "No Bazel clippy production targets found." >&2
exit 1
fi
if [[ $windows_cross_compile -eq 1 ]]; then
# Build-only cross-compilation has no target-platform test runner. Lint the
# complete production surface without analyzing rust_test or
# workspace_root_test rules.
printf '%s\n' "${production_targets}"
exit 0
fi
manual_rust_test_targets="$(
./.github/scripts/run-bazel-query-ci.sh \
"${query_script}" \
--output=label \
-- 'kind("rust_test rule", attr(tags, "manual", //codex-rs/... except //codex-rs/v8-poc/...))'
)"
if [[ "${RUNNER_OS:-}" != "Windows" ]]; then
# Non-Windows clippy jobs lint the native test binaries; the
# Windows-cross binaries exist only for the fast Windows test leg.
manual_rust_test_targets="$(printf '%s\n' "${manual_rust_test_targets}" | grep -v -- '-windows-cross-bin$' || true)"
elif [[ $windows_cross_compile -eq 1 ]]; then
# `bazel query` is intentionally pre-analysis and does not remove targets
# made incompatible by `target_compatible_with`. Sharded integration tests
# add native-only manual helpers such as `core-all-test-bin`, plus separate
# `core-all-test-windows-cross-bin` helpers for the Windows cross leg. Keep
# the Windows helpers and unit-test helpers, but do not pass the native-only
# sharded integration helpers as explicit clippy targets.
manual_rust_test_targets="$(printf '%s\n' "${manual_rust_test_targets}" | grep -v -- '-test-bin$' || true)"
fi
printf '%s\n' \
"//codex-rs/..." \
"-//codex-rs/v8-poc:all"
manual_rust_test_targets="$(
printf '%s\n' "${manual_rust_test_targets}" \
| grep -v -- '-windows-cross-bin$' \
| LC_ALL=C sort \
|| true
)"
# `--config=clippy` on the `workspace_root_test` wrappers does not lint the
# underlying `rust_test` binaries. Add the internal manual `*-unit-tests-bin`
# targets explicitly so inline `#[cfg(test)]` code is linted like
# `cargo clippy --tests`.
printf '%s\n' "${manual_rust_test_targets}"
printf '%s\n' "${production_targets}"
if [[ -n "${manual_rust_test_targets}" ]]; then
printf '%s\n' "${manual_rust_test_targets}"
fi
+19 -9
View File
@@ -5,12 +5,22 @@ set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${repo_root}"
# Keep this list focused on first-party Rust targets whose compile surface can
# differ when `cfg(not(debug_assertions))` becomes active.
#
# Exclude the experimental `v8-poc` target because it pulls in expensive V8
# build machinery that is unrelated to the release-only Rust regression this
# workflow is meant to catch.
printf '%s\n' \
"//codex-rs/..." \
"-//codex-rs/v8-poc:all"
query_script="${CODEX_BAZEL_QUERY_SCRIPT:-./.github/scripts/run-bazel-query-ci.sh}"
# Enumerate explicit first-party production targets instead of returning a
# recursive package pattern. A recursive build pattern also selects rust_test
# and workspace_root_test rules, which makes build-only cross-compilation
# depend on a target-platform test execution toolchain.
production_targets="$(
"${query_script}" \
--output=label \
-- 'attr(visibility, "//visibility:public", kind("rust_(binary|library|proc_macro) rule", //codex-rs/... except //codex-rs/v8-poc/...))' \
| LC_ALL=C sort
)"
if [[ -z "${production_targets}" ]]; then
echo "No Bazel release-build targets found." >&2
exit 1
fi
printf '%s\n' "${production_targets}"