Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

Commit 1ad042b

Browse files
committed
Add tests and put command in own function
Added unit test for projUpToDate and harness test for the -old flag. Put the status -old functionality to it's own function.
1 parent 0db8cb2 commit 1ad042b

File tree

9 files changed

+382
-33
lines changed

9 files changed

+382
-33
lines changed

cmd/dep/status.go

+227-33
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,16 @@ func (cmd *statusCommand) Run(ctx *dep.Ctx, args []string) error {
273273
return errors.Errorf("no Gopkg.lock found. Run `dep ensure` to generate lock file")
274274
}
275275

276-
hasMissingPkgs, errCount, err := runStatusAll(ctx, out, p, sm, cmd)
276+
// Choose function based on command options
277+
var hasMissingPkgs bool
278+
var errCount int
279+
switch {
280+
case cmd.old:
281+
hasMissingPkgs, errCount, err = runOld(ctx, out, p, sm)
282+
default:
283+
hasMissingPkgs, errCount, err = runStatusAll(ctx, out, p, sm)
284+
}
285+
277286
if err != nil {
278287
switch err {
279288
case errFailedUpdate:
@@ -340,15 +349,6 @@ func (cmd *statusCommand) validateFlags() error {
340349
return nil
341350
}
342351

343-
// OldStatus contains information about all the out of date packages in a project.
344-
type OldStatus struct {
345-
ProjectRoot string
346-
Constraint gps.Constraint
347-
Version gps.UnpairedVersion
348-
Revision gps.Revision
349-
Latest gps.Version
350-
}
351-
352352
type rawStatus struct {
353353
ProjectRoot string
354354
Constraint string
@@ -432,7 +432,7 @@ type MissingStatus struct {
432432
MissingPackages []string
433433
}
434434

435-
func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceManager, cmd *statusCommand) (hasMissingPkgs bool, errCount int, err error) {
435+
func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceManager) (hasMissingPkgs bool, errCount int, err error) {
436436
// While the network churns on ListVersions() requests, statically analyze
437437
// code from the current project.
438438
ptree, err := p.ParseRootPackageTree()
@@ -465,17 +465,6 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
465465
return false, 0, errors.Wrapf(err, "could not set up solver for input hashing")
466466
}
467467

468-
// We only care about solution in the -old flag case
469-
var solution gps.Solution
470-
if cmd.old {
471-
params.ChangeAll = true
472-
var err error
473-
solution, err = s.Solve(context.TODO())
474-
if err != nil {
475-
return false, 0, err
476-
}
477-
}
478-
479468
// Errors while collecting constraints should not fail the whole status run.
480469
// It should count the error and tell the user about incomplete results.
481470
cm, ccerrs := collectConstraints(ctx, p, sm)
@@ -662,15 +651,6 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
662651
for _, proj := range slp {
663652
pr := proj.Ident().ProjectRoot
664653

665-
// If -old flag, only display the lines where the solver mismatches
666-
if cmd.old {
667-
if matches, err := projUpToDate(proj, solution); matches {
668-
continue
669-
} else if err != nil {
670-
return false, 0, err
671-
}
672-
}
673-
674654
if err := out.BasicLine(bsMap[string(pr)]); err != nil {
675655
return false, 0, err
676656
}
@@ -752,9 +732,223 @@ outer:
752732
return hasMissingPkgs, 0, errInputDigestMismatch
753733
}
754734

735+
func runOld(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceManager) (hasMissingPkgs bool, errCount int, err error) {
736+
ptree, err := p.ParseRootPackageTree()
737+
if err != nil {
738+
return false, 0, err
739+
}
740+
741+
// Solve the dependencies so we can check if the current dependencies are old
742+
params := gps.SolveParameters{
743+
ProjectAnalyzer: dep.Analyzer{},
744+
RootDir: p.AbsRoot,
745+
RootPackageTree: ptree,
746+
Manifest: p.Manifest,
747+
ChangeAll: true,
748+
}
749+
s, err := gps.Prepare(params, sm)
750+
if err != nil {
751+
return false, 0, errors.Wrapf(err, "could not set up solver for input hashing")
752+
}
753+
754+
if err := out.BasicHeader(); err != nil {
755+
return false, 0, err
756+
}
757+
758+
// Errors while collecting constraints should not fail the whole status run.
759+
// It should count the error and tell the user about incomplete results.
760+
cm, ccerrs := collectConstraints(ctx, p, sm)
761+
if len(ccerrs) > 0 {
762+
errCount += len(ccerrs)
763+
}
764+
765+
bsMap := make(map[string]*BasicStatus)
766+
767+
slp := p.Lock.Projects()
768+
769+
if !bytes.Equal(s.HashInputs(), p.Lock.SolveMeta.InputsDigest) {
770+
// Hash digest mismatch may indicate that some deps are no longer
771+
// needed, some are missing, or that some constraints or source
772+
// locations have changed.
773+
//
774+
// It's possible for digests to not match, but still have a correct
775+
// lock.
776+
rm, _ := ptree.ToReachMap(true, true, false, p.Manifest.IgnoredPackages())
777+
778+
external := rm.FlattenFn(paths.IsStandardImportPath)
779+
roots := make(map[gps.ProjectRoot][]string, len(external))
780+
781+
type fail struct {
782+
ex string
783+
err error
784+
}
785+
var errs []fail
786+
for _, e := range external {
787+
root, err := sm.DeduceProjectRoot(e)
788+
if err != nil {
789+
errs = append(errs, fail{
790+
ex: e,
791+
err: err,
792+
})
793+
continue
794+
}
795+
796+
roots[root] = append(roots[root], e)
797+
}
798+
799+
if len(errs) != 0 {
800+
// TODO this is just a fix quick so staticcheck doesn't complain.
801+
// Visually reconciling failure to deduce project roots with the rest of
802+
// the mismatch output is a larger problem.
803+
ctx.Err.Printf("Failed to deduce project roots for import paths:\n")
804+
for _, fail := range errs {
805+
ctx.Err.Printf("\t%s: %s\n", fail.ex, fail.err.Error())
806+
}
807+
808+
return false, 0, errors.New("address issues with undeducible import paths to get more status information")
809+
}
810+
811+
if err = out.MissingHeader(); err != nil {
812+
return false, 0, err
813+
}
814+
815+
outer2:
816+
for root, pkgs := range roots {
817+
// TODO also handle the case where the project is present, but there
818+
// are items missing from just the package list
819+
for _, lp := range slp {
820+
if lp.Ident().ProjectRoot == root {
821+
continue outer2
822+
}
823+
}
824+
825+
hasMissingPkgs = true
826+
err := out.MissingLine(&MissingStatus{ProjectRoot: string(root), MissingPackages: pkgs})
827+
if err != nil {
828+
return false, 0, err
829+
}
830+
}
831+
if err = out.MissingFooter(); err != nil {
832+
return false, 0, err
833+
}
834+
835+
// We are here because of an input-digest mismatch. Return error.
836+
return hasMissingPkgs, 0, errInputDigestMismatch
837+
}
838+
839+
solution, err := s.Solve(context.TODO())
840+
if err != nil {
841+
return false, 0, err
842+
}
843+
844+
for _, proj := range slp {
845+
if matches, err := projUpToDate(proj, solution.Projects()); matches {
846+
continue
847+
} else if err != nil {
848+
return false, 0, err
849+
}
850+
851+
bs := BasicStatus{
852+
ProjectRoot: string(proj.Ident().ProjectRoot),
853+
PackageCount: len(proj.Packages()),
854+
}
855+
switch out.(type) {
856+
case *dotOutput:
857+
ptr, err := sm.ListPackages(proj.Ident(), proj.Version())
858+
859+
if err != nil {
860+
bs.hasError = true
861+
return false, 0, err
862+
}
863+
864+
prm, _ := ptr.ToReachMap(true, true, false, p.Manifest.IgnoredPackages())
865+
bs.Children = prm.FlattenFn(paths.IsStandardImportPath)
866+
}
867+
// Split apart the version from the lock into its constituent parts.
868+
switch tv := proj.Version().(type) {
869+
case gps.UnpairedVersion:
870+
bs.Version = tv
871+
case gps.Revision:
872+
bs.Revision = tv
873+
case gps.PairedVersion:
874+
bs.Version = tv.Unpair()
875+
bs.Revision = tv.Revision()
876+
}
877+
// Check if the manifest has an override for this project. If so,
878+
// set that as the constraint.
879+
if pp, has := p.Manifest.Ovr[proj.Ident().ProjectRoot]; has && pp.Constraint != nil {
880+
bs.hasOverride = true
881+
bs.Constraint = pp.Constraint
882+
} else if pp, has := p.Manifest.Constraints[proj.Ident().ProjectRoot]; has && pp.Constraint != nil {
883+
// If the manifest has a constraint then set that as the constraint.
884+
bs.Constraint = pp.Constraint
885+
} else {
886+
bs.Constraint = gps.Any()
887+
for _, c := range cm[bs.ProjectRoot] {
888+
bs.Constraint = c.Constraint.Intersect(bs.Constraint)
889+
}
890+
}
891+
892+
// Only if we have a non-rev and non-plain version do/can we display
893+
// anything wrt the version's updateability.
894+
if bs.Version != nil && bs.Version.Type() != gps.IsVersion {
895+
c, has := p.Manifest.Constraints[proj.Ident().ProjectRoot]
896+
if !has {
897+
// Get constraint for locked project
898+
for _, lockedP := range p.Lock.P {
899+
if lockedP.Ident().ProjectRoot == proj.Ident().ProjectRoot {
900+
// Use the unpaired version as the constraint for checking updates.
901+
c.Constraint = bs.Version
902+
}
903+
}
904+
}
905+
// TODO: This constraint is only the constraint imposed by the
906+
// current project, not by any transitive deps. As a result,
907+
// transitive project deps will always show "any" here.
908+
bs.Constraint = c.Constraint
909+
910+
vl, err := sm.ListVersions(proj.Ident())
911+
if err == nil {
912+
gps.SortPairedForUpgrade(vl)
913+
914+
for _, v := range vl {
915+
// Because we've sorted the version list for
916+
// upgrade, the first version we encounter that
917+
// matches our constraint will be what we want.
918+
if c.Constraint.Matches(v) {
919+
// Latest should be of the same type as the Version.
920+
if bs.Version.Type() == gps.IsSemver {
921+
bs.Latest = v
922+
} else {
923+
bs.Latest = v.Revision()
924+
}
925+
break
926+
}
927+
}
928+
} else {
929+
// Failed to fetch version list (could happen due to
930+
// network issue).
931+
bs.hasError = true
932+
return false, 0, err
933+
}
934+
}
935+
936+
bsMap[bs.ProjectRoot] = &bs
937+
}
938+
939+
for k := range bsMap {
940+
if err := out.BasicLine(bsMap[k]); err != nil {
941+
return false, 0, err
942+
}
943+
}
944+
if footerErr := out.BasicFooter(); footerErr != nil {
945+
return false, 0, footerErr
946+
}
947+
return false, errCount, err
948+
}
949+
755950
// projUpToDate returns true if the project p, is at the same revision as what the solution indicates
756-
func projUpToDate(p gps.LockedProject, s gps.Solution) (bool, error) {
757-
solutionProjects := s.Projects()
951+
func projUpToDate(p gps.LockedProject, solutionProjects []gps.LockedProject) (bool, error) {
758952
for i := range solutionProjects {
759953
if solutionProjects[i].Ident().ProjectRoot == p.Ident().ProjectRoot {
760954
spr, _, _ := gps.VersionComponentStrings(solutionProjects[i].Version())

cmd/dep/status_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,57 @@ func TestStatusFormatVersion(t *testing.T) {
3838
}
3939
}
4040

41+
func TestProjUpToDate(t *testing.T) {
42+
deptestProj := gps.NewLockedProject(gps.ProjectIdentifier{ProjectRoot: "github.com/sdboyer/deptest"}, gps.NewVersion("1.0.0").Pair(gps.Revision("ff2948a2ac8f538c4ecd55962e919d1e13e74baf")), []string{})
43+
deptestDosProj := gps.NewLockedProject(gps.ProjectIdentifier{ProjectRoot: "github.com/sdboyer/deptestdos"}, gps.NewVersion("2.0.0").Pair(gps.Revision("5c607206be5decd28e6263ffffdcee067266015e")), []string{})
44+
goDepTestProj := gps.NewLockedProject(gps.ProjectIdentifier{ProjectRoot: "github.com/carolynvs/go-dep-test"}, gps.NewVersion("0.1.1").Pair(gps.Revision("40691983e4002d3a3f5879cc0f1fe99bedda148c")), []string{})
45+
46+
tests := []struct {
47+
proj gps.LockedProject
48+
solutionProjects []gps.LockedProject
49+
want bool
50+
wantErr bool
51+
}{
52+
{
53+
proj: gps.NewLockedProject(gps.ProjectIdentifier{ProjectRoot: "github.com/sdboyer/deptest"}, gps.NewVersion("1.0.0").Pair(gps.Revision("ff2948a2ac8f538c4ecd55962e919d1e13e74baf")), []string{}),
54+
solutionProjects: []gps.LockedProject{
55+
deptestProj, deptestDosProj, goDepTestProj,
56+
},
57+
want: true,
58+
wantErr: false,
59+
},
60+
{
61+
proj: gps.NewLockedProject(gps.ProjectIdentifier{ProjectRoot: "github.com/carolynvs/go-dep-test"}, gps.NewVersion("0.1.0").Pair(gps.Revision("b9c5511fa463628e6251554db29a4be161d02aed")), []string{}),
62+
solutionProjects: []gps.LockedProject{
63+
deptestProj, deptestDosProj, goDepTestProj,
64+
},
65+
want: false,
66+
wantErr: false,
67+
},
68+
{
69+
proj: gps.NewLockedProject(gps.ProjectIdentifier{ProjectRoot: "github.com/carolynvs/go-dep-test"}, gps.NewVersion("0.1.0").Pair(gps.Revision("b9c5511fa463628e6251554db29a4be161d02aed")), []string{}),
70+
solutionProjects: []gps.LockedProject{
71+
deptestProj, deptestDosProj,
72+
},
73+
want: false,
74+
wantErr: true,
75+
},
76+
}
77+
78+
for _, test := range tests {
79+
got, err := projUpToDate(test.proj, test.solutionProjects)
80+
if test.wantErr && err == nil {
81+
t.Errorf("expecting error but didn't receive one")
82+
}
83+
if !test.wantErr && err != nil {
84+
t.Errorf("unexpected error: \n\t(GOT): %v\n\t(WNT): nil", err.Error())
85+
}
86+
if test.want != got {
87+
t.Errorf("returned incorrect result: \n\t(GOT): %v\n\t(WNT): %v", got, test.want)
88+
}
89+
}
90+
}
91+
4192
func TestBasicLine(t *testing.T) {
4293
project := dep.Project{}
4394
aSemverConstraint, _ := gps.NewSemverConstraint("1.2.3")

cmd/dep/testdata/harness_tests/status/old_constraints/final/Gopkg.lock

+27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)