-
-
Notifications
You must be signed in to change notification settings - Fork 638
Description
Problem Summary
The gazelle_python_manifest.test generated by the gazelle_python_manifest macro fails on Linux CI but passes on macOS due to incorrect file path handling in the test implementation.
Error Message on Linux
FAIL: TestGazelleManifestIsUpdated (0.00s)
test.go:46: decoding manifest file: failed to decode manifest file:
open tools/python/urf/gazelle_python.yaml: no such file or directory
Root Cause
The test code has an inconsistency in how it accesses data files:
- ✅ Correctly uses runfiles for the manifest generator hash file via
runfiles.Rlocation() - ❌ Incorrectly uses direct file access for the manifest and requirements files
- ❌ Uses
$(rootpath)instead of$(rlocationpath)in the Bazel rule definition
This works on macOS because its Bazel sandbox is more lenient, but fails on Linux where the sandbox strictly enforces file access through the runfiles tree.
Technical Details
Why It Fails on Linux But Not macOS
- macOS Bazel Sandbox: More lenient, allows accessing workspace files even with
rundir = "." - Linux Bazel Sandbox: Stricter isolation, only allows access to files in the runfiles tree
- The Path Issue:
$(rootpath)expands to workspace-relative paths likegazelle/manifest/gazelle_python.yaml- In Linux sandbox, this path doesn't exist - the file is only in the runfiles tree at
_main/gazelle/manifest/gazelle_python.yaml - The test needs to use
runfiles.Rlocation()to find the actual file location
Code Issues
Issue 1: gazelle/manifest/defs.bzl (Lines 120, 122)
Current (incorrect):
attrs = {
"env": {
"_TEST_MANIFEST": "$(rootpath {})".format(manifest), # ❌ Wrong
"_TEST_MANIFEST_GENERATOR_HASH": "$(rlocationpath {})".format(manifest_generator_hash), # ✅ Correct
"_TEST_REQUIREMENTS": "$(rootpath {})".format(requirements), # ❌ Wrong
},
}Should be:
attrs = {
"env": {
"_TEST_MANIFEST": "$(rlocationpath {})".format(manifest), # ✅ Fixed
"_TEST_MANIFEST_GENERATOR_HASH": "$(rlocationpath {})".format(manifest_generator_hash), # ✅ Already correct
"_TEST_REQUIREMENTS": "$(rlocationpath {})".format(requirements), # ✅ Fixed
},
}Issue 2: gazelle/manifest/test/test.go (Lines 53, 73, 84-86)
The test code resolves the paths using runfiles.Rlocation() but then doesn't use the resolved paths:
Current (incorrect):
// Lines 35-38: Correctly resolves the path
requirementsPathResolved, err := runfiles.Rlocation(requirementsPath)
if err != nil {
t.Fatalf("failed to resolve runfiles path of requirements: %v", err)
}
// Line 73: But then uses the UNRESOLVED path! ❌
requirements, err := os.Open(requirementsPath) // Bug: should use requirementsPathResolvedSimilar issues at:
- Line 53:
manifestFile.Decode(manifestPath)should usemanifestPathResolved - Line 73:
os.Open(requirementsPath)should userequirementsPathResolved - Lines 84-86:
filepath.EvalSymlinks(manifestPath)should usemanifestPathResolved
Example: How It Should Work
The test already has the correct pattern for _TEST_MANIFEST_GENERATOR_HASH:
// ✅ This is the correct pattern (lines 61-65):
manifestGeneratorHashPath, err := runfiles.Rlocation(
os.Getenv("_TEST_MANIFEST_GENERATOR_HASH"))
if err != nil {
t.Fatalf("failed to resolve runfiles path of manifest: %v", err)
}
// Then uses the resolved path:
manifestGeneratorHash, err := os.Open(manifestGeneratorHashPath) // ✅ CorrectThe same pattern needs to be applied to _TEST_MANIFEST and _TEST_REQUIREMENTS.
Why This Fix Works
-
$(rootpath)expands to a workspace-relative path- Only works in lenient sandboxes that allow direct workspace access
- Fails in strict Linux sandboxes
-
$(rlocationpath)expands to a runfiles-compatible path- Works consistently across all platforms
- The canonical way to reference data dependencies in Bazel tests
- See: https://bazel.build/reference/be/make-variables
-
runfiles.Rlocation()resolves the runfiles path to the actual file location in the sandbox- Handles platform differences automatically
- Required for cross-platform compatibility
- See: https://bazel.build/extending/rules#runfiles
Reproduction
To reproduce the issue:
# On Linux (e.g., in Docker or Linux CI)
cd gazelle/examples/bzlmod_build_file_generation
bazel test //:gazelle_python_manifest.test
# Result: FAIL with "no such file or directory"References
- Bazel Runfiles: https://bazel.build/extending/rules#runfiles
- Bazel Test Environment: https://bazel.build/reference/test-encyclopedia
$(rlocationpath)vs$(rootpath): https://bazel.build/reference/be/make-variables- Runfiles best practices: https://bazel.build/extending/rules#runfiles_features_to_avoid
Credit: Issue reported and investigated by @timfallmk