Skip to content

Commit

Permalink
Don't use templating to build error messages (#3679)
Browse files Browse the repository at this point in the history
It's pretty hard to understand, and we don't need the complexity.
  • Loading branch information
justinsb committed Dec 1, 2022
1 parent 43c578c commit f705db0
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 280 deletions.
96 changes: 39 additions & 57 deletions internal/errors/resolver/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,50 +27,6 @@ func init() {
AddErrorResolver(&gitExecErrorResolver{})
}

const (
genericGitExecError = `
Error: Failed to execute git command {{ printf "%q " .gitcmd }}
{{- if gt (len .repo) 0 -}}
against repo {{ printf "%q " .repo }}
{{- end }}
{{- if gt (len .ref) 0 -}}
for reference {{ printf "%q " .ref }}
{{- end }}
{{- template "ExecOutputDetails" . }}
`

unknownRefGitExecError = `
Error: Unknown ref {{ printf "%q" .ref }}. Please verify that the reference exists in upstream repo {{ printf "%q" .repo }}.
{{- template "ExecOutputDetails" . }}
`

noGitBinaryError = `
Error: No git executable found. kpt requires git to be installed and available in the path.
{{- template "ExecOutputDetails" . }}
`

httpsAuthRequired = `
Error: Repository {{ printf "%q" .repo }} requires authentication. kpt does not support this for the 'https' protocol. Please use the 'git' protocol instead.
{{- template "ExecOutputDetails" . }}
`

repositoryUnavailable = `
Error: Unable to access repository {{ printf "%q" .repo }}.
{{- template "ExecOutputDetails" . }}
`

repositoryNotFound = `
Error: Repository {{ printf "%q" .repo }} not found.
{{- template "ExecOutputDetails" . }}
`
)

// gitExecErrorResolver is an implementation of the ErrorResolver interface
// that can produce error messages for errors of the gitutil.GitExecError type.
type gitExecErrorResolver struct{}
Expand All @@ -82,29 +38,55 @@ func (*gitExecErrorResolver) Resolve(err error) (ResolvedResult, bool) {
}
fullCommand := fmt.Sprintf("git %s %s", gitExecErr.Command,
strings.Join(gitExecErr.Args, " "))
tmplArgs := map[string]interface{}{
"gitcmd": fullCommand,
"repo": gitExecErr.Repo,
"ref": gitExecErr.Ref,
"stdout": gitExecErr.StdOut,
"stderr": gitExecErr.StdErr,
}

var msg string
switch gitExecErr.Type {
case gitutil.UnknownReference:
msg = ExecuteTemplate(unknownRefGitExecError, tmplArgs)
msg = fmt.Sprintf("Error: Unknown ref %q. Please verify that the reference exists in upstream repo %q.", gitExecErr.Ref, gitExecErr.Repo)
msg = msg + "\n" + BuildOutputDetails(gitExecErr.StdOut, gitExecErr.StdErr)

case gitutil.GitExecutableNotFound:
msg = ExecuteTemplate(noGitBinaryError, tmplArgs)
msg = "Error: No git executable found. kpt requires git to be installed and available in the path."
msg = msg + "\n" + BuildOutputDetails(gitExecErr.StdOut, gitExecErr.StdErr)

case gitutil.HTTPSAuthRequired:
msg = ExecuteTemplate(httpsAuthRequired, tmplArgs)
msg = fmt.Sprintf("Error: Repository %q requires authentication.", gitExecErr.Repo)
msg += " kpt does not support this for the 'https' protocol."
msg += " Please use the 'git' protocol instead."
msg = msg + "\n" + BuildOutputDetails(gitExecErr.StdOut, gitExecErr.StdErr)

case gitutil.RepositoryUnavailable:
msg = ExecuteTemplate(repositoryUnavailable, tmplArgs)
msg = fmt.Sprintf("Error: Unable to access repository %q.", gitExecErr.Repo)
msg = msg + "\n" + BuildOutputDetails(gitExecErr.StdOut, gitExecErr.StdErr)

case gitutil.RepositoryNotFound:
msg = ExecuteTemplate(repositoryNotFound, tmplArgs)
msg = fmt.Sprintf("Error: Repository %q not found.", gitExecErr.Repo)
msg = msg + "\n" + BuildOutputDetails(gitExecErr.StdOut, gitExecErr.StdErr)
default:
msg = ExecuteTemplate(genericGitExecError, tmplArgs)
msg = fmt.Sprintf("Error: Failed to execute git command %q", fullCommand)
if gitExecErr.Repo != "" {
msg += fmt.Sprintf(" against repo %q", gitExecErr.Repo)
}
if gitExecErr.Ref != "" {
msg += fmt.Sprintf(" for reference %q", gitExecErr.Ref)
}
msg = msg + "\n" + BuildOutputDetails(gitExecErr.StdOut, gitExecErr.StdErr)
}
return ResolvedResult{
Message: msg,
}, true
}

func BuildOutputDetails(stdout string, stderr string) string {
var sb strings.Builder
if len(stdout) > 0 || len(stderr) > 0 {
sb.WriteString("\nDetails:\n")
}
if len(stdout) > 0 {
sb.WriteString(stdout)
}
if len(stderr) > 0 {
sb.WriteString(stderr)
}
return sb.String()
}
116 changes: 39 additions & 77 deletions internal/errors/resolver/live.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package resolver

import (
"fmt"

initialization "github.com/GoogleContainerTools/kpt/commands/live/init"
"github.com/GoogleContainerTools/kpt/internal/cmdutil"
"github.com/GoogleContainerTools/kpt/internal/errors"
Expand Down Expand Up @@ -45,14 +47,6 @@ Error: Package has multiple inventory object templates.
The package should have one and only one inventory object template.
`

resourceGroupCRDInstallErrorMsg = `
Error: Unable to install the ResourceGroup CRD.
{{- if gt (len .cause) 0 }}
{{ printf "\nDetails:" }}
{{ printf "%s" .cause }}
{{- end }}
`
//nolint:lll
noResourceGroupCRDMsg = `
Error: The ResourceGroup CRD was not found in the cluster. Please install it either by using the '--install-resource-group' flag or the 'kpt live install-resource-group' command.
Expand All @@ -75,25 +69,6 @@ Error: Inventory information has already been added to the package Kptfile objec

multipleResourceGroupsMsg = `
Error: Multiple ResourceGroup objects found. Please make sure at most one ResourceGroup object exists within the package.
`

//nolint:lll
inventoryInfoValidationMsg = `
Error: The inventory information is not valid. Please update the information in the ResourceGroup file or provide information with the command line flags. To generate the inventory information the first time, use the 'kpt live init' command.
Details:
{{- range .err.Violations}}
{{printf "%s" .Reason }}
{{- end}}
`

unknownTypesMsg = `
Error: {{ printf "%d" (len .err.GroupVersionKinds) }} resource types could not be found in the cluster or as CRDs among the applied resources.
Resource types:
{{- range .err.GroupVersionKinds}}
{{ printf "%s" .String }}
{{- end}}
`
)

