Skip to content

Commit

Permalink
Add support for buildpack api 0.8 (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
sambhav authored Apr 11, 2022
1 parent 2f1a458 commit 52e0183
Show file tree
Hide file tree
Showing 8 changed files with 1,044 additions and 319 deletions.
41 changes: 30 additions & 11 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,6 @@ func Build(builder Builder, options ...Option) {
config = option(config)
}

if len(config.arguments) != 4 {
config.exitHandler.Error(fmt.Errorf("expected 3 arguments and received %d", len(config.arguments)-1))
return
}

var (
err error
file string
Expand Down Expand Up @@ -191,11 +186,36 @@ func Build(builder Builder, options ...Option) {
config.exitHandler.Error(fmt.Errorf("this version of libcnb is only compatible with buildpack APIs >= %s, <= %s", MinSupportedBPVersion, MaxSupportedBPVersion))
return
}
var buildpackPlanPath string

ctx.Layers = Layers{config.arguments[1]}
logger.Debugf("Layers: %+v", ctx.Layers)
if API.LessThan(semver.MustParse("0.8")) {
if len(config.arguments) != 4 {
config.exitHandler.Error(fmt.Errorf("expected 3 arguments and received %d", len(config.arguments)-1))
return
}
ctx.Layers = Layers{config.arguments[1]}
ctx.Platform.Path = config.arguments[2]
buildpackPlanPath = config.arguments[3]
} else {
layersDir, ok := os.LookupEnv("CNB_LAYERS_DIR")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_LAYERS_DIR to be set"))
return
}
ctx.Layers = Layers{layersDir}
ctx.Platform.Path, ok = os.LookupEnv("CNB_PLATFORM_DIR")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_PLATFORM_DIR to be set"))
return
}
buildpackPlanPath, ok = os.LookupEnv("CNB_BP_PLAN_PATH")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_BP_PLAN_PATH to be set"))
return
}
}

ctx.Platform.Path = config.arguments[2]
logger.Debugf("Layers: %+v", ctx.Layers)
if logger.IsDebugEnabled() {
logger.Debug(PlatformFormatter(ctx.Platform))
}
Expand All @@ -222,9 +242,8 @@ func Build(builder Builder, options ...Option) {
ctx.PersistentMetadata = store.Metadata
logger.Debugf("Persistent Metadata: %+v", ctx.PersistentMetadata)

file = config.arguments[3]
if _, err = toml.DecodeFile(file, &ctx.Plan); err != nil && !os.IsNotExist(err) {
config.exitHandler.Error(fmt.Errorf("unable to decode buildpack plan %s\n%w", file, err))
if _, err = toml.DecodeFile(buildpackPlanPath, &ctx.Plan); err != nil && !os.IsNotExist(err) {
config.exitHandler.Error(fmt.Errorf("unable to decode buildpack plan %s\n%w", buildpackPlanPath, err))
return
}
logger.Debugf("Buildpack Plan: %+v", ctx.Plan)
Expand Down
217 changes: 164 additions & 53 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ test-key = "test-value"
tomlWriter.On("Write", mock.Anything, mock.Anything).Return(nil)

Expect(os.Setenv("CNB_STACK_ID", "test-stack-id")).To(Succeed())
Expect(os.Setenv("CNB_LAYERS_DIR", layersPath)).To(Succeed())
Expect(os.Setenv("CNB_PLATFORM_DIR", platformPath)).To(Succeed())
Expect(os.Setenv("CNB_BP_PLAN_PATH", buildpackPlanPath)).To(Succeed())

workingDir, err = os.Getwd()
Expect(err).NotTo(HaveOccurred())
Expand All @@ -173,6 +176,9 @@ test-key = "test-value"
Expect(os.Chdir(workingDir)).To(Succeed())
Expect(os.Unsetenv("CNB_BUILDPACK_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_STACK_ID")).To(Succeed())
Expect(os.Unsetenv("CNB_PLATFORM_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_BP_PLAN_PATH")).To(Succeed())
Expect(os.Unsetenv("CNB_LAYERS_DIR")).To(Succeed())

Expect(os.RemoveAll(applicationPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPath)).To(Succeed())
Expand All @@ -181,7 +187,7 @@ test-key = "test-value"
Expect(os.RemoveAll(platformPath)).To(Succeed())
})

context("buildpack API is not 0.5, 0.6, or 0.7", func() {
context("buildpack API is not within the supported range", func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
Expand All @@ -204,11 +210,45 @@ version = "1.1.1"
)

Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(
"this version of libcnb is only compatible with buildpack APIs >= 0.5, <= 0.8",
fmt.Sprintf("this version of libcnb is only compatible with buildpack APIs >= %s, <= %s", libcnb.MinSupportedBPVersion, libcnb.MaxSupportedBPVersion),
))
})
})

