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

fix(status): add constraint for locked projects #962

Merged
merged 5 commits into from
Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 53 additions & 7 deletions cmd/dep/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/golang/dep"
"github.com/golang/dep/gps"
"github.com/golang/dep/gps/paths"
"github.com/golang/dep/gps/pkgtree"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -389,7 +388,7 @@ 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(ptree, p, sm)
cm := collectConstraints(ctx, p, sm)

// 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
Expand Down Expand Up @@ -461,7 +460,7 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
} else {
bs.Constraint = gps.Any()
for _, c := range cm[bs.ProjectRoot] {
bs.Constraint = c.Intersect(bs.Constraint)
bs.Constraint = c.Constraint.Intersect(bs.Constraint)
}
}

Expand All @@ -470,7 +469,12 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
if bs.Version != nil && bs.Version.Type() != gps.IsVersion {
c, has := p.Manifest.Constraints[proj.Ident().ProjectRoot]
if !has {
c.Constraint = gps.Any()
// Get constraint for locked project
for _, lockedP := range p.Lock.P {
if lockedP.Ident().ProjectRoot == proj.Ident().ProjectRoot {
c.Constraint = lockedP.Version()
}
}
}
// TODO: This constraint is only the constraint imposed by the
// current project, not by any transitive deps. As a result,
Expand Down Expand Up @@ -639,7 +643,49 @@ func formatVersion(v gps.Version) string {
return v.String()
}

func collectConstraints(ptree pkgtree.PackageTree, p *dep.Project, sm gps.SourceManager) map[string][]gps.Constraint {
// TODO
return map[string][]gps.Constraint{}
// projectConstraint stores ProjectRoot and Constraint for that project.
type projectConstraint struct {
Project gps.ProjectRoot
Constraint gps.Constraint
}

// constraintsCollection is a map of ProjectRoot(dependency) and a collection of
// projectConstraint for the dependencies. This can be used to find constraints
// on a dependency and the projects that apply those constraints.
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 {
constraintCollection := make(constraintsCollection)

// Get direct deps of the root project.
_, directDeps, err := getDirectDependencies(sm, p)
if err != nil {
ctx.Err.Println("Error getting direct deps:", err)
}
// Create a root analyzer.
rootAnalyzer := newRootAnalyzer(false, ctx, directDeps, sm)

// Iterate through the locked projects and collect constraints of all the projects.
for _, proj := range p.Lock.Projects() {
manifest, _, err := sm.GetManifestAndLock(proj.Ident(), proj.Version(), rootAnalyzer)
if err != nil {
ctx.Err.Println("Error getting manifest and lock:", err)
continue
}

// Get project constraints.
pc := manifest.DependencyConstraints()

// Iterate through the project constraints to get individual dependency
// project and constraint values.
for pr, pp := range pc {
constraintCollection[string(pr)] = append(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this is overzealous right now - it pulls in constraints regardless of whether they're actually applicable or not. it's unlikely to create problems right now, but it will need to be updated in the future (please open an issue!) to do the equivalent of something like intersectConstraintsWithImports() or getApplicableConstraints()

constraintCollection[string(pr)],
projectConstraint{proj.Ident().ProjectRoot, pp.Constraint},
)
}
}

return constraintCollection
}
119 changes: 119 additions & 0 deletions cmd/dep/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ package main

import (
"bytes"
"io/ioutil"
"log"
"reflect"
"testing"
"text/tabwriter"

"strings"

"github.com/golang/dep"
"github.com/golang/dep/gps"
"github.com/golang/dep/internal/test"
)

func TestStatusFormatVersion(t *testing.T) {
Expand Down Expand Up @@ -287,3 +291,118 @@ func TestBasicStatusGetConsolidatedLatest(t *testing.T) {
})
}
}

