jbang info tools does not report errors
create file:
//DEPS org.h2database:h2:2.2.224
//DEPS jakarta.data:jakarta.data-api:1.0.1
//DEPS org.hibernate.orm:hibernate-core:7.0.2.Final
//DEPS org.hibernate.orm:hibernate-jpamodelgen:7.0.2.Final
jbang test.jsh says:
[jbang] Resolving dependencies...
[jbang] org.h2database:h2:2.2.224
[jbang] [ERROR] Could not read artifact descriptor for org.h2database:h2:jar:2.2.224
but
[jbang] Resolving dependencies...
[jbang] org.h2database:h2:2.2.224
[jbang] [WARN] Unable to obtain full information, the script probably contains errors
{
"originalResource": "/Users/max/.jbang/cache/stdins/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42.jsh",
"backingResource": "/Users/max/.jbang/cache/stdins/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42.jsh",
"dependencies": [
"org.h2database:h2:2.2.224",
"jakarta.data:jakarta.data-api:1.0.1",
"org.hibernate.orm:hibernate-core:7.0.2.Final",
"org.hibernate.orm:hibernate-jpamodelgen:7.0.2.Final"
],
"availableJdkPath": "/Users/max/.sdkman/candidates/java/25-graal",
"compileOptions": [
"-g",
"-parameters"
],
"sources": [
{
"originalResource": "/Users/max/.jbang/cache/stdins/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42.jsh",
"backingResource": "/Users/max/.jbang/cache/stdins/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42/6c6b5981e85a822544a583681542ee5fbc7b492daaaed304c614fa0738b48d42.jsh"
}
],
"docs": {}
it should contain info about that error.
#2069 introduced it for files / resources but seem we missed it for dependencies
It does when you run it with --verbose. But we could simply add the message of the underlying error to the warning text.
Short reproducer without having to create any files: jbang info tools --deps org.h2database:h2:2.2.224 itests/helloworld.java
Btw. This is super annoying when using jbang in jupyter as it doesn't get the error stream so it only gets what's in the JSON
Ok, but what do you want in that case? Add like a "dependencyResolutionError" field or something?
Edit: I'm asking because normally the absence of the resolvedDependencies array means that something went wrong. There's just no information about what went wrong.
I think we want to record a "errors" list in the output.
having to look both in output and parse stderr as well as .json is going to be too error prone
we had a unit test in jbang-eclipse that covered this use case:
https://github.com/jbangdev/jbang-eclipse/blob/a2a7968eb1d4c20b9fcfc6ca8326abc121ff9c69/dev.jbang.eclipse.test/src/main/java/dev/jbang/eclipse/core/internal/ImportScriptTest.java#L36-L55
the script in question: https://github.com/jbangdev/jbang-eclipse/blob/main/dev.jbang.eclipse.test/scripts/brokendeps.java
The unit test fails now with recent jbangs.
Another failing test case, for local missing dependency jars:
https://github.com/jbangdev/jbang-eclipse/blob/main/dev.jbang.eclipse.test/scripts/brokendeps2.java
https://github.com/jbangdev/jbang-eclipse/blob/a2a7968eb1d4c20b9fcfc6ca8326abc121ff9c69/dev.jbang.eclipse.test/src/main/java/dev/jbang/eclipse/core/internal/ImportScriptTest.java#L55-L70
@fbricon is this not more due to #2069 where we stopped hard failing in info tools and instead have json be reported even if there are issues?
this one is about enhancing the json with info about errors observed.
I think we want to record a "errors" list in the output.
Sure, we can do that. Although for tools it might not be as obvious what the error affects.
Let me explain, if we have dependencies and the resolving goes wrong, for some reason, then we'd add the error to that list and there's be no "resolvedDependencies" element in the json output. You a tool could say: hey the error is probably something to do with the dependencies because "resolvedDependencies" is missing. But! It could also be that something failed before that and we never got to the part where we resolve dependencies.
For humans reading the error message it's probably obvious, but for let's say an IDE plugin it might not be. So the advantage of having a "dependencyResolutionError" element might be that a tool can make more intelligent decisions based on the extra information.
But it's something minor, if you prefer "errors" we do a simple error list.
having to look both in output and parse stderr as well as .json is going to be too error prone
I agree.
jbang --version 0.132.1
for brokendeps.java, there's no error at all, just a vague warning:
jbang info tools brokendeps.java
[jbang] Resolving dependencies... [jbang] com.github.lalyos:jfiglet:6.6.6 [jbang] [WARN] Unable to obtain full information, the script probably contains errors { "originalResource": "brokendeps.java", "backingResource": "/Users/fbricon/Dev/projects/jbang-eclipse/dev.jbang.eclipse.test/scripts/brokendeps.java", "applicationJar": "/Users/fbricon/.jbang/cache/jars/brokendeps.java.7080704be6aec19b968b0dac6c0c2ab5560236480ec958d7255776b1cf5a4e54/brokendeps.jar", "dependencies": [ "com.github.lalyos:jfiglet:6.6.6" ], "availableJdkPath": "/Users/fbricon/.sdkman/candidates/java/25-tem", "compileOptions": [ "-g", "-parameters" ], "sources": [ { "originalResource": "brokendeps.java", "backingResource": "/Users/fbricon/Dev/projects/jbang-eclipse/dev.jbang.eclipse.test/scripts/brokendeps.java" } ], "docs": {} }
for brokendeps2.java, jbang fails hard:
jbang info tools brokendeps2.java [jbang] [ERROR] Cannot invoke "dev.jbang.resources.ResourceRef.getFile()" because "resourceRef" is null [jbang] Run with --verbose for more details. The --verbose must be placed before the jbang command. I.e. jbang --verbose run [...]
we were able to handle both cases in jbang-eclipse in the past.
for brokendeps.java, there's no error at all, just a vague warning:
This is by design, if there's no "resolvedDependencies" element then something went wrong while trying to resolve the dependencies. Yes, right now you won't get the actual error, but you'll get all the other information while in older versions of JBang the entire info tools call would fail and you'd get zero information besides the error.
for brokendeps2.java, jbang fails hard:
This error is definitely unfortunate, I'll look into it. But I'm pretty sure old JBang versions would also "fail hard", just with a different error.
Ok, the brokendeps2.java issue is definitely a nasty bug that we'll need to fix ASAP: #2251
Turns out we have no tests for that!
for brokendeps.java, there's no error at all, just a vague warning:
This is by design, if there's no "resolvedDependencies" element then something went wrong while trying to resolve the dependencies. Yes, right now you won't get the actual error, but you'll get all the other information while in older versions of JBang the entire
info toolscall would fail and you'd get zero information besides the error.
maybe so but at last I knew that particular dependency caused an error in the past, now I don't.
You a tool could say: hey the error is probably something to do with the dependencies because "resolvedDependencies" is missing. But! It could also be that something failed before that and we never got to the part where we resolve dependencies.
that isn't really how the tools would deal with it - it will just read the errors and get the context /error from them. So its more like:
- run the jbang command
- get resolvedDependencies and apply if available
- get errors and report on them
so if errors can be structured like:
"errors": [
{"message": "Could not resolve dep x.y.z ...",
"exception": "<printstacktrace> of exception if/when relevant"
}
]
maybe even make it "issues" and have a "type": "warning|error" then tools don't even require trying to parse stderr...
could even over time add "details" with map of additional info over time if need be.
it will just read the errors and get the context /error from them
Sure, just saying that you won't always be able to detect why "resolvedDependencies" wasn't there. If all you care about if there was an error or not and be able to display that error to the user then it's enough to have an "error" field.
so if errors can be structured like
Actually, there isn't really a possibility of having multiple errors, either we can get full information or we can't. So there's only ever the possibility of a single exception occurring. The only other "issues" are missing (re)sources, but they already get handled on an individual basis in their respective (re)source lists. (All (re)sources are already structured elements with an original reference and either a link to the actual file or an error explaining why the (re)source couldn't be retrieved.)
So a single "error" element would actually be sufficient.
(Which would make the "project" json somewhat compatible with the "resource" json, because both would have an "originalResource" field and either a "backingResource" or an "error" field) Which is somewhat logical because a project is obtained from a resource after all).
So a single "error" element would actually be sufficient.
what if error happens when collecting the referenced jars or source projects?
those would be in addition to the maven resolve?
(Which would make the "project" json somewhat compatible with the "resource" json, because both would have an "originalResource" field and either a "backingResource" or an "error" field) Which is somewhat logical because a project is obtained from a resource after all).
not following this? can you give example?
So a single "error" element would actually be sufficient.
what if error happens when collecting the referenced jars or source projects?
those would be in addition to the maven resolve?
No, not in addition to, any issue in resolving dependencies, be it Maven or downloading a Jar or trying to obtain a source project will fail the entire process. (In the end it's a single call to DependencyResolver.resolve())
Now theoretically we could implement it so obtaining remote jars and compiling source projects would be handled as independent steps whose success doesn't affect the others, but given the fact that Maven resolving is all-or-nothing it didn't seem to make sense to go through all that effort for basically no gain. (We'd need a Maven resolver that would tell us per dependency if it was successful or not and not stop if it encounters an error. Probably doable, but again, not sure if it would be worth the effort)
(Which would make the "project" json somewhat compatible with the "resource" json, because both would have an "originalResource" field and either a "backingResource" or an "error" field) Which is somewhat logical because a project is obtained from a resource after all).
not following this? can you give example?
It's a minor technical detail. RIght now the output of info tools has the following fields:
{
"originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java",
"backingResource": "C:\\Users\\tako\\.jbang\\....\\hello.java",
.
.
.
"sources": [
{
"originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java",
"backingResource": "C:\\Users\\tako\\.jbang\\...\\hello.java"
}
],
.
.
.
}
You see both at the top level and in sources (as well as resources and docs, not shown here) the same 2 entries, originalResource and backingResource, which correspond to the same fields in the ResourceRef class.
Any time we can't find or retrieve a resource we get this instead:
"files": [
{
"originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java",
"error": "not resolvable from Chain of [ResourceRef: itests/brokenresource.java (C:\\Projects\\jbang\\jbang\\itests\\brokenresource.java) of File Resource resolver, A trusting resource resolver]"
}
],
So if we only have a single "error" element at the top level we maintain some consistency and perhaps make it a little bit easier to write code/scripts that deal with resources and errors.
{
"originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java",
"backingResource": "C:\\Users\\tako\\.jbang\\....\\hello.java",
.
.
.
"error": "Could not read artifact descriptor for org.h2database:h2:jar:2.2.224",
}
But like I said, it's a very technical detail
I need that "Could not read artifact descriptor for org.h2database:h2:jar:2.2.224" message so I can parse it to extract the missing dependency id. Ideally that message format won't change if you change the underlying resolver.
No, not in addition to, any issue in resolving dependencies, be it Maven or downloading a Jar or trying to obtain a source project will fail the entire process. (In the end it's a single call to
DependencyResolver.resolve())
Thats as long as these are all handled by //DEPS but as discussed in https://github.com/jbangdev/jbang/pull/2252#discussion_r2435191169 its not a full given we keep that given there are distinct separate/dfiferent behaviors in play for those different kinds.
Now theoretically we could implement it so obtaining remote jars and compiling source projects would be handled as independent steps whose success doesn't affect the others, but given the fact that Maven resolving is all-or-nothing it didn't seem to make sense to go through all that effort for basically no gain. (We'd need a Maven resolver that would tell us per dependency if it was successful or not and not stop if it encounters an error. Probably doable, but again, not sure if it would be worth the effort)
I'm not suggesting we do have maven resolver do it for each individual artifact - just that its not a given that there will only be one error produced.
ignoring source/jar situation - lets say we use the new maven 4 concurrent resolver download - then a resolve could result in multiple resolves failing.
(Which would make the "project" json somewhat compatible with the "resource" json, because both would have an "originalResource" field and either a "backingResource" or an "error" field) Which is somewhat logical because a project is obtained from a resource after all).
not following this? can you give example?
It's a minor technical detail. RIght now the output of
info toolshas the following fields:{ "originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java", "backingResource": "C:\\Users\\tako\\.jbang\\....\\hello.java", . . . "sources": [ { "originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java", "backingResource": "C:\\Users\\tako\\.jbang\\...\\hello.java" } ], . . . }You see both at the top level and in sources (as well as resources and docs, not shown here) the same 2 entries,
originalResourceandbackingResource, which correspond to the same fields in theResourceRefclass.Any time we can't find or retrieve a resource we get this instead:
"files": [ { "originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java", "error": "not resolvable from Chain of [ResourceRef: itests/brokenresource.java (C:\\Projects\\jbang\\jbang\\itests\\brokenresource.java) of File Resource resolver, A trusting resource resolver]" } ],So if we only have a single "error" element at the top level we maintain some consistency and perhaps make it a little bit easier to write code/scripts that deal with resources and errors.
{ "originalResource": "https://github.com/jbangdev/jbang-catalog/blob/HEAD/hello.java", "backingResource": "C:\\Users\\tako\\.jbang\\....\\hello.java", . . . "error": "Could not read artifact descriptor for org.h2database:h2:jar:2.2.224", }But like I said, it's a very technical detail
Ok - get it now but its not really "same" given the files refer to error specifci to that resource, where the error at toplevel would not necessarily relate to that file (could be any other file in the project)
No, not in addition to, any issue in resolving dependencies, be it Maven or downloading a Jar or trying to obtain a source project will fail the entire process. (In the end it's a single call to
DependencyResolver.resolve())Thats as long as these are all handled by
//DEPSbut as discussed in #2252 (comment) its not a full given we keep that given there are distinct separate/dfiferent behaviors in play for those different kinds.
Sure, but even if they were distinct, we'd somehow have to decide to continue "doing stuff" after an error has occurred... and for what?
ignoring source/jar situation - lets say we use the new maven 4 concurrent resolver download - then a resolve could result in multiple resolves failing.
Yes, but would we get multiple exceptions? I'd assume we'd still use a single DependencyResolver.resolve() call that can either return a result or throw an exception. I'd assume that if you want to track what happened during download you'll have to program against some new API that will give much more information. But I'm still not sure why'd we want to go through the trouble?
But like I said, it's a very technical detail
Ok - get it now but its not really "same" given the files refer to error specifci to that resource, where the error at toplevel would not necessarily relate to that file (could be any other file in the project)
I'd argue that the existence of an "error" field means something went wrong in retrieving/creating that ... thing. If it's a source or file we weren't able to retrieve it. Why? Well it could be any number of things. Invalid path or url, file doesn't exist, connection problems, memory issues, etc If the resource is a project it's the same, we were not able to retrieve all the project information because some error occurred. In both cases the cause of the error can be anything but it's related to retrieving/creating the resource that was referenced.
But .... I'm not going to defend this any further, we can simply do errors: [ ], no problem. It'll have a single entry for now, but at least it can be expanded in the future.