-
-
Notifications
You must be signed in to change notification settings - Fork 612
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix RuleRunner to work without BUILD_ROOT file in pytest sandbox #21112
base: main
Are you sure you want to change the base?
Conversation
Repos that use pants.testutil might not have a BUILD_ROOT file, and most likely would not make any RuleRunner-based tests depend on that file (adding it to the pytest sandbox). Instead, the RuleRunner needs to manage adding a sentinel file. This was not an issue before NativeOptionParser was wired up in the python layer as part of 2.22. Now, however, NativeOptionParser needs to be able to detect the build root using either an env var (PANTS_BUILDROOT_OVERRIDE) or a sentinel file in the cwd. This makes RuleRunner add that sentinel file.
@@ -24,7 +24,6 @@ python_sources( | |||
"pants_integration_test.py": { | |||
"dependencies": ["//BUILD_ROOT:files", "src/python/pants/__main__.py"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also tried removing the //BUILD_ROOT:files
dependency from pants_integration_test.py
. But that didn't work, and it turned out to be a more invasive change.
Fixing this will require removing or changing tmpdir creation functions in this file that call get_buildroot()
repeatedly. We need to change that assumption so the test author can pass in the build root instead of having these functions calculate it from the current working directory, which happens to be the pytest sandbox.
I suspect this issue existed before #20887 (ie it is not a new bug in 2.22.x), but pants_integration_test
-based tests are far less common than RuleRunner
based tests. Since this is (probably) not a new bug, we can deal with changing the assumptions in this code at some later date.
|
||
# Change cwd and add sentinel file (BUILDROOT) so NativeOptionParser can find build_root. | ||
with pushd(self.build_root): | ||
Path("BUILDROOT").touch() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opted to use BUILDROOT
instead of BUILD_ROOT
so that anyone who needs to inspect a sandbox has a better idea where the file comes from (or can more easily grep for where it comes from).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't fully understand this comment. I'm fine with either one, but did you mean, using BUILDROOT in lieu of BUILD_ROOT so that it lines up with the other usages?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a BUILD_ROOT
file at the root of the pants repo. Some tests depend on that (//BUILD_ROOT:files
), so it gets copied to the root of the pytest sandbox.
Now, RuleRunner also adds a sentinel file to its own sandboxes. Using the variant with _
gives a subtle indicator of why the file is in the sandbox / what created the file; It gives a subtle indicator that the file is not a copy of the file that //:BUILD_ROOT:files
pulls in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm :)
Running SpecParser() at import time caused issues with tests that no longer have the BUILD_ROOT file in the sandbox (now that rule_runner does not depend on it).
This is where the test relied on the transitive dependency on //BUILD_ROOT via rule_runner. Since that dep had to be removed to avoid external plugin issues, we re-add it to tests that cannot easily be adjusted to work without it.
I'm slowly working through all of the test failures to fix them by either using |
name="tests", | ||
sources=["*_test.py", "!*_integration_test.py"], | ||
overrides={ | ||
"publish_test.py": {"timeout": 70}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hit a timeout locally where it took 60.5 seconds, but killed it at 60.3 seconds.
@contextmanager | ||
def pushd(self): | ||
with pushd(self.build_root): | ||
yield |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A new convenience API method for use in tests (and in the rule_runner itself).
@@ -24,7 +24,6 @@ python_sources( | |||
"pants_integration_test.py": { | |||
"dependencies": ["//BUILD_ROOT:files", "src/python/pants/__main__.py"] | |||
}, | |||
"rule_runner.py": {"dependencies": ["//BUILD_ROOT:files"]}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the fix that makes the errors in external repos visible in the pants repo.
Tests are passing now. @benjyw I would like your feedback on this before I merge it and cherry-pick it to 2.22.x. |
High level, I don't have a good understanding of the originating problem but the changes themselves seem mostly mechanical. I see green checkmarks, so I'm fine with that. The I'm kinda curious for @benjyw's thoughts on this, as I think he wrote the new native options parser - so I just want to ensure we're not working around something that should be handled at the Rust layer? |
👍 The linked slack conversation has a bit more context. Working on this proved confusing for me too.
I don't much care for it either. I tried (unsuccessfully) to encapsulate all of the wonky cwd management logic within the
I wonder about doing something in the rust layer too. It seems like we need a way for tests to tell the rust layer what the build_root should be, without requiring the sentinel file. The python layer has that feature, so adding it to the rust layer sounds reasonable. But I'm not confident enough with rust to pull that off. I started in that direction, confused myself in the process, and then asked @benjyw which solution he preferred (rust api to override build_root detection or sentinel file in the sandbox) -- he said to add the sentinel file to the sandbox. Adding the sentinel file ended up being somewhat convoluted as well. So, I'm not sold that this is better than something in the rust layer. But, it at least gets tests to fail like they do in external repos, and then patches up the fallout in the pants repo. So, it's probably good enough for a 2.22.x backport, which I think needs to happen before 2.22.0 final is released. |
I agree with @sureshjoshi about this being mostly of the bandaid kind. The better approach I think would be to not rely on CWD as much as we do now (historically, it was assumed that CWD was always the same as the build root) -- this being the case have added some hoops to jump through for tests that exercises pants from a test sandbox, as then the CWD is not the build root. Those hoops are now starting to fall apart with the move of options into rust land, so this fix mends that by maintaining the assumption about the relationship of CWD with build root, rather than getting rid of the assumption (which I think would be the preferred solution long term, but is likely significantly more work to get done, so I'm 👍🏽 with this as a stop gap in the mean time). My $.02 :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved based on the latest context/comments from @cognifloyd and @kaos
Might be something to review later, but the fact that in-repo plugin tests are broken is pretty important too
After #20887 (pants 2.22.0.dev2),
RuleRunner
-based tests do not work in external repos:https://pantsbuild.slack.com/archives/C0D7TNJHL/p1719344475216619
This test run shows the
ValueError
s that show up inRuleRunner
-based tests:https://github.com/StackStorm/st2/actions/runs/9667956659/job/26670955784
The tests were passing in the pants repo because
rule_runner.py
had an explicit dependency on//BUILD_ROOT:files
. So, theBUILD_ROOT
file was added to the pytest sandbox for everyRuleRunner
-based test. Removing therule_runner.py
dependency on//BUILD_ROOT:files
causes theRuleRunner
-based tests to fail in the pants repo as well.This issue was exposed because the rust-based
NativeOptionParser
does not provide an API for overriding theBuildRoot
, unlike the python layer which uses a singletonBuildRoot
object and allows RuleRunner to replace the build_root, bypassing the sentinel file-lookup logic. TheNativeOptionParser
requires either thePANTS_BUILDROOT_OVERRIDE
env var or a sentinel file (one ofBUILD_ROOT
,BUILDROOT
, orpants.toml
) in the current working directory (or a parent of the current working directory) to calculate the build_root.This PR:
//BUILD_ROOT:files
for some tests that do not actually require it.//BUILD_ROOT:files
fromtestutil/rule_runner.py
.RuleRunner
change the current working directory to the temporary build_root directory while bootstrapping options (ie for the codepaths that initialize the rust-basedNativeOptionParser
).RuleRunner
add the sentinel file in the temporary build_root directory thatRuleRunner
creates soNativeOptionParser
can find it in the current working directory.RuleRunner.pushd()
api method to allow tests to change the current directory toRuleRunner.build_root
.//BUILD_ROOT:files
for tests that relied on the transitive dep viatestutil/rule_runner.py
. These tests either did not useRuleRunner
(eg they only usedmock_console
), or relied on working in the sandbox with the actual pants code under test (meaning the pytest sandbox IS the build_root for that test).