func TestCollectConstraints(t *testing.T) {
ver1, _ := gps.NewSemverConstraintIC("v1.0.0")
ver08, _ := gps.NewSemverConstraintIC("v0.8.0")
ver2, _ := gps.NewSemverConstraintIC("v2.0.0")

cases := []struct {
name string
project dep.Project
wantConstraints constraintsCollection
}{
{
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{"."},
),
},
},
},
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{"."},
),
},
},
},
wantConstraints: constraintsCollection{
"github.com/sdboyer/deptest": []projectConstraint{
{"github.com/darkowlzz/deptest-project-1", ver1},
{"github.com/darkowlzz/deptest-project-2", ver08},
},
"github.com/sdboyer/deptestdos": []projectConstraint{
{"github.com/darkowlzz/deptest-project-2", ver2},
},
"github.com/sdboyer/dep-test": []projectConstraint{
{"github.com/darkowlzz/deptest-project-2", ver1},
},
},
},
{
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{"."},
),
},
},
},
wantConstraints: constraintsCollection{
"github.com/sdboyer/deptest": []projectConstraint{
{"github.com/darkowlzz/deptest-project-1", ver1},
},
},
},
}

h := test.NewHelper(t)
defer h.Cleanup()

h.TempDir("src")
pwd := h.Path(".")
discardLogger := log.New(ioutil.Discard, "", 0)

ctx := &dep.Ctx{
GOPATH: pwd,
Out: discardLogger,
Err: discardLogger,
}

sm, err := ctx.SourceManager()
h.Must(err)
defer sm.Release()

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
gotConstraints := collectConstraints(ctx, &c.project, sm)

if !reflect.DeepEqual(gotConstraints, c.wantConstraints) {
t.Fatalf("Unexpected collected constraints: \n\t(GOT): %v\n\t(WNT): %v", gotConstraints, c.wantConstraints)
}
})
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"ProjectRoot":"github.com/sdboyer/deptest","Constraint":"^0.8.0","Version":"v0.8.0","Revision":"ff2948a2ac8f538c4ecd55962e919d1e13e74baf","Latest":"3f4c3bea144e112a69bbe5d8d01c1b09a544253f","PackageCount":1},{"ProjectRoot":"github.com/sdboyer/deptestdos","Constraint":"*","Version":"v2.0.0","Revision":"5c607206be5decd28e6263ffffdcee067266015e","Latest":"5c607206be5decd28e6263ffffdcee067266015e","PackageCount":1}]
[{"ProjectRoot":"github.com/sdboyer/deptest","Constraint":"^0.8.0","Version":"v0.8.0","Revision":"ff2948a2ac8f538c4ecd55962e919d1e13e74baf","Latest":"3f4c3bea144e112a69bbe5d8d01c1b09a544253f","PackageCount":1},{"ProjectRoot":"github.com/sdboyer/deptestdos","Constraint":"v2.0.0","Version":"v2.0.0","Revision":"5c607206be5decd28e6263ffffdcee067266015e","Latest":"5c607206be5decd28e6263ffffdcee067266015e","PackageCount":1}]
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
PROJECT CONSTRAINT VERSION REVISION LATEST PKGS USED
github.com/sdboyer/deptest ^0.8.0 v0.8.0 ff2948a 3f4c3be 1
github.com/sdboyer/deptestdos * v2.0.0 5c60720 5c60720 1
github.com/sdboyer/deptestdos v2.0.0 v2.0.0 5c60720 5c60720 1
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
PROJECT CONSTRAINT VERSION REVISION LATEST PKGS USED
github.com/sdboyer/deptest * (override) v0.8.1 3f4c3be ff2948a 1
github.com/sdboyer/deptestdos * v2.0.0 5c60720 5c60720 1
PROJECT CONSTRAINT VERSION REVISION LATEST PKGS USED
github.com/sdboyer/deptest v0.8.1 (override) v0.8.1 3f4c3be 3f4c3be 1
github.com/sdboyer/deptestdos v2.0.0 v2.0.0 5c60720 5c60720 1