make new-app error reports clearer#12978
Conversation
pkg/generate/app/cmd/newapp.go
Outdated
| remote, err := app.IsRemoteRepository(s) | ||
| c.ArgumentClassificationErrors["Remote access"] = err | ||
| local, err := app.IsDirectory(s) | ||
| c.ArgumentClassificationErrors["Local access"] = err |
There was a problem hiding this comment.
shouldn't this whole block be protected by the if !validated condition, to mimic the switch behavior?
There was a problem hiding this comment.
also only set the classification errors is err!=nil
There was a problem hiding this comment.
I was originally that way (whole block, etc .etc.), and then broke slightly from that norm in this sense:
- The information as to whether the arg satisfied any of the tests seemed useful to me
- note I don't update the
c.Componentsetc. for any of the subsequent classifications on a match has been made ... in that sense I preserve the switch behavior
There was a problem hiding this comment.
And on classificatnoi errors and err != nil, again, that was intentional. If a classification passed, I wanted it illustrated by the fact that the error field was nil. If I don't add a key / nil err pair, then unless you know the entire list of classifications, you don't know what has passed if we only list the actual errors.
There was a problem hiding this comment.
I'm not sure how the additional information is useful since there's nothing the user can do about it (eg if we think it's an environment variable, it doesn't really matter if we also think it's a source repo, or are sure it's not a source repo because of error X, it's still going to get processed/consumed as an environment variable).
If anything it may just lead to more confusion since anytime new-app fails overall(for unrelated reasons), it's going to print out messages talking about the error it got when trying to treat an env variable argument as a source repo.
There was a problem hiding this comment.
And on classificatnoi errors and err != nil, again, that was intentional. If a classification passed, I wanted it illustrated by the fact that the error field was nil. If I don't add a key / nil err pair, then unless you know the entire list of classifications, you don't know what has passed if we only list the actual errors.
yeah i sort of figured that was the intention, but for an end user it's a pretty ugly/confusing output. I might be convinced of keeping the nil value and doing better processing when printing the errors out to reformat the "nil" to something more informative to the user, but overall I think doing anything with it is tipping too far on the side of "what gabe+ben want to see to debug the problem" and not "what is useful to a user to see to know what they should do to fix it". For example "Component reference" means nothing at all to an end user.
There was a problem hiding this comment.
After some internal ping-pong, I landed on not feeling strongly enough to dig in one side or the other :-) I'll switch back to the closer mimic of the switch behavior.
pkg/generate/app/cmd/newapp.go
Outdated
| validated = true | ||
| } | ||
|
|
||
| err = app.IsComponentReference(s) |
There was a problem hiding this comment.
same here, guard with if !validated
pkg/generate/app/cmd/newapp.go
Outdated
| } | ||
|
|
||
| err = app.IsComponentReference(s) | ||
| c.ArgumentClassificationErrors["Component reference processing"] = err |
There was a problem hiding this comment.
only set this if err!=nil?
pkg/generate/app/cmd/newapp.go
Outdated
| } | ||
|
|
||
| rc, err = app.IsPossibleTemplateFile(s) | ||
| c.ArgumentClassificationErrors["Template processing"] = err |
pkg/cmd/cli/cmd/newapp.go
Outdated
| transformError(err, baseName, commandName, commandPath, groups) | ||
| } | ||
| buf := &bytes.Buffer{} | ||
| fmt.Fprintf(buf, "Prior to API Object processing, here were the results from application argument classification:\n") |
There was a problem hiding this comment.
only print this if len(config.ArgumentClassificationErrors)>0
(in conjunction w/ not adding things to that map unless the value is non-nil, as mentioned below)
There was a problem hiding this comment.
OK ... still debating the suggestions above, I agree with the len check.
pkg/cmd/cli/cmd/newapp.go
Outdated
| for key, value := range config.ArgumentClassificationErrors { | ||
| fmt.Fprintf(buf, fmt.Sprintf("\n%s: %v\n", key, value)) | ||
| } | ||
| fmt.Fprint(buf, "\n\nThen, the following errors were noted during API Object processing:\n\n") |
There was a problem hiding this comment.
s/noted/occurred/ but this test will also have to be reworked to account for the possibility that it is the first output, once you make the change i suggested above.
There was a problem hiding this comment.
Will do rewording ... agreement on above suggestions still pending
|
What the heck is "API Object processing" and why is it showing up in an error message to an end user? |
|
:-) It was my attempt to categorize/summarize the fact that Prior to the REST interactions with the master that result in creation, there is client side interpretation of the arguments that result in git invocations, file system checks, that could or could not fail for various reasons. I tasked with exposing those failures for debug when That opening phrase was an attempt to provided context. But of course suggestions to change are appreciated (assuming you agree with exposing those errors if the command fails). |
|
Perhaps replace the entire fist sentence with: "Attempts to classify the arguments resulted in these errors:" The for the next sentence go with "The following errors occurred after argument classification:" |
a4ae8a9 to
ff09cdc
Compare
|
Updates to @bparees comments pushed. Fixing "API Object processing" still pending ... waiting a bit to see what feedback arrives. |
pkg/cmd/cli/cmd/newapp.go
Outdated
| transformError(err, baseName, commandName, commandPath, groups) | ||
| } | ||
| buf := &bytes.Buffer{} | ||
| if config.ArgumentClassificationErrors != nil && len(config.ArgumentClassificationErrors) > 0 { |
There was a problem hiding this comment.
config.ArgumentClassificationErrors != nil is unnecessary: len(nil) == 0 in golang.
pkg/cmd/cli/cmd/newbuild.go
Outdated
| transformBuildError(err, baseName, commandName, commandPath, groups) | ||
| } | ||
| buf := &bytes.Buffer{} | ||
| if config.ArgumentClassificationErrors != nil && len(config.ArgumentClassificationErrors) > 0 { |
There was a problem hiding this comment.
config.ArgumentClassificationErrors != nil is unnecessary: len(nil) == 0 in golang.
There was a problem hiding this comment.
part of next push
pkg/generate/app/cmd/newapp.go
Outdated
| continue | ||
| } | ||
|
|
||
| // had to move off of elegant switch to capture errors for future display, but mimic |
There was a problem hiding this comment.
This seems more like a commit comment than a code comment ;)
There was a problem hiding this comment.
It certainly is .... between your comment and the exchange I had with @bparees, I believe the explanation has been sufficiently proliferated :-)
deleted with next push
| unknown := []string{} | ||
| c.ArgumentClassificationErrors = map[string]error{} | ||
| for _, s := range args { | ||
| switch { |
There was a problem hiding this comment.
If you're ditching the switch statement, can you refactor into a separate function which then allows you to avoid all the nested ifs? i.e.:
if foo {
// something
return
}
if bar {
// something else
return
}
rather than
if foo {
// something
} else {
if bar {
// something else
} else {
if baz ...
}
}
There was a problem hiding this comment.
actually, the refactor into functions made me realize I could preserve the switch - thanks!... part of next push
|
Comments added. For what my view is worth, I feel pretty reluctant about this change on the basis that it feels like it's building more stuff on top of our shaky foundations and locking us more into them. I'm concerned this will make future code maintenance/cleanup harder, rather than easier. If possible, I'd sooner see one of the following:
|
ff09cdc to
023acd6
Compare
|
Updates pushed include:
On @jim-minter 's concerns outside of the code change comments:
My two cents. @bparees - based on the responses from various folks, where's your head wrt this? |
|
I still want to see this done, the current experience is bad.
i'm not sure what is particularly heavyweight about this, curious if the changes resulting from your feedback make you feel any better about it.
definitely not a fan of this, the current error behavior is pretty baffling to users. (and this PR spawned from a user issue in which the user was so confused by the behavior that they thought new-app didn't support ip address based source repos)
i'm not against also doing this, at this point i'm sure a lot of us have a mental wishlist of "if i was writing new-app from scratch...." and it would certainly not hurt to have that written down.
that's what --code, --template, --image, etc are for. and it is true that in the case of the original issue the user hit, if they'd rerun the command w/ --code they'd have gotten a more useful error: but obviously this user did not understand the failure they'd hit sufficiently to realize new-app had mis-categorized the argument and that telling new-app what the arg type was might get them more information...so i'm not convinced that's a sufficient solution (as evidenced by it not having been sufficient for the user who hit this) |
pkg/cmd/cli/cmd/newapp.go
Outdated
| } | ||
| buf := &bytes.Buffer{} | ||
| if len(config.ArgumentClassificationErrors) > 0 { | ||
| fmt.Fprintf(buf, "Attempts to classify the arguments resulted in these errors:\n") |
There was a problem hiding this comment.
"Errors occurred while determining argument types:"
There was a problem hiding this comment.
part of next push
pkg/cmd/cli/cmd/newapp.go
Outdated
| for key, value := range config.ArgumentClassificationErrors { | ||
| fmt.Fprintf(buf, fmt.Sprintf("\n%s: %v\n", key, value)) | ||
| } | ||
| fmt.Fprint(buf, "\nThe following errors occurred during application creation:\n") |
There was a problem hiding this comment.
"Errors occurred during resource creation:"
There was a problem hiding this comment.
part of next push
pkg/cmd/cli/cmd/newapp.go
Outdated
| } | ||
|
|
||
| func handleRunError(err error, baseName, commandName, commandPath string) error { | ||
| func handleRunError(err error, baseName, commandName, commandPath string, config *newcmd.AppConfig) error { |
There was a problem hiding this comment.
the only difference between this and handleBuildError is which function is invoked for transformation...seems like an opportunity to collapse some code (pass the transform function in as an argument)
There was a problem hiding this comment.
(and might make @jim-minter feel better about the weight of the changes :) )
There was a problem hiding this comment.
part of next push
pkg/cmd/cli/cmd/newbuild.go
Outdated
| fmt.Fprint(buf, "\nThe following errors occurred when creating a build from source code:\n") | ||
| } | ||
| for _, group := range groups { | ||
| //TODO how coupled are we to kcmdutil.MultipleErrors ... format is compressed, non-optimal readability |
There was a problem hiding this comment.
i'm not seeing a current need to change it.
pkg/generate/app/cmd/newapp.go
Outdated
| c.Components = append(c.Components, s) | ||
| return true | ||
| } | ||
| c.ArgumentClassificationErrors["Component reference processing"] = err |
There was a problem hiding this comment.
i'd like to see another term used here that will have meaning to the user. I think this is essentially checking if the value is either:
- an image
- an imagestreamtag
- a template that exists in the cluster(?)
if it weren't for 3 this would be easier to fix.
There was a problem hiding this comment.
I'll work off of the terminology in the suggestion
pkg/generate/app/cmd/newapp.go
Outdated
| } | ||
|
|
||
| if derr != nil { | ||
| c.ArgumentClassificationErrors["Local access"] = derr |
There was a problem hiding this comment.
these two error keys don't make it clear the failure was related to trying to treat the argument as a source repo. (remote access to what? local access to what?)
There was a problem hiding this comment.
I'll work off of the terminology in the suggestion
pkg/generate/app/cmd/newapp.go
Outdated
| case c.addEnvironmentArguments(s): | ||
| case c.addSourceArguments(s): | ||
| case c.addComponentArguments(s): | ||
| case c.addTemplateArguments(s): |
There was a problem hiding this comment.
if the user passes multiple arguments, this error accumulation and reporting logic breaks down. You need to accumulate the ArgumentClassificationErrors on a per argument basis.
There was a problem hiding this comment.
yep I'll include the arg string in the key - good catch
test/cmd/newapp.sh
Outdated
| os::cmd::expect_failure_and_text 'oc new-app https://githb.com/openshift/nodejs-e' 'Remote access: ' | ||
| os::cmd::expect_failure_and_text 'oc new-build --strategy=docker https://192.30.253.113/openshift/ruby-hello-world.git' 'Remote access: ' | ||
| os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'Remote access: ' | ||
| os::cmd::expect_failure_and_text 'oc new-build https://githb.com/openshift/nodejs-e' 'Remote access: ' |
There was a problem hiding this comment.
add a test w/ multiple arguments that all fail.
There was a problem hiding this comment.
part of next push
023acd6 to
75cabce
Compare
|
responses to latest @bparees comments pushed |
pkg/cmd/cli/cmd/newapp.go
Outdated
| } | ||
|
|
||
| func handleRunError(err error, baseName, commandName, commandPath string) error { | ||
| func handleError(err error, baseName, commandName, commandPath string, config *newcmd.AppConfig, f func(err error, baseName, commandName, commandPath string, groups errorGroups)) error { |
There was a problem hiding this comment.
rename f to transformError?
There was a problem hiding this comment.
sure more informative less terse ... part of next push
pkg/cmd/cli/cmd/newapp.go
Outdated
| for key, value := range config.ArgumentClassificationErrors { | ||
| fmt.Fprintf(buf, fmt.Sprintf("\n%s: %v\n", key, value)) | ||
| } | ||
| fmt.Fprint(buf, "\nErrors occurred during resource creation:\n") |
There was a problem hiding this comment.
Should this be split so printing the \n is inside the if clause and printing the rest of the text outside?
There was a problem hiding this comment.
Yeah I debated putting the "Errors occurred during resource creation:" in even if there were no ArgumentClassificationErrors, simply to add some context and clarification around the terse kcmdutil.MultipleErrors output.
You've tipped me in that direction. Part of next push.
pkg/generate/app/cmd/newapp.go
Outdated
| c.Components = append(c.Components, s) | ||
| return true | ||
| } | ||
| c.ArgumentClassificationErrors[fmt.Sprintf("%s as a imagestream tag or docker image reference ", s)] = err |
There was a problem hiding this comment.
a->an in a imagestream tag
There was a problem hiding this comment.
part of next push
pkg/generate/app/cmd/newapp.go
Outdated
| OSClient client.Interface | ||
| OriginNamespace string | ||
|
|
||
| ArgumentClassificationErrors map[string]error |
There was a problem hiding this comment.
I wonder whether
ArgumentClassificationErrors []struct {
Key string
Value error
}
may prove better, to keep ordering of messages?
There was a problem hiding this comment.
hmm ... yeah, slightly more cumbersome to use, but the implementation does prescribe a precedence.
I'll prototype and see if it looks palatable.
There was a problem hiding this comment.
and then I'll be quiet :)
There was a problem hiding this comment.
:-)
change is palatable ... about to push
pkg/generate/app/cmd/newapp.go
Outdated
| return true | ||
| } | ||
| if err != nil { | ||
| c.ArgumentClassificationErrors[fmt.Sprintf("%s as a template in an accessible project", s)] = err |
There was a problem hiding this comment.
Is the text right given it says as possible template file above?
There was a problem hiding this comment.
part of next push
pkg/generate/app/cmd/newapp.go
Outdated
| case app.IsPossibleTemplateFile(s): | ||
| glog.V(2).Infof("treating %s as possible template file\n", s) | ||
| c.Components = append(c.Components, s) | ||
| case c.addEnvironmentArguments(s): |
There was a problem hiding this comment.
wonder whether calling these functions tryToAddFoo might make this a little clearer
There was a problem hiding this comment.
part of next push
|
@bparees pushed changes stemming from your last set of code comments and updated the sample outputs in the description |
pkg/cmd/cli/cmd/newapp.go
Outdated
| } | ||
| fmt.Fprint(buf, "\n") | ||
| } | ||
| fmt.Fprint(buf, "Errors occurred during resource creation:\n") |
There was a problem hiding this comment.
this should also be conditional on there actually being at least one resource creation error.
There was a problem hiding this comment.
The fact that we are in handleErrors at this point already ensures that there is at least one error. See the if err == nil return snippet at the top. I believe an additional check is redundant.
test/cmd/newapp.sh
Outdated
| os::cmd::expect_failure_and_text 'oc new-app https://githb.com/openshift/nodejs-e' 'as a GIT repository URL: ' | ||
| os::cmd::expect_failure_and_text 'oc new-build --strategy=docker https://192.30.253.113/openshift/ruby-hello-world.git' 'as a GIT repository URL: ' | ||
| os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'as a GIT repository URL: ' | ||
| os::cmd::expect_failure_and_text 'oc new-build https://githb.com/openshift/nodejs-e' 'as a GIT repository URL: ' |
There was a problem hiding this comment.
these all need to be fixed to Git
There was a problem hiding this comment.
doh!! .. the one time I didn't run test-cmd :-)
There was a problem hiding this comment.
script update pushed
7d0cce7 to
ab9137a
Compare
|
lgtm but we're going to need a final signoff from @smarterclayton on the error messaging. |
|
@smarterclayton bump on you take on updated error message examples in PR description - thanks |
ab9137a to
c0eaf6f
Compare
987dd12 to
0a11b3a
Compare
|
@smarterclayton bump for review of new error output. |
|
@openshift/cli-review ptal. |
pkg/cmd/cli/cmd/newapp.go
Outdated
| } | ||
| fmt.Fprint(buf, "\n") | ||
| } | ||
| fmt.Fprint(buf, "Errors occurred during resource creation:\n") |
There was a problem hiding this comment.
nit: fmt.Fprintln could be used instead
There was a problem hiding this comment.
switch to fmt.Fprintln pushed
|
@fabianofranz this lgtm from a cli perspective |
|
thanks @juanvallejo |
|
[Test]ing while waiting on the merge queue |
|
Looks like a new-app extended test is not happy: Didn't realize this extended test existed. I believe it is getting confused by the new, additional error messages that were added. I'll start working on an update to the extended test to account for the new messages. |
|
Looks like something happened with pkg/generate/app/cmd/newapp_test.go after one of the rebases. Will need to address that too. |
|
OK fixes to those two items pushed. [test] |
|
Evaluated for origin test up to 5fa0f68 |
|
[merge] |
|
continuous-integration/openshift-jenkins/test SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pull_requests_origin_future/870/) (Base Commit: 5e64198) |
|
Evaluated for origin merge up to 5fa0f68 |
|
continuous-integration/openshift-jenkins/merge SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pull_requests_origin_future/870/) (Base Commit: da719a3) (Image: devenv-rhel7_6047) |
Fixes #12892
@openshift/devex ptal
Some sample output: