Skip to content

Commit

Permalink
Enhance Maven errors (#162)
Browse files Browse the repository at this point in the history
* Enhance Maven errors

* Fix lint errors

* Inhance help text

* improving matching and messages

* improve error messages in maven

---------

Co-authored-by: Emil Wåreus <[email protected]>
  • Loading branch information
4ernovm and emilwareus authored Dec 12, 2023
1 parent a5d43b7 commit cac75d6
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 16 deletions.
137 changes: 130 additions & 7 deletions internal/resolution/pm/maven/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ package maven

import (
"path/filepath"
"regexp"
"strings"

"github.com/debricked/cli/internal/resolution/job"
"github.com/debricked/cli/internal/resolution/pm/util"
)

const (
lockFileExtension = "maven.debricked.lock"
lockFileExtension = "maven.debricked.lock"
nonParseablePomErrRegex = "Non-parseable POM (.*)"
networkUnreachableErrRegex = "Failed to retrieve plugin descriptor"
invalidVersionErrRegex = "('[\\w\\.]+' for [\\w\\.:-]+ must not contain any of these characters .* but found .)"
dependenciesResolveErrRegex = `Could not resolve dependencies for project\s+([\w\.-]+:[\w\.-]+:[\w\.-]+:[\w\.-]+)`
)

type Job struct {
Expand All @@ -27,18 +33,135 @@ func (j *Job) Run() {
workingDirectory := filepath.Dir(filepath.Clean(j.GetFile()))
cmd, err := j.cmdFactory.MakeDependencyTreeCmd(workingDirectory)
if err != nil {
j.Errors().Critical(util.NewPMJobError(err.Error()))
j.handleError(util.NewPMJobError(err.Error()))

return
}
j.SendStatus("creating dependency graph")

status := "creating dependency graph"
j.SendStatus(status)
var output []byte
output, err = cmd.Output()
if err != nil {
if output == nil {
j.Errors().Critical(util.NewPMJobError(err.Error()))
} else {
j.Errors().Critical(util.NewPMJobError(string(output)))
errContent := err.Error()
if output != nil {
errContent = string(output)
}

cmdErr := util.NewPMJobError(errContent)
cmdErr.SetStatus(status)

j.handleError(cmdErr)
}
}

func (j *Job) handleError(cmdErr job.IError) {
expressions := []string{
nonParseablePomErrRegex,
networkUnreachableErrRegex,
invalidVersionErrRegex,
dependenciesResolveErrRegex,
}

for _, expression := range expressions {
regex := regexp.MustCompile(expression)

if regex.MatchString(cmdErr.Error()) {
cmdErr = j.addDocumentation(expression, regex, cmdErr)
j.Errors().Critical(cmdErr)

return
}
}

j.Errors().Critical(cmdErr)
}

func (j *Job) addDocumentation(expr string, regex *regexp.Regexp, cmdErr job.IError) job.IError {
switch {
case expr == nonParseablePomErrRegex:
cmdErr = j.addNonParseablePomErrorDocumentation(regex, cmdErr)
case expr == networkUnreachableErrRegex:
cmdErr = j.addNetworkUnreachableErrorDocumentation(cmdErr)
case expr == invalidVersionErrRegex:
cmdErr = j.addInvalidVersionErrorDocumentation(regex, cmdErr)
case expr == dependenciesResolveErrRegex:
cmdErr = j.addDependenciesResolveErrorDocumentation(regex, cmdErr)
}

return cmdErr
}

func (j *Job) addNonParseablePomErrorDocumentation(regex *regexp.Regexp, cmdErr job.IError) job.IError {
matches := regex.FindAllStringSubmatch(cmdErr.Error(), 1)
message := "the POM file for errors"
if len(matches) > 0 && len(matches[0]) > 1 {
message = matches[0][1]
}

cmdErr.SetDocumentation(
strings.Join(
[]string{
"Failed to build Maven dependency tree.",
"Your POM file is not valid.",
"Please check",
message,
}, " "),
)

return cmdErr
}

func (j *Job) addNetworkUnreachableErrorDocumentation(cmdErr job.IError) job.IError {
cmdErr.SetDocumentation(
strings.Join(
[]string{
"We weren't able to retrieve one or more plugin descriptor(s).",
"Please check your Internet connection and try again.",
}, " "),
)

return cmdErr
}

func (j *Job) addInvalidVersionErrorDocumentation(regex *regexp.Regexp, cmdErr job.IError) job.IError {
matches := regex.FindAllStringSubmatch(cmdErr.Error(), 1)
message := ""
if len(matches) > 0 && len(matches[0]) > 1 {
message = matches[0][1]
}

cmdErr.SetDocumentation(
strings.Join(
[]string{
"There is an error in dependencies:",
message,
}, " "),
)

return cmdErr
}

func (j *Job) addDependenciesResolveErrorDocumentation(regex *regexp.Regexp, cmdErr job.IError) job.IError {
matches := regex.FindAllStringSubmatch(cmdErr.Error(), 1)
message := "An error occurred during dependencies resolve "
if len(matches) > 0 && len(matches[0]) > 1 {
message += strings.Join(
[]string{
"for: ",
matches[0][1],
"",
}, "")
}

cmdErr.SetDocumentation(
strings.Join(
[]string{
message,
"\nTry to run `mvn dependency:tree -e` to get more details.\n",
util.InstallPrivateDependencyMessage,
}, ""),
)

return cmdErr
}
51 changes: 42 additions & 9 deletions internal/resolution/pm/maven/job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,48 @@ func TestNewJob(t *testing.T) {
}

func TestRunCmdErr(t *testing.T) {
cmdErr := errors.New("cmd-error")
j := NewJob("file", testdata.CmdFactoryMock{Err: cmdErr})

go jobTestdata.WaitStatus(j)

j.Run()

assert.Len(t, j.Errors().GetAll(), 1)
assert.Contains(t, j.Errors().GetAll(), util.NewPMJobError(cmdErr.Error()))
cases := []struct {
error string
doc string
}{
{
error: "cmd-error",
doc: util.UnknownError,
},
{
error: " |[FATAL] Non-parseable POM /home/asus/Projects/playground/maven-project/pom.xml: end tag name </target> must be the same as start tag <source> from line 37 (position: TEXT seen ...<source>1.6</target>... @37:31) @ /home/asus/Projects/playground/maven-project/pom.xml, line 37, column 31\n",
doc: "Failed to build Maven dependency tree. Your POM file is not valid. Please check /home/asus/Projects/playground/maven-project/pom.xml: end tag name </target> must be the same as start tag <source> from line 37 (position: TEXT seen ...<source>1.6</target>... @37:31) @ /home/asus/Projects/playground/maven-project/pom.xml, line 37, column 31",
},
{
error: " |[WARNING] Failed to retrieve plugin descriptor for org.apache.maven.plugins:maven-compiler-plugin:2.3.2: Plugin org.apache.maven.plugins:maven-compiler-plugin:2.3.2 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-compiler-plugin:jar:2.3.2\n",
doc: "We weren't able to retrieve one or more plugin descriptor(s). Please check your Internet connection and try again.",
},
{
error: " |[ERROR] 'dependencies.dependency.version' for org.hamcrest:hamcrest-library:jar must not contain any of these characters \\/:\"<>|?* but found * @ com.example.maven-project:maven-project:1.0-SNAPSHOT, /home/asus/Projects/playground/maven-project/pom.xml, line 196, column 18\n",
doc: "There is an error in dependencies: 'dependencies.dependency.version' for org.hamcrest:hamcrest-library:jar must not contain any of these characters \\/:\"<>|?* but found *",
},
{
error: " |[ERROR] Failed to execute goal on project jackpot: Could not resolve dependencies for project com.jeteo:jackpot:war:1.0-SNAPSHOT: The following artifacts could not be resolved: javax.servlet:com.springsource.javax.servlet:jar:2.5.0, javax.servlet:com.springsource.javax.servlet.jsp.jstl:jar:1.2.0 (http://repository.springsource.com/maven/bundles/release) -> [Help 1]\n",
doc: "An error occurred during dependencies resolve for: com.jeteo:jackpot:war:1.0-SNAPSHOT\nTry to run `mvn dependency:tree -e` to get more details.\nIf this is a private dependency, please make sure that the debricked CLI has access to install it or pre-install it before running the debricked CLI.",
},
}

for _, c := range cases {
expectedError := util.NewPMJobError(c.error)
expectedError.SetDocumentation(c.doc)

cmdErr := errors.New(c.error)
j := NewJob("file", testdata.CmdFactoryMock{Err: cmdErr})

go jobTestdata.WaitStatus(j)

j.Run()

errors := j.Errors().GetAll()

assert.Len(t, errors, 1)
assert.Contains(t, errors, expectedError)
}
}

func TestRunCmdOutputErr(t *testing.T) {
Expand Down

0 comments on commit cac75d6

Please sign in to comment.