context("errors if required env vars are not set for buildpack API >=0.8", func() {
for _, e := range []string{"CNB_LAYERS_DIR", "CNB_PLATFORM_DIR", "CNB_BP_PLAN_PATH"} {
// We need to do this assignment because of the way that spec binds variables
envVar := e
context(fmt.Sprintf("when %s is unset", envVar), func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.8"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
`),
0600),
).To(Succeed())
os.Unsetenv(envVar)
})

it("fails", func() {
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(
fmt.Sprintf("expected %s to be set", envVar),
))
})
})
}
})

it("encounters the wrong number of arguments", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)

Expand All @@ -234,65 +274,136 @@ version = "1.1.1"
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError("CNB_STACK_ID not set"))
})

it("creates context", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
context("when BP API >= 0.8", func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.8"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
`),
0600),
).To(Succeed())
})

libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
)
it("creates context", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)

ctx := builder.Calls[0].Arguments[0].(libcnb.BuildContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.6",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
ClearEnvironment: true,
Description: "A test buildpack",
Keywords: []string{"test", "buildpack"},
Licenses: []libcnb.License{
{Type: "Apache-2.0", URI: "https://spdx.org/licenses/Apache-2.0.html"},
{Type: "Apache-1.1", URI: "https://spdx.org/licenses/Apache-1.1.html"},
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath}),
)

ctx := builder.Calls[0].Arguments[0].(libcnb.BuildContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.8",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
},
},
Path: buildpackPath,
Stacks: []libcnb.BuildpackStack{
{
ID: "test-id",
Mixins: []string{"test-name"},
Path: buildpackPath,
}))
Expect(ctx.Layers).To(Equal(libcnb.Layers{Path: layersPath}))
Expect(ctx.PersistentMetadata).To(Equal(map[string]interface{}{"test-key": "test-value"}))
Expect(ctx.Plan).To(Equal(libcnb.BuildpackPlan{
Entries: []libcnb.BuildpackPlanEntry{
{
Name: "test-name",
Metadata: map[string]interface{}{
"test-key": "test-value",
},
},
},
},
Metadata: map[string]interface{}{"test-key": "test-value"},
}))
Expect(ctx.Layers).To(Equal(libcnb.Layers{Path: layersPath}))
Expect(ctx.PersistentMetadata).To(Equal(map[string]interface{}{"test-key": "test-value"}))
Expect(ctx.Plan).To(Equal(libcnb.BuildpackPlan{
Entries: []libcnb.BuildpackPlanEntry{
{
Name: "test-name",
Metadata: map[string]interface{}{
"test-key": "test-value",
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
},
},
},
},
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
})
})

context("when BP API < 0.8", func() {
it.Before(func() {
Expect(os.Unsetenv("CNB_PLATFORM_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_BP_PLAN_PATH")).To(Succeed())
Expect(os.Unsetenv("CNB_LAYERS_DIR")).To(Succeed())
})

it("creates context", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)

libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
)

ctx := builder.Calls[0].Arguments[0].(libcnb.BuildContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.6",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
ClearEnvironment: true,
Description: "A test buildpack",
Keywords: []string{"test", "buildpack"},
Licenses: []libcnb.License{
{Type: "Apache-2.0", URI: "https://spdx.org/licenses/Apache-2.0.html"},
{Type: "Apache-1.1", URI: "https://spdx.org/licenses/Apache-1.1.html"},
},
},
},
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
Path: buildpackPath,
Stacks: []libcnb.BuildpackStack{
{
ID: "test-id",
Mixins: []string{"test-name"},
},
},
Metadata: map[string]interface{}{"test-key": "test-value"},
}))
Expect(ctx.Layers).To(Equal(libcnb.Layers{Path: layersPath}))
Expect(ctx.PersistentMetadata).To(Equal(map[string]interface{}{"test-key": "test-value"}))
Expect(ctx.Plan).To(Equal(libcnb.BuildpackPlan{
Entries: []libcnb.BuildpackPlanEntry{
{
Name: "test-name",
Metadata: map[string]interface{}{
"test-key": "test-value",
},
},
},
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
},
},
},
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
})
})

it("extracts buildpack path from command path if CNB_BUILDPACK_PATH is not set", func() {
Expand Down
Loading

0 comments on commit 52e0183

Please sign in to comment.