-
Notifications
You must be signed in to change notification settings - Fork 135
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
Log Sorbet signature block errors that lead to misleading RBI signatures generated #1980
Conversation
a131c53
to
60a1b1d
Compare
@paracycle - I've updated the approach to follow the Thanks for your help! |
c2560fb
to
5971c43
Compare
lib/tapioca/gem/pipeline.rb
Outdated
gem, | ||
include_doc: false, | ||
include_loc: false, | ||
error_handler: $stderr.method(:puts).to_proc |
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 think I'd prefer this to be a required keyword argument. Coincidentally, I think that will force you to add support for an error handler for the gem/pipeline_spec
tests, which in turn should allow you to properly test this case as a unit test inside that file.
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.
Sounds good. As long as the general design is looking ok, I'll do another pass to make sure that everything is fully covered with tests.
@paracycle - I've updated the approach based on your last feedback. Let me know if the general design matches your expectations and I can go through and add tests. One thing I was considering, but do not have the time for in this PR: it might be nice for that |
de7051e
to
919ac12
Compare
@@ -65,7 +65,7 @@ def symbols_from_paths(paths) | |||
|
|||
private | |||
|
|||
sig { returns(T::Array[T.class_of(Rails::Engine)]) } | |||
T::Sig::WithoutRuntime.sig { returns(T::Array[T.class_of(Rails::Engine)]) } |
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.
NOTE: the T::Sig::WithoutRuntime
is needed because tapioca itself does not directly depend on Rails, but will attempt to generate signatures for this method for projects that do not include Rails, and trigger an sig block exception to be logged.
@@ -230,7 +230,7 @@ def require_helper(file) | |||
# The `eager_load_paths` method still exists, but doesn't return all paths anymore and causes Tapioca to miss some | |||
# engine paths. The following commit is the change: | |||
# https://github.com/rails/rails/commit/ebfca905db14020589c22e6937382e6f8f687664 | |||
sig { params(engine: T.class_of(Rails::Engine)).returns(T::Array[String]) } | |||
T::Sig::WithoutRuntime.sig { params(engine: T.class_of(Rails::Engine)).returns(T::Array[String]) } |
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.
NOTE: the T::Sig::WithoutRuntime
is needed because tapioca itself does not directly depend on Rails, but will attempt to generate signatures for this method for projects that do not include Rails, and trigger an sig block exception to be logged.
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.
Thank you for your recent changes, this is looking really good. I have a small test improvement suggestion.
spec/tapioca/gem/pipeline_spec.rb
Outdated
sig { params(gem_name: String, include_doc: T::Boolean, include_loc: T::Boolean).returns(String) } | ||
def compile(gem_name = DEFAULT_GEM_NAME, include_doc: false, include_loc: false) | ||
sig { params(gem_name: String, include_doc: T::Boolean, include_loc: T::Boolean, error_handler: T.proc.params(error: String).void).returns(String) } | ||
def compile(gem_name = DEFAULT_GEM_NAME, include_doc: false, include_loc: false, error_handler: ->(err) {}) |
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 would very much like it if the default behaviour of the error handler was to collect the errors, and, after the compilation is done, to assert that the list of collected errors is empty.
That would be a free negative assertion for all the tests that we don't expect to fail, and the behaviour could be easily overriden by passing an alternative error handler, like how you are doing in the added test.
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 like it and can include this change as well. Thanks!
@paracycle - I've updated the specs to include a negative assertion for all the tests that we don't expect to fail and fixed the failing rubocop linting. Let me know if there is anything else you think this needs. Thanks again for all of your help! |
c9ab842
to
8ba5ee1
Compare
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.
Thank you for all the work on this PR. I am really happy with the result, except for a minor comment.
8ba5ee1
to
88e872e
Compare
@paracycle - I've just addressed the lingering test state for the |
Hmm... the CI failure seems unrelated to my changes. Is there any chance someone can retrigger the build, or should I attempt to force-push an update to trigger another build? |
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 reran the failed tests, seems to be related to an infrastructure issue
@phil-monroe Funny story: It turns out that about 3 years ago, I'd discovered that the exception swallowing behaviour of I will rebase that PR on top of this work and ship it finally. Thanks for the reminder :) |
Ha, I totally get it. Thanks for all of your help and feel free to reach out if need any help validating additional changes in the future. The one follow on feature request I kind of wish tapioca had related to these changes: What if the compiled RBIs also documented the raised exception details in the generated RBIs? That way, if you miss the log messages but go to look at the RBIs while debugging, there is still a historical record that something was indeed wrong with the compilation phase. Thoughts? |
Sure, that is also a good idea. I've been wanting Tapioca to generate more comments on generated methods, especially for DSL RBI methods, explaining why the method is being defined, for a long time. For example, It would definitely be good to note warning/error like messages there, those that aren't bad enough to stop generating RBIs but important enough to have more visibility. I guess the main question would be how to make it explicit that the comment that is added is not part of the comment that we extract from the source method definition, but that might a good thing to discuss in detail. Do you mind opening an issue for this? |
Yeah, I like that concept, and happy to create a dedicated issue to discuss more! Thanks again for all of your help @paracycle ! |
Motivation
When a sorbet signature block ends up throwing an exception, it gets swallowed up by the
signature_for(method)
in theTapioca::Runtime::Reflection
utilities, and an incorrect signature is generated. This has created some confusion for my team when the sorbet type checking failed, even though it appeared as if the signature was implemented correctly.Example
Sorbet Interface in upstream gem
NOTE: the dependency/require statements on the
ExampleContracts::WidgetDto
had a simple bug that led to it being defined in most scenarios, but was not happing in the tapioca run downstream from these packages.Tapioca generated RBI for interface defined upstream
NOTE: Tapioca does not log any errors or warnings when generating this RBI.
Example sorbet error
As you can see, the original implementation of the
Example::WidgetAdapter
indeed seemingly does have a signature defined, but the swallowed exception in Tapioca leads to a misleading RBI generated and a sorbet type-checking error.Implementation
Log any errors raised to
$stderr
when reflecting on method signatures to increase developer visibility + understanding.With this change in place, you will now see a logged error message like the following:
Tests
Tests have been added and/or modified to check for the reported errors.