Expand All @@ -104,92 +79,79 @@ type liveErrorResolver struct{}
func (*liveErrorResolver) Resolve(err error) (ResolvedResult, bool) {
var noInventoryObjError *inventory.NoInventoryObjError
if errors.As(err, &noInventoryObjError) {
return ResolvedResult{
Message: ExecuteTemplate(noInventoryObjErrorMsg, map[string]interface{}{
"err": *noInventoryObjError,
}),
}, true
msg := noInventoryObjErrorMsg
return ResolvedResult{Message: msg}, true
}

var multipleInventoryObjError *inventory.MultipleInventoryObjError
if errors.As(err, &multipleInventoryObjError) {
return ResolvedResult{
Message: ExecuteTemplate(multipleInventoryObjErrorMsg, map[string]interface{}{
"err": *multipleInventoryObjError,
}),
}, true
msg := multipleInventoryObjErrorMsg
return ResolvedResult{Message: msg}, true
}

var resourceGroupCRDInstallError *cmdutil.ResourceGroupCRDInstallError
if errors.As(err, &resourceGroupCRDInstallError) {
return ResolvedResult{
Message: ExecuteTemplate(resourceGroupCRDInstallErrorMsg, map[string]interface{}{
"cause": resourceGroupCRDInstallError.Err.Error(),
}),
}, true
msg := "Error: Unable to install the ResourceGroup CRD."

cause := resourceGroupCRDInstallError.Err
msg += fmt.Sprintf("\nDetails: %v", cause)

return ResolvedResult{Message: msg}, true
}

var noResourceGroupCRDError *cmdutil.NoResourceGroupCRDError
if errors.As(err, &noResourceGroupCRDError) {
return ResolvedResult{
Message: ExecuteTemplate(noResourceGroupCRDMsg, map[string]interface{}{
"err": *noResourceGroupCRDError,
}),
}, true
msg := noResourceGroupCRDMsg
return ResolvedResult{Message: msg}, true
}

var invExistsError *initialization.InvExistsError
if errors.As(err, &invExistsError) {
return ResolvedResult{
Message: ExecuteTemplate(invInfoAlreadyExistsMsg, map[string]interface{}{
"err": *invExistsError,
}),
}, true
msg := invInfoAlreadyExistsMsg
return ResolvedResult{Message: msg}, true
}

var invInfoInRGAlreadyExistsError *initialization.InvInRGExistsError
if errors.As(err, &invInfoInRGAlreadyExistsError) {
return ResolvedResult{
Message: ExecuteTemplate(invInfoInRGAlreadyExistsMsg, map[string]interface{}{
"err": *invInfoInRGAlreadyExistsError,
}),
}, true
msg := invInfoInRGAlreadyExistsMsg
return ResolvedResult{Message: msg}, true
}

var invInKfExistsError *initialization.InvInKfExistsError
if errors.As(err, &invInKfExistsError) {
return ResolvedResult{
Message: ExecuteTemplate(invInfoInKfAlreadyExistsMsg, map[string]interface{}{
"err": *invInKfExistsError,
}),
}, true
msg := invInfoInKfAlreadyExistsMsg
return ResolvedResult{Message: msg}, true
}

var multipleResourceGroupsError *pkg.MultipleResourceGroupsError
if errors.As(err, &multipleResourceGroupsError) {
return ResolvedResult{
Message: ExecuteTemplate(multipleResourceGroupsMsg, map[string]interface{}{
"err": *multipleResourceGroupsError,
}),
}, true
msg := multipleResourceGroupsMsg
return ResolvedResult{Message: msg}, true
}

var inventoryInfoValidationError *live.InventoryInfoValidationError
if errors.As(err, &inventoryInfoValidationError) {
return ResolvedResult{
Message: ExecuteTemplate(inventoryInfoValidationMsg, map[string]interface{}{
"err": *inventoryInfoValidationError,
}),
}, true
msg := "Error: The inventory information is not valid."
msg += " Please update the information in the ResourceGroup file or provide information with the command line flags."
msg += " To generate the inventory information the first time, use the 'kpt live init' command."

msg += "\nDetails:\n"
for _, v := range inventoryInfoValidationError.Violations {
msg += fmt.Sprintf("%s\n", v.Reason)
}

return ResolvedResult{Message: msg}, true
}

var unknownTypesError *manifestreader.UnknownTypesError
if errors.As(err, &unknownTypesError) {
return ResolvedResult{
Message: ExecuteTemplate(unknownTypesMsg, map[string]interface{}{
"err": *unknownTypesError,
}),
}, true
msg := fmt.Sprintf("Error: %d resource types could not be found in the cluster or as CRDs among the applied resources.", len(unknownTypesError.GroupVersionKinds))
msg += "\n\nResource types:\n"
for _, gvk := range unknownTypesError.GroupVersionKinds {
msg += fmt.Sprintf("%s\n", gvk)
}

return ResolvedResult{Message: msg}, true
}

var resultError *common.ResultError
Expand Down

0 comments on commit f705db0

Please sign in to comment.