diff --git a/pkg/buildpack/builder.go b/pkg/buildpack/builder.go index 6bdaecad3..6c80235f1 100644 --- a/pkg/buildpack/builder.go +++ b/pkg/buildpack/builder.go @@ -269,15 +269,24 @@ func validateBuildpacks(mainBP Buildpack, depBPs []Buildpack) error { bpd := bp.Descriptor() for _, orderEntry := range bpd.Order { for _, groupEntry := range orderEntry.Group { - if _, ok := depsWithRefs[groupEntry.BuildpackInfo.FullName()]; !ok { + bpFullName, err := groupEntry.BuildpackInfo.FullNameWithVersion() + if err != nil { + return errors.Wrapf( + err, + "buildpack %s must specify a version when referencing buildpack %s", + style.Symbol(bpd.Info.FullName()), + style.Symbol(bpFullName), + ) + } + if _, ok := depsWithRefs[bpFullName]; !ok { return errors.Errorf( "buildpack %s references buildpack %s which is not present", style.Symbol(bpd.Info.FullName()), - style.Symbol(groupEntry.FullName()), + style.Symbol(bpFullName), ) } - depsWithRefs[groupEntry.BuildpackInfo.FullName()] = append(depsWithRefs[groupEntry.BuildpackInfo.FullName()], bpd.Info) + depsWithRefs[bpFullName] = append(depsWithRefs[bpFullName], bpd.Info) } } } diff --git a/pkg/buildpack/builder_test.go b/pkg/buildpack/builder_test.go index b81fe82af..b732f9560 100644 --- a/pkg/buildpack/builder_test.go +++ b/pkg/buildpack/builder_test.go @@ -201,6 +201,41 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.AssertError(t, err, "buildpack 'bp.present.id@bp.present.version' references buildpack 'bp.missing.id@bp.missing.version' which is not present") }) }) + + when("there is a referenced buildpack from dependency buildpack that does not have proper version defined", func() { + it("should error", func() { + mainBP, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ + ID: "bp.1.id", + Version: "bp.1.version", + }, + Order: dist.Order{{ + Group: []dist.BuildpackRef{ + {BuildpackInfo: dist.BuildpackInfo{ID: "bp.present.id", Version: "bp.present.version"}}, + }, + }}, + }, 0644) + h.AssertNil(t, err) + builder := buildpack.NewBuilder(mockImageFactory(expectedImageOS)) + builder.SetBuildpack(mainBP) + + presentBP, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.present.id", Version: "bp.present.version"}, + Order: dist.Order{{ + Group: []dist.BuildpackRef{ + {BuildpackInfo: dist.BuildpackInfo{ID: "bp.missing.id"}}, + }, + }}, + }, 0644) + h.AssertNil(t, err) + builder.AddDependency(presentBP) + + err = testFn(builder) + h.AssertError(t, err, "buildpack 'bp.present.id@bp.present.version' must specify a version when referencing buildpack 'bp.missing.id'") + }) + }) }) when("validate stacks", func() { diff --git a/pkg/dist/buildpack.go b/pkg/dist/buildpack.go index 4042c717d..7cd86d71a 100644 --- a/pkg/dist/buildpack.go +++ b/pkg/dist/buildpack.go @@ -1,5 +1,11 @@ package dist +import ( + "github.com/pkg/errors" + + "github.com/buildpacks/pack/internal/style" +) + const AssumedBuildpackAPIVersion = "0.1" const BuildpacksDir = "/cnb/buildpacks" @@ -20,6 +26,13 @@ func (b BuildpackInfo) FullName() string { return b.ID } +func (b BuildpackInfo) FullNameWithVersion() (string, error) { + if b.Version == "" { + return b.ID, errors.Errorf("buildpack %s does not have a version defined", style.Symbol(b.ID)) + } + return b.ID + "@" + b.Version, nil +} + // Satisfy stringer func (b BuildpackInfo) String() string { return b.FullName() }