diff --git a/cmd/dep/status.go b/cmd/dep/status.go index ced007d747..1d8eaf8156 100644 --- a/cmd/dep/status.go +++ b/cmd/dep/status.go @@ -417,7 +417,12 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana return false, 0, errors.Wrapf(err, "could not set up solver for input hashing") } - cm := collectConstraints(ctx, p, sm) + // Errors while collecting constraints should not fail the whole status run. + // It should count the error and tell the user about incomplete results. + cm, ccerrs := collectConstraints(ctx, p, sm) + if len(ccerrs) > 0 { + errCount += len(ccerrs) + } // Get the project list and sort it so that the printed output users see is // deterministically ordered. (This may be superfluous if the lock is always @@ -566,7 +571,7 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana // Count ListVersions error because we get partial results when // this happens. - errCount = len(errListVerCh) + errCount += len(errListVerCh) if ctx.Verbose { for err := range errListVerCh { ctx.Err.Println(err.Error()) @@ -684,7 +689,9 @@ type projectConstraint struct { type constraintsCollection map[string][]projectConstraint // collectConstraints collects constraints declared by all the dependencies. -func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) constraintsCollection { +// It returns constraintsCollection and a slice of errors encountered while +// collecting the constraints, if any. +func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) (constraintsCollection, []error) { logger := ctx.Err if !ctx.Verbose { logger = log.New(ioutil.Discard, "", 0) @@ -692,10 +699,14 @@ func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) cons logger.Println("Collecting project constraints:") + var mutex sync.Mutex + constraintCollection := make(constraintsCollection) + // Get direct deps of the root project. _, directDeps, err := getDirectDependencies(sm, p) if err != nil { - logger.Println("Error getting direct deps:", err) + // Return empty collection, not nil, if we fail here. + return constraintCollection, []error{errors.Wrap(err, "failed to get direct dependencies")} } // Create a root analyzer. @@ -703,9 +714,6 @@ func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) cons lp := p.Lock.Projects() - var mutex sync.Mutex - constraintCollection := make(constraintsCollection) - // Channel for receiving all the errors. errCh := make(chan error, len(lp)) @@ -750,13 +758,15 @@ func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) cons wg.Wait() close(errCh) + var errs []error if len(errCh) > 0 { - for err := range errCh { - logger.Println(err.Error()) + for e := range errCh { + errs = append(errs, e) + logger.Println(e.Error()) } } - return constraintCollection + return constraintCollection, errs } type byProject []projectConstraint diff --git a/cmd/dep/status_test.go b/cmd/dep/status_test.go index 997cc08f78..904eec90bf 100644 --- a/cmd/dep/status_test.go +++ b/cmd/dep/status_test.go @@ -8,6 +8,7 @@ import ( "bytes" "io/ioutil" "log" + "path/filepath" "reflect" "testing" "text/tabwriter" @@ -299,45 +300,42 @@ func TestCollectConstraints(t *testing.T) { cases := []struct { name string - project dep.Project + lock dep.Lock wantConstraints constraintsCollection + wantErr bool }{ { name: "without any constraints", - project: dep.Project{ - Lock: &dep.Lock{ - P: []gps.LockedProject{ - gps.NewLockedProject( - gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")}, - gps.NewVersion("v1.0.0"), - []string{"."}, - ), - }, + lock: dep.Lock{ + P: []gps.LockedProject{ + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")}, + gps.NewVersion("v1.0.0"), + []string{"."}, + ), }, }, wantConstraints: constraintsCollection{}, }, { name: "with multiple constraints", - project: dep.Project{ - Lock: &dep.Lock{ - P: []gps.LockedProject{ - gps.NewLockedProject( - gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")}, - gps.NewVersion("v1.0.0"), - []string{"."}, - ), - gps.NewLockedProject( - gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")}, - gps.NewVersion("v0.1.0"), - []string{"."}, - ), - gps.NewLockedProject( - gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")}, - gps.NewBranch("master").Pair(gps.Revision("824a8d56a4c6b2f4718824a98cd6d70d3dbd4c3e")), - []string{"."}, - ), - }, + lock: dep.Lock{ + P: []gps.LockedProject{ + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")}, + gps.NewVersion("v1.0.0"), + []string{"."}, + ), + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")}, + gps.NewVersion("v0.1.0"), + []string{"."}, + ), + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")}, + gps.NewBranch("master").Pair(gps.Revision("824a8d56a4c6b2f4718824a98cd6d70d3dbd4c3e")), + []string{"."}, + ), }, }, wantConstraints: constraintsCollection{ @@ -355,20 +353,18 @@ func TestCollectConstraints(t *testing.T) { }, { name: "skip projects with invalid versions", - project: dep.Project{ - Lock: &dep.Lock{ - P: []gps.LockedProject{ - gps.NewLockedProject( - gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")}, - gps.NewVersion("v0.1.0"), - []string{"."}, - ), - gps.NewLockedProject( - gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")}, - gps.NewVersion("v1.0.0"), - []string{"."}, - ), - }, + lock: dep.Lock{ + P: []gps.LockedProject{ + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")}, + gps.NewVersion("v0.1.0"), + []string{"."}, + ), + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")}, + gps.NewVersion("v1.0.0"), + []string{"."}, + ), }, }, wantConstraints: constraintsCollection{ @@ -376,6 +372,7 @@ func TestCollectConstraints(t *testing.T) { {"github.com/darkowlzz/deptest-project-1", ver1}, }, }, + wantErr: true, }, } @@ -396,12 +393,23 @@ func TestCollectConstraints(t *testing.T) { h.Must(err) defer sm.Release() + // Create new project and set root. Setting root is required for PackageList + // to run properly. + p := new(dep.Project) + p.SetRoot(filepath.Join(pwd, "src")) + for _, c := range cases { t.Run(c.name, func(t *testing.T) { - gotConstraints := collectConstraints(ctx, &c.project, sm) + p.Lock = &c.lock + gotConstraints, err := collectConstraints(ctx, p, sm) + if len(err) > 0 && !c.wantErr { + t.Fatalf("unexpected errors while collecting constraints: %v", err) + } else if len(err) == 0 && c.wantErr { + t.Fatalf("expected errors while collecting constraints, but got none") + } if !reflect.DeepEqual(gotConstraints, c.wantConstraints) { - t.Fatalf("Unexpected collected constraints: \n\t(GOT): %v\n\t(WNT): %v", gotConstraints, c.wantConstraints) + t.Fatalf("unexpected collected constraints: \n\t(GOT): %v\n\t(WNT): %v", gotConstraints, c.wantConstraints) } }) }