mirror of https://github.com/buildpacks/pack.git
2101 lines
69 KiB
Go
2101 lines
69 KiB
Go
package builder_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/buildpacks/imgutil"
|
|
"github.com/buildpacks/imgutil/fakes"
|
|
"github.com/buildpacks/lifecycle/api"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/heroku/color"
|
|
"github.com/pkg/errors"
|
|
"github.com/sclevine/spec"
|
|
"github.com/sclevine/spec/report"
|
|
|
|
pubbldr "github.com/buildpacks/pack/builder"
|
|
"github.com/buildpacks/pack/internal/builder"
|
|
"github.com/buildpacks/pack/internal/builder/testmocks"
|
|
ifakes "github.com/buildpacks/pack/internal/fakes"
|
|
"github.com/buildpacks/pack/pkg/archive"
|
|
"github.com/buildpacks/pack/pkg/buildpack"
|
|
"github.com/buildpacks/pack/pkg/dist"
|
|
"github.com/buildpacks/pack/pkg/logging"
|
|
h "github.com/buildpacks/pack/testhelpers"
|
|
)
|
|
|
|
func TestBuilder(t *testing.T) {
|
|
color.Disable(true)
|
|
defer color.Disable(false)
|
|
spec.Run(t, "Builder", testBuilder, spec.Parallel(), spec.Report(report.Terminal{}))
|
|
}
|
|
|
|
func testBuilder(t *testing.T, when spec.G, it spec.S) {
|
|
var (
|
|
baseImage *fakes.Image
|
|
subject *builder.Builder
|
|
mockController *gomock.Controller
|
|
mockLifecycle *testmocks.MockLifecycle
|
|
bp1v1 buildpack.BuildModule
|
|
bp1v2 buildpack.BuildModule
|
|
bp2v1 buildpack.BuildModule
|
|
bp2v2 buildpack.BuildModule
|
|
ext1v1 buildpack.BuildModule
|
|
ext1v2 buildpack.BuildModule
|
|
ext2v1 buildpack.BuildModule
|
|
bpOrder buildpack.BuildModule
|
|
outBuf bytes.Buffer
|
|
logger logging.Logger
|
|
)
|
|
|
|
it.Before(func() {
|
|
logger = logging.NewLogWithWriters(&outBuf, &outBuf)
|
|
baseImage = fakes.NewImage("base/image", "", nil)
|
|
mockController = gomock.NewController(t)
|
|
|
|
lifecycleTarReader := archive.ReadDirAsTar(
|
|
filepath.Join("testdata", "lifecycle", "platform-0.4"),
|
|
".", 0, 0, 0755, true, false, nil,
|
|
)
|
|
|
|
descriptorContents, err := os.ReadFile(filepath.Join("testdata", "lifecycle", "platform-0.4", "lifecycle.toml"))
|
|
h.AssertNil(t, err)
|
|
|
|
lifecycleDescriptor, err := builder.ParseDescriptor(string(descriptorContents))
|
|
h.AssertNil(t, err)
|
|
|
|
mockLifecycle = testmocks.NewMockLifecycle(mockController)
|
|
mockLifecycle.EXPECT().Open().Return(lifecycleTarReader, nil).AnyTimes()
|
|
mockLifecycle.EXPECT().Descriptor().Return(builder.CompatDescriptor(lifecycleDescriptor)).AnyTimes()
|
|
|
|
bp1v1, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "buildpack-1-id",
|
|
Version: "buildpack-1-version-1",
|
|
},
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"mixinX", "mixinY"},
|
|
}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
bp1v2, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "buildpack-1-id",
|
|
Version: "buildpack-1-version-2",
|
|
},
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"mixinX", "mixinY"},
|
|
}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
bp2v1, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "buildpack-2-id",
|
|
Version: "buildpack-2-version-1",
|
|
},
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"build:mixinA", "run:mixinB"},
|
|
}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
ext1v1, err = ifakes.NewFakeExtension(dist.ExtensionDescriptor{
|
|
WithAPI: api.MustParse("0.9"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "extension-1-id",
|
|
Version: "extension-1-version-1",
|
|
},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
ext1v2, err = ifakes.NewFakeExtension(dist.ExtensionDescriptor{
|
|
WithAPI: api.MustParse("0.9"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "extension-1-id",
|
|
Version: "extension-1-version-2",
|
|
},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
ext2v1, err = ifakes.NewFakeExtension(dist.ExtensionDescriptor{
|
|
WithAPI: api.MustParse("0.9"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "extension-2-id",
|
|
Version: "extension-2-version-1",
|
|
},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
bpOrder, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "order-buildpack-id",
|
|
Version: "order-buildpack-version",
|
|
},
|
|
WithOrder: []dist.OrderEntry{{
|
|
Group: []dist.ModuleRef{
|
|
{
|
|
ModuleInfo: bp1v1.Descriptor().Info(),
|
|
Optional: true,
|
|
},
|
|
{
|
|
ModuleInfo: bp2v1.Descriptor().Info(),
|
|
Optional: false,
|
|
},
|
|
},
|
|
}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
})
|
|
|
|
it.After(func() {
|
|
h.AssertNilE(t, baseImage.Cleanup())
|
|
mockController.Finish()
|
|
})
|
|
|
|
when("the base image is not valid", func() {
|
|
when("#FromImage", func() {
|
|
when("metadata isn't valid", func() {
|
|
it("returns an error", func() {
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.builder.metadata",
|
|
`{"something-random": ,}`,
|
|
))
|
|
|
|
_, err := builder.FromImage(baseImage)
|
|
h.AssertError(t, err, "getting label")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("#New", func() {
|
|
when("metadata isn't valid", func() {
|
|
it("returns an error", func() {
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.builder.metadata",
|
|
`{"something-random": ,}`,
|
|
))
|
|
|
|
_, err := builder.FromImage(baseImage)
|
|
h.AssertError(t, err, "getting label")
|
|
})
|
|
})
|
|
|
|
when("missing CNB_USER_ID", func() {
|
|
it("returns an error", func() {
|
|
_, err := builder.New(baseImage, "some/builder")
|
|
h.AssertError(t, err, "image 'base/image' missing required env var 'CNB_USER_ID'")
|
|
})
|
|
})
|
|
|
|
when("missing CNB_GROUP_ID", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
})
|
|
|
|
it("returns an error", func() {
|
|
_, err := builder.New(baseImage, "some/builder")
|
|
h.AssertError(t, err, "image 'base/image' missing required env var 'CNB_GROUP_ID'")
|
|
})
|
|
})
|
|
|
|
when("CNB_USER_ID is not an int", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "not an int"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
})
|
|
|
|
it("returns an error", func() {
|
|
_, err := builder.New(baseImage, "some/builder")
|
|
h.AssertError(t, err, "failed to parse 'CNB_USER_ID', value 'not an int' should be an integer")
|
|
})
|
|
})
|
|
|
|
when("CNB_GROUP_ID is not an int", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "not an int"))
|
|
})
|
|
|
|
it("returns an error", func() {
|
|
_, err := builder.New(baseImage, "some/builder")
|
|
h.AssertError(t, err, "failed to parse 'CNB_GROUP_ID', value 'not an int' should be an integer")
|
|
})
|
|
})
|
|
|
|
when("missing stack id label and run image", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
})
|
|
|
|
it("does not return an error", func() {
|
|
_, err := builder.New(baseImage, "some/builder")
|
|
h.AssertNilE(t, err)
|
|
})
|
|
})
|
|
|
|
when("mixins metadata is malformed", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.id", "some-id"))
|
|
})
|
|
|
|
it("returns an error", func() {
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.mixins", `{"mixinX", "mixinY", "build:mixinA"}`))
|
|
_, err := builder.New(baseImage, "some/builder")
|
|
h.AssertError(t, err, "getting label io.buildpacks.stack.mixins")
|
|
})
|
|
})
|
|
|
|
when("order metadata is malformed", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.id", "some-id"))
|
|
})
|
|
|
|
it("returns an error", func() {
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.buildpack.order", `{"something", }`))
|
|
_, err := builder.New(baseImage, "some/builder")
|
|
h.AssertError(t, err, "getting label io.buildpacks.buildpack.order")
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
when("the base image is a valid build image", func() {
|
|
it.Before(func() {
|
|
var err error
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.id", "some.stack.id"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.mixins", `["mixinX", "mixinY", "build:mixinA"]`))
|
|
subject, err = builder.New(baseImage, "some/builder")
|
|
h.AssertNil(t, err)
|
|
|
|
subject.SetLifecycle(mockLifecycle)
|
|
})
|
|
|
|
it.After(func() {
|
|
h.AssertNilE(t, baseImage.Cleanup())
|
|
})
|
|
|
|
when("#Save", func() {
|
|
it("creates a builder from the image and renames it", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
h.AssertEq(t, baseImage.Name(), "some/builder")
|
|
})
|
|
|
|
it("adds creator metadata", func() {
|
|
testName := "test-name"
|
|
testVersion := "1.2.5"
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{
|
|
Name: testName,
|
|
Version: testVersion,
|
|
}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
|
|
h.AssertEq(t, metadata.CreatedBy.Name, testName)
|
|
h.AssertEq(t, metadata.CreatedBy.Version, testVersion)
|
|
})
|
|
|
|
it("adds creator name if not provided", func() {
|
|
testVersion := "1.2.5"
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{
|
|
Version: testVersion,
|
|
}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
|
|
h.AssertEq(t, metadata.CreatedBy.Name, "Pack CLI")
|
|
h.AssertEq(t, metadata.CreatedBy.Version, testVersion)
|
|
})
|
|
|
|
it("creates the workspace dir with CNB user and group", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/workspace")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/workspace",
|
|
h.IsDirectory(),
|
|
h.HasFileMode(0755),
|
|
h.HasOwnerAndGroup(1234, 4321),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("creates the layers dir with CNB user and group", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/layers")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/layers",
|
|
h.IsDirectory(),
|
|
h.HasOwnerAndGroup(1234, 4321),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("creates the cnb dir", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb",
|
|
h.IsDirectory(),
|
|
h.HasOwnerAndGroup(0, 0),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("creates the build-config dir", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/build-config")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/build-config",
|
|
h.IsDirectory(),
|
|
h.HasOwnerAndGroup(0, 0),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
it("creates the buildpacks dir", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/buildpacks")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/buildpacks",
|
|
h.IsDirectory(),
|
|
h.HasOwnerAndGroup(0, 0),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("creates the platform dir", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/platform")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/platform",
|
|
h.IsDirectory(),
|
|
h.HasOwnerAndGroup(0, 0),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
h.AssertOnTarEntry(t, layerTar, "/platform/env",
|
|
h.IsDirectory(),
|
|
h.HasOwnerAndGroup(0, 0),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("sets the working dir to the layers dir", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
workingDir, err := baseImage.WorkingDir()
|
|
h.AssertNil(t, err)
|
|
h.AssertEq(t, workingDir, "/layers")
|
|
})
|
|
|
|
it("does not overwrite the order layer when SetOrder has not been called", func() {
|
|
tmpDir, err := os.MkdirTemp("", "")
|
|
h.AssertNil(t, err)
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
layerFile := filepath.Join(tmpDir, "order.tar")
|
|
err = archive.CreateSingleFileTar(layerFile, "/cnb/order.toml", "some content")
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertNil(t, baseImage.AddLayer(layerFile))
|
|
h.AssertNil(t, baseImage.Save())
|
|
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/order.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/order.toml", h.ContentEquals("some content"))
|
|
})
|
|
|
|
it("adds additional tags as requested", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}, "additional-tag-one", "additional-tag-two"))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
h.AssertEq(t, baseImage.Name(), "some/builder")
|
|
savedNames := baseImage.SavedNames()
|
|
slices.Sort(savedNames)
|
|
h.AssertEq(t, 3, len(savedNames))
|
|
h.AssertEq(t, "additional-tag-one", savedNames[0])
|
|
h.AssertEq(t, "additional-tag-two", savedNames[1])
|
|
h.AssertEq(t, "some/builder", savedNames[2])
|
|
})
|
|
|
|
when("validating order", func() {
|
|
it.Before(func() {
|
|
subject.SetLifecycle(mockLifecycle)
|
|
})
|
|
|
|
when("has single buildpack", func() {
|
|
it.Before(func() {
|
|
subject.AddBuildpack(bp1v1)
|
|
})
|
|
|
|
it("should resolve unset version (to legacy label and order.toml)", func() {
|
|
subject.SetOrder(dist.Order{{
|
|
Group: []dist.ModuleRef{
|
|
{ModuleInfo: dist.ModuleInfo{ID: bp1v1.Descriptor().Info().ID}}},
|
|
}})
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/order.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/order.toml", h.ContentEquals(`[[order]]
|
|
|
|
[[order.group]]
|
|
id = "buildpack-1-id"
|
|
version = "buildpack-1-version-1"
|
|
`))
|
|
})
|
|
|
|
when("order points to missing buildpack id", func() {
|
|
it("should error", func() {
|
|
subject.SetOrder(dist.Order{{
|
|
Group: []dist.ModuleRef{
|
|
{ModuleInfo: dist.ModuleInfo{ID: "missing-buildpack-id"}}},
|
|
}})
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t, err, "no versions of buildpack 'missing-buildpack-id' were found on the builder")
|
|
})
|
|
})
|
|
|
|
when("order points to missing buildpack version", func() {
|
|
it("should error", func() {
|
|
subject.SetOrder(dist.Order{{
|
|
Group: []dist.ModuleRef{
|
|
{ModuleInfo: dist.ModuleInfo{ID: "buildpack-1-id", Version: "missing-buildpack-version"}}},
|
|
}})
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t, err, "buildpack 'buildpack-1-id' with version 'missing-buildpack-version' was not found on the builder")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("has repeated buildpacks with the same ID and version", func() {
|
|
it.Before(func() {
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bp1v1)
|
|
})
|
|
|
|
when("order omits version", func() {
|
|
it("should de-duplicate identical buildpacks", func() {
|
|
subject.SetOrder(dist.Order{
|
|
{Group: []dist.ModuleRef{{
|
|
ModuleInfo: dist.ModuleInfo{
|
|
ID: bp1v1.Descriptor().Info().ID,
|
|
Homepage: bp1v1.Descriptor().Info().Homepage,
|
|
}}},
|
|
},
|
|
{Group: []dist.ModuleRef{{
|
|
ModuleInfo: dist.ModuleInfo{
|
|
ID: bp1v1.Descriptor().Info().ID,
|
|
Homepage: bp1v1.Descriptor().Info().Homepage,
|
|
}}},
|
|
},
|
|
})
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
})
|
|
})
|
|
})
|
|
|
|
when("has multiple buildpacks with same ID", func() {
|
|
it.Before(func() {
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bp1v2)
|
|
})
|
|
|
|
when("order explicitly sets version", func() {
|
|
it("should keep order version", func() {
|
|
subject.SetOrder(dist.Order{{
|
|
Group: []dist.ModuleRef{
|
|
{ModuleInfo: bp1v1.Descriptor().Info()}},
|
|
}})
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/order.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/order.toml", h.ContentEquals(`[[order]]
|
|
|
|
[[order.group]]
|
|
id = "buildpack-1-id"
|
|
version = "buildpack-1-version-1"
|
|
`))
|
|
})
|
|
})
|
|
|
|
when("order version is empty", func() {
|
|
it("return error", func() {
|
|
subject.SetOrder(dist.Order{{
|
|
Group: []dist.ModuleRef{
|
|
{ModuleInfo: dist.ModuleInfo{ID: "buildpack-1-id"}}},
|
|
}})
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertError(t, err, "multiple versions of 'buildpack-1-id' - must specify an explicit version")
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
when("validating buildpacks", func() {
|
|
when("nested buildpack does not exist", func() {
|
|
when("buildpack by id does not exist", func() {
|
|
it("returns an error", func() {
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bpOrder)
|
|
|
|
// order buildpack requires bp2v1
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t, err, "buildpack 'buildpack-2-id@buildpack-2-version-1' not found on the builder")
|
|
})
|
|
})
|
|
|
|
when("buildpack version does not exist", func() {
|
|
it("returns an error", func() {
|
|
subject.AddBuildpack(bp1v2)
|
|
subject.AddBuildpack(bp2v1)
|
|
|
|
// order buildpack requires bp1v1 rather than bp1v2
|
|
subject.AddBuildpack(bpOrder)
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t, err, "buildpack 'buildpack-1-id@buildpack-1-version-1' not found on the builder")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("buildpack stack id does not match", func() {
|
|
it("returns an error", func() {
|
|
bp, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: bp1v1.Descriptor().Info(),
|
|
WithStacks: []dist.Stack{{ID: "other.stack.id"}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
subject.AddBuildpack(bp)
|
|
err = subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t, err, "buildpack 'buildpack-1-id@buildpack-1-version-1' does not support stack 'some.stack.id'")
|
|
})
|
|
})
|
|
|
|
when("buildpack is not compatible with lifecycle", func() {
|
|
it("returns an error", func() {
|
|
bp, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.1"),
|
|
WithInfo: bp1v1.Descriptor().Info(),
|
|
WithStacks: []dist.Stack{{ID: "some.stack.id"}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
subject.AddBuildpack(bp)
|
|
err = subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t,
|
|
err,
|
|
"buildpack 'buildpack-1-id@buildpack-1-version-1' (Buildpack API 0.1) is incompatible with lifecycle '0.0.0' (Buildpack API(s) 0.2, 0.3, 0.4, 0.9)")
|
|
})
|
|
})
|
|
|
|
when("buildpack mixins are not satisfied", func() {
|
|
it("returns an error", func() {
|
|
bp, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: bp1v1.Descriptor().Info(),
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"missing"},
|
|
}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
|
|
subject.AddBuildpack(bp)
|
|
err = subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t, err, "buildpack 'buildpack-1-id@buildpack-1-version-1' requires missing mixin(s): missing")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("getting layers label", func() {
|
|
it("fails if layers label isn't set correctly", func() {
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.buildpack.layers",
|
|
`{"something-here: }`,
|
|
))
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertError(t, err, "getting label io.buildpacks.buildpack.layers")
|
|
})
|
|
})
|
|
|
|
when("saving with duplicated buildpacks", func() {
|
|
it("adds a single buildpack to the builder image", func() {
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bp2v1)
|
|
subject.AddBuildpack(bp1v1)
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
// Expect 6 layers from the following locations:
|
|
// - 1 from defaultDirsLayer
|
|
// - 1 from lifecycleLayer
|
|
// - 2 from buildpacks
|
|
// - 1 from orderLayer
|
|
// - 1 from stackLayer
|
|
// - 1 from runImageLayer
|
|
h.AssertEq(t, baseImage.NumberOfAddedLayers(), 7)
|
|
})
|
|
|
|
when("duplicated buildpack, has different contents", func() {
|
|
var bp1v1Alt buildpack.BuildModule
|
|
var bp1v1AltWithNewContent buildpack.BuildModule
|
|
it.Before(func() {
|
|
var err error
|
|
bp1v1Alt, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "buildpack-1-id",
|
|
Version: "buildpack-1-version-1",
|
|
},
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"mixinX", "mixinY"},
|
|
}},
|
|
}, 0644, ifakes.WithExtraBuildpackContents("coolbeans", "a file cool as beans"))
|
|
|
|
h.AssertNil(t, err)
|
|
|
|
bp1v1AltWithNewContent, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "buildpack-1-id",
|
|
Version: "buildpack-1-version-1",
|
|
},
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"mixinX", "mixinY"},
|
|
}},
|
|
}, 0644, ifakes.WithExtraBuildpackContents("coolwatermelon", "a file cool as watermelon"))
|
|
|
|
h.AssertNil(t, err)
|
|
})
|
|
|
|
it("uses the whiteout layers", func() {
|
|
logger := logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose())
|
|
|
|
subject.AddBuildpack(bp1v1Alt)
|
|
subject.AddBuildpack(bp1v1AltWithNewContent)
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
oldPath := filepath.Join("/cnb", "buildpacks", "buildpack-1-id", "buildpack-1-version-1", "coolbeans")
|
|
layer, err := baseImage.FindLayerWithPath(oldPath)
|
|
|
|
h.AssertEq(t, layer, "")
|
|
h.AssertError(t, err, fmt.Sprintf("could not find '%s' in any layer", oldPath))
|
|
|
|
newPath := filepath.Join("/cnb", "buildpacks", "buildpack-1-id", "buildpack-1-version-1", "coolwatermelon")
|
|
layer, err = baseImage.FindLayerWithPath(newPath)
|
|
|
|
h.AssertNotEq(t, layer, "")
|
|
h.AssertNil(t, err)
|
|
})
|
|
|
|
it("uses the last buildpack", func() {
|
|
logger := logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose())
|
|
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bp1v1Alt)
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
// Expect 5 layers from the following locations:
|
|
// - 1 from defaultDirsLayer
|
|
// - 1 from lifecycleLayer
|
|
// - 1 from buildpacks
|
|
// - 1 from orderLayer
|
|
// - 1 from stackLayer
|
|
// - 1 from runImageLayer
|
|
h.AssertEq(t, baseImage.NumberOfAddedLayers(), 6)
|
|
oldSha256 := "2ba2e8563f7f43533ba26047a44f3e8bb7dd009043bd73a0e6aadb02c084955c"
|
|
newSha256 := "719faea06424d01bb5788ce63c1167e8d382b2d9df8fcf3a0a54ea9b2e3b4045"
|
|
if runtime.GOOS == "windows" {
|
|
newSha256 = "d99d31efba72ebf98e8101ada9e89464566e943c05367c561b116c2cb86837c9"
|
|
}
|
|
|
|
h.AssertContains(t, outBuf.String(), fmt.Sprintf(`buildpack 'buildpack-1-id@buildpack-1-version-1' was previously defined with different contents and will be overwritten
|
|
- previous diffID: 'sha256:%s'
|
|
- using diffID: 'sha256:%s'`, oldSha256, newSha256))
|
|
|
|
layer, err := baseImage.FindLayerWithPath(filepath.Join("/cnb", "buildpacks", "buildpack-1-id", "buildpack-1-version-1", "coolbeans"))
|
|
h.AssertNil(t, err)
|
|
|
|
bpLayer, err := os.Open(layer)
|
|
h.AssertNil(t, err)
|
|
defer bpLayer.Close()
|
|
|
|
hsh := sha256.New()
|
|
_, err = io.Copy(hsh, bpLayer)
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertEq(t, newSha256, fmt.Sprintf("%x", hsh.Sum(nil)))
|
|
})
|
|
})
|
|
|
|
when("adding buildpack that already exists on the image", func() {
|
|
it("skips adding buildpack that already exists", func() {
|
|
logger := logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose())
|
|
diffID := "2ba2e8563f7f43533ba26047a44f3e8bb7dd009043bd73a0e6aadb02c084955c"
|
|
bpLayer := dist.ModuleLayers{
|
|
"buildpack-1-id": map[string]dist.ModuleLayerInfo{
|
|
"buildpack-1-version-1": {
|
|
API: api.MustParse("0.2"),
|
|
Stacks: nil,
|
|
Order: nil,
|
|
LayerDiffID: fmt.Sprintf("sha256:%s", diffID),
|
|
Homepage: "",
|
|
},
|
|
},
|
|
}
|
|
bpLayerString, err := json.Marshal(bpLayer)
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertNil(t, baseImage.SetLabel( // label builder as already having a buildpack with diffID `diffID`
|
|
dist.BuildpackLayersLabel,
|
|
string(bpLayerString),
|
|
))
|
|
|
|
subject.AddBuildpack(bp1v1)
|
|
err = subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
|
|
fmt.Println(outBuf.String())
|
|
expectedLog := "Buildpack 'buildpack-1-id@buildpack-1-version-1' already exists on builder with same contents, skipping..."
|
|
h.AssertContains(t, outBuf.String(), expectedLog)
|
|
})
|
|
})
|
|
})
|
|
|
|
when("error adding buildpacks to builder", func() {
|
|
when("unable to convert buildpack to layer tar", func() {
|
|
var bp1v1Err buildpack.BuildModule
|
|
it.Before(func() {
|
|
var err error
|
|
bp1v1Err, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "buildpack-1-id",
|
|
Version: "buildpack-1-version-1",
|
|
},
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"mixinX", "mixinY"},
|
|
}},
|
|
}, 0644, ifakes.WithBpOpenError(errors.New("unable to open buildpack")))
|
|
h.AssertNil(t, err)
|
|
})
|
|
it("errors", func() {
|
|
subject.AddBuildpack(bp1v1Err)
|
|
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
|
|
h.AssertError(t, err, "unable to open buildpack")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("modules are added in random order", func() {
|
|
var fakeLayerImage *h.FakeAddedLayerImage
|
|
|
|
it.Before(func() {
|
|
var err error
|
|
fakeLayerImage = &h.FakeAddedLayerImage{Image: baseImage}
|
|
subject, err = builder.New(fakeLayerImage, "some/builder")
|
|
h.AssertNil(t, err)
|
|
subject.SetLifecycle(mockLifecycle)
|
|
|
|
bp2v2, err = ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{
|
|
WithAPI: api.MustParse("0.2"),
|
|
WithInfo: dist.ModuleInfo{
|
|
ID: "buildpack-2-id",
|
|
Version: "buildpack-2-version-2",
|
|
},
|
|
WithStacks: []dist.Stack{{
|
|
ID: "some.stack.id",
|
|
Mixins: []string{"build:mixinA", "run:mixinB"},
|
|
}},
|
|
}, 0644)
|
|
h.AssertNil(t, err)
|
|
})
|
|
|
|
it("layers are written ordered by buildpacks ID & Version", func() {
|
|
// add buildpacks in a random order
|
|
subject.AddBuildpack(bp2v2)
|
|
subject.AddBuildpack(bp1v2)
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bp2v1)
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
|
|
layers := fakeLayerImage.AddedLayersOrder()
|
|
h.AssertEq(t, len(layers), 4)
|
|
h.AssertTrue(t, strings.Contains(layers[0], h.LayerFileName(bp1v1)))
|
|
h.AssertTrue(t, strings.Contains(layers[1], h.LayerFileName(bp1v2)))
|
|
h.AssertTrue(t, strings.Contains(layers[2], h.LayerFileName(bp2v1)))
|
|
h.AssertTrue(t, strings.Contains(layers[3], h.LayerFileName(bp2v2)))
|
|
})
|
|
|
|
it("extensions are written ordered by buildpacks ID & Version", func() {
|
|
// add buildpacks in a random order
|
|
subject.AddBuildpack(ext2v1)
|
|
subject.AddBuildpack(ext1v2)
|
|
subject.AddBuildpack(ext1v1)
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
|
|
layers := fakeLayerImage.AddedLayersOrder()
|
|
h.AssertEq(t, len(layers), 3)
|
|
h.AssertTrue(t, strings.Contains(layers[0], h.LayerFileName(ext1v1)))
|
|
h.AssertTrue(t, strings.Contains(layers[1], h.LayerFileName(ext1v2)))
|
|
h.AssertTrue(t, strings.Contains(layers[2], h.LayerFileName(ext2v1)))
|
|
})
|
|
})
|
|
|
|
when("system buildpacks", func() {
|
|
it.Before(func() {
|
|
subject.SetLifecycle(mockLifecycle)
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.SetSystem(dist.System{
|
|
Pre: dist.SystemBuildpacks{
|
|
Buildpacks: []dist.ModuleRef{
|
|
{ModuleInfo: dist.ModuleInfo{ID: bp1v1.Descriptor().Info().ID}}},
|
|
},
|
|
})
|
|
})
|
|
|
|
it("should write system buildpacks to system.toml)", func() {
|
|
err := subject.Save(logger, builder.CreatorMetadata{})
|
|
h.AssertNil(t, err)
|
|
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/system.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/system.toml", h.ContentEquals(`[system]
|
|
[system.pre]
|
|
|
|
[[system.pre.buildpacks]]
|
|
id = "buildpack-1-id"
|
|
version = "buildpack-1-version-1"
|
|
`))
|
|
})
|
|
})
|
|
})
|
|
when("#SetLifecycle", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("should set the lifecycle version successfully", func() {
|
|
h.AssertEq(t, subject.LifecycleDescriptor().Info.Version.String(), "0.0.0")
|
|
})
|
|
|
|
it("should add the lifecycle binaries as an image layer", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/lifecycle")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle",
|
|
h.IsDirectory(),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/detector",
|
|
h.ContentEquals("detector"),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/restorer",
|
|
h.ContentEquals("restorer"),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/analyzer",
|
|
h.ContentEquals("analyzer"),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/builder",
|
|
h.ContentEquals("builder"),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/exporter",
|
|
h.ContentEquals("exporter"),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/launcher",
|
|
h.ContentEquals("launcher"),
|
|
h.HasFileMode(0755),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
|
|
it("should add lifecycle symlink", func() {
|
|
h.AssertOnTarEntry(t, layerTar, "/lifecycle",
|
|
h.SymlinksTo("/cnb/lifecycle"),
|
|
h.HasFileMode(0644),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
})
|
|
|
|
it("sets the lifecycle version on the metadata", func() {
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, metadata.Lifecycle.Version.String(), "0.0.0")
|
|
h.AssertEq(t, metadata.Lifecycle.API.BuildpackVersion.String(), "0.2")
|
|
h.AssertEq(t, metadata.Lifecycle.API.PlatformVersion.String(), "0.2")
|
|
h.AssertNotNil(t, metadata.Lifecycle.APIs)
|
|
h.AssertEq(t, metadata.Lifecycle.APIs.Buildpack.Deprecated.AsStrings(), []string{})
|
|
h.AssertEq(t, metadata.Lifecycle.APIs.Buildpack.Supported.AsStrings(), []string{"0.2", "0.3", "0.4", "0.9"})
|
|
h.AssertEq(t, metadata.Lifecycle.APIs.Platform.Deprecated.AsStrings(), []string{"0.2"})
|
|
h.AssertEq(t, metadata.Lifecycle.APIs.Platform.Supported.AsStrings(), []string{"0.3", "0.4"})
|
|
})
|
|
})
|
|
|
|
when("#AddBuildpack", func() {
|
|
it.Before(func() {
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bp1v2)
|
|
subject.AddBuildpack(bp2v1)
|
|
subject.AddBuildpack(bpOrder)
|
|
})
|
|
|
|
it("adds the buildpack as an image layer", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
assertImageHasBPLayer(t, baseImage, bp1v1)
|
|
assertImageHasBPLayer(t, baseImage, bp1v2)
|
|
assertImageHasBPLayer(t, baseImage, bp2v1)
|
|
assertImageHasOrderBpLayer(t, baseImage, bpOrder)
|
|
})
|
|
|
|
it("adds the buildpack metadata", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, len(metadata.Buildpacks), 4)
|
|
|
|
h.AssertEq(t, metadata.Buildpacks[0].ID, "buildpack-1-id")
|
|
h.AssertEq(t, metadata.Buildpacks[0].Version, "buildpack-1-version-1")
|
|
|
|
h.AssertEq(t, metadata.Buildpacks[1].ID, "buildpack-1-id")
|
|
h.AssertEq(t, metadata.Buildpacks[1].Version, "buildpack-1-version-2")
|
|
|
|
h.AssertEq(t, metadata.Buildpacks[2].ID, "buildpack-2-id")
|
|
h.AssertEq(t, metadata.Buildpacks[2].Version, "buildpack-2-version-1")
|
|
|
|
h.AssertEq(t, metadata.Buildpacks[3].ID, "order-buildpack-id")
|
|
h.AssertEq(t, metadata.Buildpacks[3].Version, "order-buildpack-version")
|
|
})
|
|
|
|
it("adds the buildpack layers label", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.buildpack.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
h.AssertEq(t, len(layers), 3)
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]), 2)
|
|
h.AssertEq(t, len(layers["buildpack-2-id"]), 1)
|
|
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]["buildpack-1-version-1"].Order), 0)
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]["buildpack-1-version-1"].Stacks), 1)
|
|
h.AssertEq(t, layers["buildpack-1-id"]["buildpack-1-version-1"].Stacks[0].ID, "some.stack.id")
|
|
h.AssertSliceContainsOnly(t, layers["buildpack-1-id"]["buildpack-1-version-1"].Stacks[0].Mixins, "mixinX", "mixinY")
|
|
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]["buildpack-1-version-2"].Order), 0)
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]["buildpack-1-version-2"].Stacks), 1)
|
|
h.AssertEq(t, layers["buildpack-1-id"]["buildpack-1-version-2"].Stacks[0].ID, "some.stack.id")
|
|
h.AssertSliceContainsOnly(t, layers["buildpack-1-id"]["buildpack-1-version-2"].Stacks[0].Mixins, "mixinX", "mixinY")
|
|
|
|
h.AssertEq(t, len(layers["buildpack-2-id"]["buildpack-2-version-1"].Order), 0)
|
|
h.AssertEq(t, len(layers["buildpack-2-id"]["buildpack-2-version-1"].Stacks), 1)
|
|
h.AssertEq(t, layers["buildpack-2-id"]["buildpack-2-version-1"].Stacks[0].ID, "some.stack.id")
|
|
h.AssertSliceContainsOnly(t, layers["buildpack-2-id"]["buildpack-2-version-1"].Stacks[0].Mixins, "build:mixinA", "run:mixinB")
|
|
|
|
h.AssertEq(t, len(layers["order-buildpack-id"]["order-buildpack-version"].Order), 1)
|
|
h.AssertEq(t, len(layers["order-buildpack-id"]["order-buildpack-version"].Order[0].Group), 2)
|
|
h.AssertEq(t, layers["order-buildpack-id"]["order-buildpack-version"].Order[0].Group[0].ID, "buildpack-1-id")
|
|
h.AssertEq(t, layers["order-buildpack-id"]["order-buildpack-version"].Order[0].Group[0].Version, "buildpack-1-version-1")
|
|
h.AssertEq(t, layers["order-buildpack-id"]["order-buildpack-version"].Order[0].Group[0].Optional, true)
|
|
h.AssertEq(t, layers["order-buildpack-id"]["order-buildpack-version"].Order[0].Group[1].ID, "buildpack-2-id")
|
|
h.AssertEq(t, layers["order-buildpack-id"]["order-buildpack-version"].Order[0].Group[1].Version, "buildpack-2-version-1")
|
|
h.AssertEq(t, layers["order-buildpack-id"]["order-buildpack-version"].Order[0].Group[1].Optional, false)
|
|
})
|
|
|
|
when("base image already has buildpack layers label", func() {
|
|
it.Before(func() {
|
|
var mdJSON bytes.Buffer
|
|
h.AssertNil(t, json.Compact(
|
|
&mdJSON,
|
|
[]byte(`{
|
|
"buildpack-1-id": {
|
|
"buildpack-1-version-1": {
|
|
"layerDiffID": "sha256:buildpack-1-version-1-diff-id"
|
|
},
|
|
"buildpack-1-version-2": {
|
|
"layerDiffID": "sha256:buildpack-1-version-2-diff-id"
|
|
}
|
|
}
|
|
}
|
|
`)))
|
|
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.buildpack.layers",
|
|
mdJSON.String(),
|
|
))
|
|
|
|
var err error
|
|
subject, err = builder.New(baseImage, "some/builder")
|
|
h.AssertNil(t, err)
|
|
|
|
subject.AddBuildpack(bp1v2)
|
|
subject.AddBuildpack(bp2v1)
|
|
|
|
subject.SetLifecycle(mockLifecycle)
|
|
})
|
|
|
|
it("appends buildpack layer info", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.buildpack.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
h.AssertEq(t, len(layers), 2)
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]), 2)
|
|
h.AssertEq(t, len(layers["buildpack-2-id"]), 1)
|
|
|
|
h.AssertEq(t, layers["buildpack-1-id"]["buildpack-1-version-1"].LayerDiffID, "sha256:buildpack-1-version-1-diff-id")
|
|
|
|
h.AssertUnique(t,
|
|
layers["buildpack-1-id"]["buildpack-1-version-1"].LayerDiffID,
|
|
layers["buildpack-1-id"]["buildpack-1-version-2"].LayerDiffID,
|
|
layers["buildpack-2-id"]["buildpack-2-version-1"].LayerDiffID,
|
|
)
|
|
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]["buildpack-1-version-1"].Order), 0)
|
|
h.AssertEq(t, len(layers["buildpack-1-id"]["buildpack-1-version-2"].Order), 0)
|
|
h.AssertEq(t, len(layers["buildpack-2-id"]["buildpack-2-version-1"].Order), 0)
|
|
})
|
|
|
|
it("informs when overriding existing buildpack, and log level is DEBUG", func() {
|
|
logger := logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose())
|
|
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.buildpack.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
|
|
h.AssertContains(t,
|
|
outBuf.String(),
|
|
"buildpack 'buildpack-1-id@buildpack-1-version-2' already exists on builder and will be overwritten",
|
|
)
|
|
h.AssertNotContains(t, layers["buildpack-1-id"]["buildpack-1-version-2"].LayerDiffID, "buildpack-1-version-2-diff-id")
|
|
})
|
|
|
|
it("doesn't message when overriding existing buildpack when log level is INFO", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.buildpack.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
|
|
h.AssertNotContains(t,
|
|
outBuf.String(),
|
|
"buildpack 'buildpack-1-id@buildpack-1-version-2' already exists on builder and will be overwritten",
|
|
)
|
|
h.AssertNotContains(t, layers["buildpack-1-id"]["buildpack-1-version-2"].LayerDiffID, "buildpack-1-version-2-diff-id")
|
|
})
|
|
})
|
|
|
|
when("base image already has metadata", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.builder.metadata",
|
|
`{
|
|
"buildpacks":[{"id":"prev.id"}],
|
|
"groups":[{"buildpacks":[{"id":"prev.id"}]}],
|
|
"stack":{"runImage":{"image":"prev/run","mirrors":["prev/mirror"]}},
|
|
"lifecycle":{"version":"6.6.6","apis":{"buildpack":{"deprecated":["0.1"],"supported":["0.2","0.3"]},"platform":{"deprecated":[],"supported":["2.3","2.4"]}}}
|
|
}`,
|
|
))
|
|
|
|
var err error
|
|
subject, err = builder.New(baseImage, "some/builder")
|
|
h.AssertNil(t, err)
|
|
|
|
subject.AddBuildpack(bp1v1)
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("appends the buildpack to the metadata", func() {
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, len(metadata.Buildpacks), 2)
|
|
|
|
// keeps original metadata
|
|
h.AssertEq(t, metadata.Buildpacks[0].ID, "prev.id")
|
|
h.AssertEq(t, metadata.Stack.RunImage.Image, "prev/run")
|
|
h.AssertEq(t, metadata.Stack.RunImage.Mirrors[0], "prev/mirror")
|
|
h.AssertEq(t, subject.LifecycleDescriptor().Info.Version.String(), "6.6.6")
|
|
|
|
// adds new buildpack
|
|
h.AssertEq(t, metadata.Buildpacks[1].ID, "buildpack-1-id")
|
|
h.AssertEq(t, metadata.Buildpacks[1].Version, "buildpack-1-version-1")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("#AddExtension", func() {
|
|
it.Before(func() {
|
|
subject.AddExtension(ext1v1)
|
|
subject.AddExtension(ext1v2)
|
|
subject.AddExtension(ext2v1)
|
|
})
|
|
|
|
it("adds the extension as an image layer", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
assertImageHasExtLayer(t, baseImage, ext1v1)
|
|
assertImageHasExtLayer(t, baseImage, ext1v2)
|
|
assertImageHasExtLayer(t, baseImage, ext2v1)
|
|
})
|
|
|
|
it("adds the extension metadata", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, len(metadata.Extensions), 3)
|
|
|
|
h.AssertEq(t, metadata.Extensions[0].ID, "extension-1-id")
|
|
h.AssertEq(t, metadata.Extensions[0].Version, "extension-1-version-1")
|
|
|
|
h.AssertEq(t, metadata.Extensions[1].ID, "extension-1-id")
|
|
h.AssertEq(t, metadata.Extensions[1].Version, "extension-1-version-2")
|
|
|
|
h.AssertEq(t, metadata.Extensions[2].ID, "extension-2-id")
|
|
h.AssertEq(t, metadata.Extensions[2].Version, "extension-2-version-1")
|
|
})
|
|
|
|
it("adds the extension layers label", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.extension.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
h.AssertEq(t, len(layers), 2)
|
|
h.AssertEq(t, len(layers["extension-1-id"]), 2)
|
|
h.AssertEq(t, len(layers["extension-2-id"]), 1)
|
|
|
|
h.AssertEq(t, layers["extension-1-id"]["extension-1-version-1"].API.String(), "0.9")
|
|
h.AssertEq(t, layers["extension-1-id"]["extension-1-version-2"].API.String(), "0.9")
|
|
h.AssertEq(t, layers["extension-2-id"]["extension-2-version-1"].API.String(), "0.9")
|
|
})
|
|
|
|
when("base image already has extension layers label", func() {
|
|
it.Before(func() {
|
|
var mdJSON bytes.Buffer
|
|
h.AssertNil(t, json.Compact(
|
|
&mdJSON,
|
|
[]byte(`{
|
|
"extension-1-id": {
|
|
"extension-1-version-1": {
|
|
"layerDiffID": "sha256:extension-1-version-1-diff-id"
|
|
},
|
|
"extension-1-version-2": {
|
|
"layerDiffID": "sha256:extension-1-version-2-diff-id"
|
|
}
|
|
}
|
|
}
|
|
`)))
|
|
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.extension.layers",
|
|
mdJSON.String(),
|
|
))
|
|
|
|
var err error
|
|
subject, err = builder.New(baseImage, "some/builder")
|
|
h.AssertNil(t, err)
|
|
|
|
subject.AddExtension(ext1v2)
|
|
subject.AddExtension(ext2v1)
|
|
|
|
subject.SetLifecycle(mockLifecycle)
|
|
})
|
|
|
|
it("appends extension layer info", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.extension.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
h.AssertEq(t, len(layers), 2)
|
|
h.AssertEq(t, len(layers["extension-1-id"]), 2)
|
|
h.AssertEq(t, len(layers["extension-2-id"]), 1)
|
|
|
|
h.AssertEq(t, layers["extension-1-id"]["extension-1-version-1"].LayerDiffID, "sha256:extension-1-version-1-diff-id")
|
|
|
|
h.AssertUnique(t,
|
|
layers["extension-1-id"]["extension-1-version-1"].LayerDiffID,
|
|
layers["extension-1-id"]["extension-1-version-2"].LayerDiffID,
|
|
layers["extension-2-id"]["extension-2-version-1"].LayerDiffID,
|
|
)
|
|
})
|
|
|
|
it("informs when overriding existing extension, and log level is DEBUG", func() {
|
|
logger := logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose())
|
|
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.extension.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
|
|
h.AssertContains(t,
|
|
outBuf.String(),
|
|
"extension 'extension-1-id@extension-1-version-2' already exists on builder and will be overwritten",
|
|
)
|
|
h.AssertNotContains(t, layers["extension-1-id"]["extension-1-version-2"].LayerDiffID, "extension-1-version-2-diff-id")
|
|
})
|
|
|
|
it("doesn't message when overriding existing extension when log level is INFO", func() {
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
|
|
label, err := baseImage.Label("io.buildpacks.extension.layers")
|
|
h.AssertNil(t, err)
|
|
|
|
var layers dist.ModuleLayers
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &layers))
|
|
|
|
h.AssertNotContains(t,
|
|
outBuf.String(),
|
|
"extension 'extension-1-id@extension-1-version-2' already exists on builder and will be overwritten",
|
|
)
|
|
h.AssertNotContains(t, layers["extension-1-id"]["extension-1-version-2"].LayerDiffID, "extension-1-version-2-diff-id")
|
|
})
|
|
})
|
|
|
|
when("base image already has metadata", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.builder.metadata",
|
|
`{
|
|
"extensions":[{"id":"prev.id"}],
|
|
"lifecycle":{"version":"6.6.6","apis":{"buildpack":{"deprecated":["0.1"],"supported":["0.2","0.3","0.9"]},"platform":{"deprecated":[],"supported":["2.3","2.4"]}}}
|
|
}`,
|
|
))
|
|
|
|
var err error
|
|
subject, err = builder.New(baseImage, "some/builder")
|
|
h.AssertNil(t, err)
|
|
|
|
subject.AddExtension(ext1v1)
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("appends the extensions to the metadata", func() {
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, len(metadata.Extensions), 2)
|
|
|
|
// keeps original metadata
|
|
h.AssertEq(t, metadata.Extensions[0].ID, "prev.id")
|
|
h.AssertEq(t, subject.LifecycleDescriptor().Info.Version.String(), "6.6.6")
|
|
|
|
// adds new extension
|
|
h.AssertEq(t, metadata.Extensions[1].ID, "extension-1-id")
|
|
h.AssertEq(t, metadata.Extensions[1].Version, "extension-1-version-1")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("#SetOrder", func() {
|
|
when("the buildpacks exist in the image", func() {
|
|
it.Before(func() {
|
|
subject.AddBuildpack(bp1v1)
|
|
subject.AddBuildpack(bp2v1)
|
|
subject.SetOrder(dist.Order{
|
|
{Group: []dist.ModuleRef{
|
|
{
|
|
ModuleInfo: dist.ModuleInfo{
|
|
ID: bp1v1.Descriptor().Info().ID,
|
|
// Version excluded intentionally
|
|
},
|
|
},
|
|
{
|
|
ModuleInfo: bp2v1.Descriptor().Info(),
|
|
Optional: true,
|
|
},
|
|
}},
|
|
})
|
|
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("adds the order.toml to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/order.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/order.toml",
|
|
h.ContentEquals(`[[order]]
|
|
|
|
[[order.group]]
|
|
id = "buildpack-1-id"
|
|
version = "buildpack-1-version-1"
|
|
|
|
[[order.group]]
|
|
id = "buildpack-2-id"
|
|
version = "buildpack-2-version-1"
|
|
optional = true
|
|
`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("adds the order to the order label", func() {
|
|
label, err := baseImage.Label("io.buildpacks.buildpack.order")
|
|
h.AssertNil(t, err)
|
|
|
|
var order dist.Order
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &order))
|
|
h.AssertEq(t, len(order), 1)
|
|
h.AssertEq(t, len(order[0].Group), 2)
|
|
h.AssertEq(t, order[0].Group[0].ID, "buildpack-1-id")
|
|
h.AssertEq(t, order[0].Group[0].Version, "")
|
|
h.AssertEq(t, order[0].Group[0].Optional, false)
|
|
h.AssertEq(t, order[0].Group[1].ID, "buildpack-2-id")
|
|
h.AssertEq(t, order[0].Group[1].Version, "buildpack-2-version-1")
|
|
h.AssertEq(t, order[0].Group[1].Optional, true)
|
|
})
|
|
})
|
|
})
|
|
|
|
when("#SetOrderExtensions", func() {
|
|
when("the extensions exist in the image", func() {
|
|
it.Before(func() {
|
|
subject.AddExtension(ext1v1)
|
|
subject.AddExtension(ext2v1)
|
|
subject.SetOrderExtensions(dist.Order{
|
|
{Group: []dist.ModuleRef{
|
|
{
|
|
ModuleInfo: dist.ModuleInfo{
|
|
ID: ext1v1.Descriptor().Info().ID,
|
|
// Version excluded intentionally
|
|
},
|
|
},
|
|
{
|
|
ModuleInfo: ext2v1.Descriptor().Info(),
|
|
Optional: true, // extensions are always optional; this shouldn't be redundantly printed
|
|
},
|
|
}},
|
|
})
|
|
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("adds the order.toml to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/order.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/order.toml",
|
|
h.ContentEquals(`[[order-extensions]]
|
|
|
|
[[order-extensions.group]]
|
|
id = "extension-1-id"
|
|
version = "extension-1-version-1"
|
|
|
|
[[order-extensions.group]]
|
|
id = "extension-2-id"
|
|
version = "extension-2-version-1"
|
|
`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("adds the order for extensions to the order-extensions label", func() {
|
|
label, err := baseImage.Label("io.buildpacks.buildpack.order-extensions")
|
|
h.AssertNil(t, err)
|
|
|
|
var orderExt dist.Order
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &orderExt))
|
|
h.AssertEq(t, len(orderExt), 1)
|
|
h.AssertEq(t, len(orderExt[0].Group), 2)
|
|
h.AssertEq(t, orderExt[0].Group[0].ID, "extension-1-id")
|
|
h.AssertEq(t, orderExt[0].Group[0].Version, "")
|
|
h.AssertEq(t, orderExt[0].Group[0].Optional, false)
|
|
h.AssertEq(t, orderExt[0].Group[1].ID, "extension-2-id")
|
|
h.AssertEq(t, orderExt[0].Group[1].Version, "extension-2-version-1")
|
|
h.AssertEq(t, orderExt[0].Group[1].Optional, false)
|
|
})
|
|
})
|
|
})
|
|
|
|
when("#SetDescription", func() {
|
|
it.Before(func() {
|
|
subject.SetDescription("Some description")
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("sets the description on the metadata", func() {
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, metadata.Description, "Some description")
|
|
})
|
|
})
|
|
|
|
when("#SetStack", func() {
|
|
it.Before(func() {
|
|
subject.SetStack(pubbldr.StackConfig{
|
|
RunImage: "some/run",
|
|
RunImageMirrors: []string{"some/mirror", "other/mirror"},
|
|
})
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("adds the stack.toml to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/stack.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/stack.toml",
|
|
h.ContentEquals(`[run-image]
|
|
image = "some/run"
|
|
mirrors = ["some/mirror", "other/mirror"]
|
|
`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("adds the stack to the metadata", func() {
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, metadata.Stack.RunImage.Image, "some/run")
|
|
h.AssertEq(t, metadata.Stack.RunImage.Mirrors[0], "some/mirror")
|
|
h.AssertEq(t, metadata.Stack.RunImage.Mirrors[1], "other/mirror")
|
|
})
|
|
})
|
|
|
|
when("#SetRunImage", func() {
|
|
it.Before(func() {
|
|
subject.SetRunImage(pubbldr.RunConfig{Images: []pubbldr.RunImageConfig{{
|
|
Image: "some/run",
|
|
Mirrors: []string{"some/mirror", "other/mirror"},
|
|
}}})
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("adds the run.toml to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/run.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/run.toml",
|
|
h.ContentEquals(`[[images]]
|
|
image = "some/run"
|
|
mirrors = ["some/mirror", "other/mirror"]
|
|
`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("adds the stack.toml to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/stack.toml")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/stack.toml",
|
|
h.ContentEquals(`[run-image]
|
|
image = "some/run"
|
|
mirrors = ["some/mirror", "other/mirror"]
|
|
`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
|
|
it("adds the run image to the metadata", func() {
|
|
label, err := baseImage.Label("io.buildpacks.builder.metadata")
|
|
h.AssertNil(t, err)
|
|
|
|
var metadata builder.Metadata
|
|
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
|
|
h.AssertEq(t, metadata.RunImages[0].Image, "some/run")
|
|
h.AssertEq(t, metadata.RunImages[0].Mirrors[0], "some/mirror")
|
|
h.AssertEq(t, metadata.RunImages[0].Mirrors[1], "other/mirror")
|
|
})
|
|
})
|
|
|
|
when("when CNB_BUILD_CONFIG_DIR is defined", func() {
|
|
var buildConfigEnvName = "CNB_BUILD_CONFIG_DIR"
|
|
var buildConfigEnvValue = "/cnb/dup-build-config-dir"
|
|
it.Before(func() {
|
|
os.Setenv(buildConfigEnvName, buildConfigEnvValue)
|
|
subject.SetBuildConfigEnv(map[string]string{
|
|
"SOME_KEY": "some-val",
|
|
"OTHER_KEY.append": "other-val",
|
|
"OTHER_KEY.delim": ":",
|
|
})
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
it.After(func() {
|
|
os.Unsetenv(buildConfigEnvName)
|
|
})
|
|
|
|
it("adds the env vars as files to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath(buildConfigEnvValue + "/env/SOME_KEY")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, buildConfigEnvValue+"/env/SOME_KEY",
|
|
h.ContentEquals(`some-val`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
h.AssertOnTarEntry(t, layerTar, buildConfigEnvValue+"/env/OTHER_KEY.append",
|
|
h.ContentEquals(`other-val`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
h.AssertOnTarEntry(t, layerTar, buildConfigEnvValue+"/env/OTHER_KEY.delim",
|
|
h.ContentEquals(`:`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
})
|
|
|
|
when("#SetBuildConfigEnv", func() {
|
|
it.Before(func() {
|
|
os.Unsetenv("CNB_BUILD_CONFIG_DIR")
|
|
subject.SetBuildConfigEnv(map[string]string{
|
|
"SOME_KEY": "some-val",
|
|
"OTHER_KEY.append": "other-val",
|
|
"OTHER_KEY.delim": ":",
|
|
})
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("adds the env vars as files to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/cnb/build-config/env/SOME_KEY")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/build-config/env/SOME_KEY",
|
|
h.ContentEquals(`some-val`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/build-config/env/OTHER_KEY.append",
|
|
h.ContentEquals(`other-val`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
h.AssertOnTarEntry(t, layerTar, "/cnb/build-config/env/OTHER_KEY.delim",
|
|
h.ContentEquals(`:`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
})
|
|
|
|
when("#SetEnv", func() {
|
|
it.Before(func() {
|
|
subject.SetEnv(map[string]string{
|
|
"SOME_KEY": "some-val",
|
|
"OTHER_KEY": "other-val",
|
|
})
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("adds the env vars as files to the image", func() {
|
|
layerTar, err := baseImage.FindLayerWithPath("/platform/env/SOME_KEY")
|
|
h.AssertNil(t, err)
|
|
h.AssertOnTarEntry(t, layerTar, "/platform/env/SOME_KEY",
|
|
h.ContentEquals(`some-val`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
h.AssertOnTarEntry(t, layerTar, "/platform/env/OTHER_KEY",
|
|
h.ContentEquals(`other-val`),
|
|
h.HasModTime(archive.NormalizedDateTime),
|
|
)
|
|
})
|
|
})
|
|
|
|
when("#DefaultRunImage", func() {
|
|
it.Before(func() {
|
|
subject.SetRunImage(pubbldr.RunConfig{Images: []pubbldr.RunImageConfig{{
|
|
Image: "some/run",
|
|
Mirrors: []string{"some/mirror", "other/mirror"},
|
|
}}})
|
|
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
|
|
h.AssertEq(t, baseImage.IsSaved(), true)
|
|
})
|
|
|
|
it("adds the run.toml to the image", func() {
|
|
actual := subject.DefaultRunImage()
|
|
h.AssertEq(t, actual.Image, "some/run")
|
|
h.AssertEq(t, actual.Mirrors, []string{"some/mirror", "other/mirror"})
|
|
})
|
|
})
|
|
})
|
|
|
|
when("builder exists", func() {
|
|
var builderImage imgutil.Image
|
|
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.id", "some.stack.id"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.mixins", `["mixinX", "mixinY", "build:mixinA"]`))
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.builder.metadata",
|
|
`{"description": "some-description", "createdBy": {"name": "some-name", "version": "1.2.3"}, "buildpacks": [{"id": "buildpack-1-id"}, {"id": "buildpack-2-id"}], "groups": [{"buildpacks": [{"id": "buildpack-1-id", "version": "buildpack-1-version", "optional": false}, {"id": "buildpack-2-id", "version": "buildpack-2-version-1", "optional": true}]}], "stack": {"runImage": {"image": "prev/run", "mirrors": ["prev/mirror"]}}, "lifecycle": {"version": "6.6.6"}}`,
|
|
))
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.buildpack.order",
|
|
`[{"group": [{"id": "buildpack-1-id", "optional": false}, {"id": "buildpack-2-id", "version": "buildpack-2-version-1", "optional": true}]}]`,
|
|
))
|
|
|
|
builderImage = baseImage
|
|
})
|
|
|
|
when("#FromImage", func() {
|
|
var bldr *builder.Builder
|
|
|
|
it.Before(func() {
|
|
var err error
|
|
bldr, err = builder.FromImage(builderImage)
|
|
h.AssertNil(t, err)
|
|
})
|
|
|
|
it("gets builder from image", func() {
|
|
h.AssertEq(t, bldr.Buildpacks()[0].ID, "buildpack-1-id")
|
|
h.AssertEq(t, bldr.Buildpacks()[1].ID, "buildpack-2-id")
|
|
|
|
order := bldr.Order()
|
|
h.AssertEq(t, len(order), 1)
|
|
h.AssertEq(t, len(order[0].Group), 2)
|
|
h.AssertEq(t, order[0].Group[0].ID, "buildpack-1-id")
|
|
h.AssertEq(t, order[0].Group[0].Version, "")
|
|
h.AssertEq(t, order[0].Group[0].Optional, false)
|
|
h.AssertEq(t, order[0].Group[1].ID, "buildpack-2-id")
|
|
h.AssertEq(t, order[0].Group[1].Version, "buildpack-2-version-1")
|
|
h.AssertEq(t, order[0].Group[1].Optional, true)
|
|
})
|
|
|
|
it("gets mixins from image", func() {
|
|
h.AssertSliceContainsOnly(t, bldr.Mixins(), "mixinX", "mixinY", "build:mixinA")
|
|
})
|
|
|
|
when("metadata is missing", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, builderImage.SetLabel(
|
|
"io.buildpacks.builder.metadata",
|
|
"",
|
|
))
|
|
})
|
|
|
|
it("should error", func() {
|
|
_, err := builder.FromImage(builderImage)
|
|
h.AssertError(t, err, "missing label 'io.buildpacks.builder.metadata'")
|
|
})
|
|
})
|
|
|
|
when("#Description", func() {
|
|
it("return description", func() {
|
|
h.AssertEq(t, bldr.Description(), "some-description")
|
|
})
|
|
})
|
|
|
|
when("#CreatedBy", func() {
|
|
it("return CreatedBy", func() {
|
|
expectedCreatorMetadata := builder.CreatorMetadata{
|
|
Name: "some-name",
|
|
Version: "1.2.3",
|
|
}
|
|
h.AssertEq(t, bldr.CreatedBy(), expectedCreatorMetadata)
|
|
})
|
|
})
|
|
|
|
when("#Name", func() {
|
|
it("return Name", func() {
|
|
h.AssertEq(t, bldr.Name(), "base/image")
|
|
})
|
|
})
|
|
|
|
when("#Image", func() {
|
|
it("return Image", func() {
|
|
h.AssertSameInstance(t, bldr.Image(), baseImage)
|
|
})
|
|
})
|
|
|
|
when("#Stack", func() {
|
|
it("return Stack", func() {
|
|
expectedStack := builder.StackMetadata{
|
|
RunImage: builder.RunImageMetadata{
|
|
Image: "prev/run",
|
|
Mirrors: []string{"prev/mirror"}}}
|
|
|
|
h.AssertEq(t, bldr.Stack(), expectedStack)
|
|
})
|
|
})
|
|
|
|
when("#UID", func() {
|
|
it("return UID", func() {
|
|
h.AssertEq(t, bldr.UID(), 1234)
|
|
})
|
|
})
|
|
|
|
when("#GID", func() {
|
|
it("return GID", func() {
|
|
h.AssertEq(t, bldr.GID(), 4321)
|
|
})
|
|
})
|
|
|
|
when("#BaseImageName", func() {
|
|
it("return name of base image", func() {
|
|
h.AssertEq(t, bldr.BaseImageName(), "base/image")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("#New", func() {
|
|
when("#WithRunImage", func() {
|
|
// Current runImage information in builder image:
|
|
// "stack": {"runImage": {"image": "prev/run", "mirrors": ["prev/mirror"]}}
|
|
var newBuilder *builder.Builder
|
|
newRunImage := "another/run"
|
|
|
|
it.Before(func() {
|
|
var err error
|
|
newBuilder, err = builder.New(builderImage, "newBuilder/image", builder.WithRunImage(newRunImage))
|
|
h.AssertNil(t, err)
|
|
})
|
|
|
|
it("overrides the run image metadata (which becomes run.toml)", func() {
|
|
// RunImages() returns Stacks + RunImages metadata.
|
|
metadata := newBuilder.RunImages()
|
|
h.AssertTrue(t, len(metadata) == 2)
|
|
for _, m := range metadata {
|
|
// Both images must be equal to the expected run-image
|
|
h.AssertEq(t, m.Image, newRunImage)
|
|
h.AssertEq(t, len(m.Mirrors), 0)
|
|
}
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
when("flatten", func() {
|
|
var (
|
|
bldr *builder.Builder
|
|
builderImage imgutil.Image
|
|
deps []buildpack.BuildModule
|
|
)
|
|
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.id", "some.stack.id"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.mixins", `["mixinX", "mixinY", "build:mixinA"]`))
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.builder.metadata",
|
|
`{"description": "some-description", "createdBy": {"name": "some-name", "version": "1.2.3"}, "buildpacks": [{"id": "buildpack-1-id"}, {"id": "buildpack-2-id"}], "groups": [{"buildpacks": [{"id": "buildpack-1-id", "version": "buildpack-1-version", "optional": false}, {"id": "buildpack-2-id", "version": "buildpack-2-version-1", "optional": true}]}], "stack": {"runImage": {"image": "prev/run", "mirrors": ["prev/mirror"]}}, "lifecycle": {"version": "6.6.6"}}`,
|
|
))
|
|
h.AssertNil(t, baseImage.SetLabel(
|
|
"io.buildpacks.buildpack.order",
|
|
`[{"group": [{"id": "buildpack-1-id", "optional": false}, {"id": "buildpack-2-id", "version": "buildpack-2-version-1", "optional": true}]}]`,
|
|
))
|
|
|
|
builderImage = baseImage
|
|
deps = []buildpack.BuildModule{bp2v1, bp1v2}
|
|
})
|
|
|
|
when("buildpacks to be flattened are NOT defined", func() {
|
|
it.Before(func() {
|
|
var err error
|
|
bldr, err = builder.New(builderImage, "some-builder")
|
|
h.AssertNil(t, err)
|
|
|
|
// Let's add the buildpacks
|
|
bldr.AddBuildpacks(bp1v1, deps)
|
|
})
|
|
|
|
when("#FlattenedModules", func() {
|
|
it("it return an empty array", func() {
|
|
h.AssertEq(t, len(bldr.FlattenedModules(buildpack.KindBuildpack)), 0)
|
|
})
|
|
})
|
|
|
|
when("#AllModules", func() {
|
|
it("it returns each buildpack individually", func() {
|
|
h.AssertEq(t, len(bldr.AllModules(buildpack.KindBuildpack)), 3)
|
|
})
|
|
})
|
|
|
|
when("#ShouldFlatten", func() {
|
|
it("it returns false for each buildpack", func() {
|
|
h.AssertFalse(t, bldr.ShouldFlatten(bp1v1))
|
|
h.AssertFalse(t, bldr.ShouldFlatten(bp2v1))
|
|
h.AssertFalse(t, bldr.ShouldFlatten(bp1v2))
|
|
})
|
|
})
|
|
})
|
|
|
|
when("buildpacks to be flattened are defined", func() {
|
|
it.Before(func() {
|
|
var err error
|
|
flattenModules, err := buildpack.ParseFlattenBuildModules([]string{"buildpack-1-id@buildpack-1-version-1,buildpack-1-id@buildpack-1-version-2,buildpack-2-id@buildpack-2-version-1"})
|
|
h.AssertNil(t, err)
|
|
|
|
bldr, err = builder.New(builderImage, "some-builder", builder.WithFlattened(flattenModules))
|
|
h.AssertNil(t, err)
|
|
|
|
// Let's add the buildpacks
|
|
bldr.AddBuildpacks(bp1v1, deps)
|
|
})
|
|
|
|
when("#FlattenedModules", func() {
|
|
it("it return one array with all buildpacks on it", func() {
|
|
h.AssertEq(t, len(bldr.FlattenedModules(buildpack.KindBuildpack)), 1)
|
|
h.AssertEq(t, len(bldr.FlattenedModules(buildpack.KindBuildpack)[0]), 3)
|
|
})
|
|
})
|
|
|
|
when("#AllModules", func() {
|
|
it("it returns each buildpack individually", func() {
|
|
h.AssertEq(t, len(bldr.AllModules(buildpack.KindBuildpack)), 3)
|
|
})
|
|
})
|
|
|
|
when("#ShouldFlatten", func() {
|
|
it("it returns true for each buildpack", func() {
|
|
h.AssertTrue(t, bldr.ShouldFlatten(bp1v1))
|
|
h.AssertTrue(t, bldr.ShouldFlatten(bp2v1))
|
|
h.AssertTrue(t, bldr.ShouldFlatten(bp1v2))
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
when("labels", func() {
|
|
var (
|
|
customLabels, imageLabels map[string]string
|
|
err error
|
|
)
|
|
it.Before(func() {
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_USER_ID", "1234"))
|
|
h.AssertNil(t, baseImage.SetEnv("CNB_GROUP_ID", "4321"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.id", "some.stack.id"))
|
|
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.stack.mixins", `["mixinX", "mixinY", "build:mixinA"]`))
|
|
})
|
|
|
|
it.After(func() {
|
|
h.AssertNilE(t, baseImage.Cleanup())
|
|
})
|
|
|
|
it("should set labels to the image", func() {
|
|
customLabels = map[string]string{"test.label.one": "1", "test.label.two": "2"}
|
|
subject, err = builder.New(baseImage, "some/builder", builder.WithLabels(customLabels))
|
|
h.AssertNil(t, err)
|
|
|
|
imageLabels, err = baseImage.Labels()
|
|
h.AssertNil(t, err)
|
|
h.AssertEq(t, imageLabels["test.label.one"], "1")
|
|
h.AssertEq(t, imageLabels["test.label.two"], "2")
|
|
})
|
|
})
|
|
}
|
|
|
|
func assertImageHasBPLayer(t *testing.T, image *fakes.Image, bp buildpack.BuildModule) {
|
|
t.Helper()
|
|
|
|
dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", bp.Descriptor().Info().ID, bp.Descriptor().Info().Version)
|
|
layerTar, err := image.FindLayerWithPath(dirPath)
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, dirPath,
|
|
h.IsDirectory(),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, path.Dir(dirPath),
|
|
h.IsDirectory(),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/build",
|
|
h.ContentEquals("build-contents"),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect",
|
|
h.ContentEquals("detect-contents"),
|
|
)
|
|
}
|
|
|
|
func assertImageHasExtLayer(t *testing.T, image *fakes.Image, ext buildpack.BuildModule) {
|
|
t.Helper()
|
|
|
|
dirPath := fmt.Sprintf("/cnb/extensions/%s/%s", ext.Descriptor().Info().ID, ext.Descriptor().Info().Version)
|
|
layerTar, err := image.FindLayerWithPath(dirPath)
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, dirPath,
|
|
h.IsDirectory(),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, path.Dir(dirPath),
|
|
h.IsDirectory(),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/generate",
|
|
h.ContentEquals("generate-contents"),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect",
|
|
h.ContentEquals("detect-contents"),
|
|
)
|
|
}
|
|
|
|
func assertImageHasOrderBpLayer(t *testing.T, image *fakes.Image, bp buildpack.BuildModule) {
|
|
t.Helper()
|
|
|
|
dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", bp.Descriptor().Info().ID, bp.Descriptor().Info().Version)
|
|
layerTar, err := image.FindLayerWithPath(dirPath)
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, dirPath,
|
|
h.IsDirectory(),
|
|
)
|
|
|
|
h.AssertOnTarEntry(t, layerTar, path.Dir(dirPath),
|
|
h.IsDirectory(),
|
|
)
|
|
}
|