Skip to content

Commit

Permalink
Add unit test for FindContexts
Browse files Browse the repository at this point in the history
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Co-authored-by: Pavel Busko <pavel.busko@sap.com>
  • Loading branch information
pbusko and c0d1ngm0nk3y committed Feb 12, 2024
1 parent ea910f1 commit 8c49831
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 150 deletions.
6 changes: 3 additions & 3 deletions buildpack/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type GenerateInputs struct {

type GenerateOutputs struct {
Dockerfiles []DockerfileInfo
Contexts []ContextInfo
Contexts []extend.ContextInfo
MetRequires []string
}

Expand Down Expand Up @@ -115,7 +115,7 @@ func readOutputFilesExt(d ExtDescriptor, extOutputDir string, extPlanIn Plan, lo
var err error
var dfInfo DockerfileInfo
var found bool
var contexts []ContextInfo
var contexts []extend.ContextInfo

// set MetRequires
gr.MetRequires = names(extPlanIn.Entries)
Expand All @@ -139,7 +139,7 @@ func readOutputFilesExt(d ExtDescriptor, extOutputDir string, extPlanIn Plan, lo
logger.Debugf("Found '%d' Dockerfiles for processing", len(gr.Dockerfiles))
}

if contexts, err = findContexts(d, extOutputDir, logger); err != nil {
if contexts, err = extend.FindContexts(d.Extension.ID, extOutputDir, logger); err != nil {
return GenerateOutputs{}, err
}

Expand Down
14 changes: 8 additions & 6 deletions buildpack/buildcontext.go → internal/extend/buildcontext.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Package buildpack provides the core infrastructure
package buildpack
// Package extend contains extensions specific helpers
package extend

import (
"fmt"
Expand All @@ -21,19 +21,20 @@ const (
// ContextInfo captures info about the context used for build- and run-image extensions
type ContextInfo struct {
ExtensionID string
Kind string
Path string
}

func findContexts(d ExtDescriptor, extOutputDir string, logger log.Logger) ([]ContextInfo, error) {
// FindContexts returns paths to Build Context folders produced by an extension. If Shared Context is provided with Run or Build Contexts the error will be thrown.
func FindContexts(extensionID string, extOutputDir string, logger log.Logger) ([]ContextInfo, error) {
var contexts []ContextInfo
var sharedIsProvided bool

sharedContextDir := filepath.Join(extOutputDir, SharedContextDir)
if s, err := os.Stat(sharedContextDir); err == nil && s.IsDir() {
logger.Debugf("found shared extension context %q", sharedContextDir)
sharedIsProvided = true
contexts = append(contexts, ContextInfo{
ExtensionID: d.Extension.ID,
ExtensionID: extensionID,
Path: sharedContextDir,
})
} else if err != nil && !os.IsNotExist(err) {
Expand All @@ -48,8 +49,9 @@ func findContexts(d ExtDescriptor, extOutputDir string, logger log.Logger) ([]Co
return nil, fmt.Errorf("image-specific context dir is provided together with a shared context")
}

logger.Debugf("found extension context %q", contextDir)
contexts = append(contexts, ContextInfo{
ExtensionID: d.Extension.ID,
ExtensionID: extensionID,
Path: contextDir,
})
} else if err != nil && !os.IsNotExist(err) {
Expand Down
96 changes: 96 additions & 0 deletions internal/extend/buildcontext_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package extend_test

import (
"io"
"os"
"path/filepath"
"testing"

"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/lifecycle/internal/extend"
"github.com/buildpacks/lifecycle/log"
h "github.com/buildpacks/lifecycle/testhelpers"
)

func TestContext(t *testing.T) {
spec.Run(t, "unit-context", testContext, spec.Report(report.Terminal{}))
}

func testContext(t *testing.T, when spec.G, it spec.S) {
var tmpDir string
var logger log.Logger

it.Before(func() {
var err error
tmpDir, err = os.MkdirTemp("", "contexts")
logger = log.NewDefaultLogger(io.Discard)

h.AssertNil(t, err)
})

it.After(func() {
_ = os.RemoveAll(tmpDir)
})

when("#FindContexts", func() {
when("only shared context is provided", func() {
it.Before(func() {
h.Mkdir(t, filepath.Join(tmpDir, extend.SharedContextDir))
})

it("succeeds", func() {
contexts, err := extend.FindContexts("A", tmpDir, logger)
h.AssertNil(t, err)

h.AssertEq(t, len(contexts), 1)
h.AssertEq(t, contexts[0], extend.ContextInfo{
ExtensionID: "A",
Path: filepath.Join(tmpDir, extend.SharedContextDir),
})
})
})

when("image specific contexts are provided", func() {
it.Before(func() {
h.Mkdir(t, filepath.Join(tmpDir, extend.RunContextDir), filepath.Join(tmpDir, extend.BuildContextDir))
})

it("succeeds", func() {
contexts, err := extend.FindContexts("A", tmpDir, logger)
h.AssertNil(t, err)

h.AssertEq(t, len(contexts), 2)
h.AssertEq(t, contexts[0], extend.ContextInfo{
ExtensionID: "A",
Path: filepath.Join(tmpDir, extend.BuildContextDir),
})
h.AssertEq(t, contexts[1], extend.ContextInfo{
ExtensionID: "A",
Path: filepath.Join(tmpDir, extend.RunContextDir),
})
})
})

when("no context is provided", func() {
it("succeeds", func() {
contexts, err := extend.FindContexts("A", tmpDir, logger)
h.AssertNil(t, err)

h.AssertEq(t, len(contexts), 0)
})
})

when("shared and image-specific contexts are provided", func() {
it.Before(func() {
h.Mkdir(t, filepath.Join(tmpDir, extend.SharedContextDir), filepath.Join(tmpDir, extend.BuildContextDir))
})

it("fails", func() {
_, err := extend.FindContexts("A", tmpDir, logger)
h.AssertNotNil(t, err)
})
})
})
}
4 changes: 2 additions & 2 deletions internal/extend/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (
h "github.com/buildpacks/lifecycle/testhelpers"
)

func TestGenerate(t *testing.T) {
spec.Run(t, "unit-extend", testConfig, spec.Report(report.Terminal{}))
func TestConfig(t *testing.T) {
spec.Run(t, "unit-config", testConfig, spec.Report(report.Terminal{}))
}

func testConfig(t *testing.T, when spec.G, it spec.S) {
Expand Down
4 changes: 2 additions & 2 deletions phase/extender.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,8 @@ func (e *Extender) dockerfileFor(kind, extID string) (*extend.Dockerfile, error)
}

func (e *Extender) contextDirFor(kind, extID string) (string, error) {
sharedContextDir := filepath.Join(e.GeneratedDir, launch.EscapeID(extID), buildpack.SharedContextDir)
kindContextDir := filepath.Join(e.GeneratedDir, launch.EscapeID(extID), fmt.Sprintf("%s.%s", buildpack.SharedContextDir, kind))
sharedContextDir := filepath.Join(e.GeneratedDir, launch.EscapeID(extID), extend.SharedContextDir)
kindContextDir := filepath.Join(e.GeneratedDir, launch.EscapeID(extID), fmt.Sprintf("%s.%s", extend.SharedContextDir, kind))

for _, dir := range []string{kindContextDir, sharedContextDir} {
if s, err := os.Stat(dir); err == nil && s.IsDir() {
Expand Down
24 changes: 12 additions & 12 deletions phase/extender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,9 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
mockCtrl.Finish()
})

when("using latest platform API", func() {
when("using the platform API 0.12", func() {
it.Before(func() {
extender.PlatformAPI = api.Platform.Latest()
extender.PlatformAPI = api.MustParse("0.12")
})

when("build base image", func() {
Expand Down Expand Up @@ -244,7 +244,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileA.Path)
h.AssertEq(t, len(dockerfile.Args), 4)
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -277,7 +277,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileB.Path)
h.AssertEq(t, len(dockerfile.Args), 4)
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -383,7 +383,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileA.Path)
h.AssertEq(t, len(dockerfile.Args), 4) // build_id, user_id, group_id
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -415,7 +415,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileB.Path)
h.AssertEq(t, len(dockerfile.Args), 4) // build_id, user_id, group_id
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -483,7 +483,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
gomock.Any(),
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileA.Path)
h.AssertEq(t, len(dockerfile.Args), 4)
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -555,7 +555,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileA.Path)
h.AssertEq(t, len(dockerfile.Args), 4)
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -588,7 +588,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileB.Path)
h.AssertEq(t, len(dockerfile.Args), 4)
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -694,7 +694,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileA.Path)
h.AssertEq(t, len(dockerfile.Args), 4) // build_id, user_id, group_id
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -726,7 +726,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
},
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileB.Path)
h.AssertEq(t, len(dockerfile.Args), 4) // build_id, user_id, group_id
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down Expand Up @@ -794,7 +794,7 @@ func testExtender(t *testing.T, when spec.G, it spec.S) {
gomock.Any(),
logger,
).DoAndReturn(
func(dockerfile extend.Dockerfile, toBaseImage v1.Image, withBuildOptions extend.Options, logger llog.Logger) (v1.Image, error) {
func(dockerfile extend.Dockerfile, _ v1.Image, _ extend.Options, _ llog.Logger) (v1.Image, error) {
h.AssertEq(t, dockerfile.Path, expectedDockerfileA.Path)
h.AssertEq(t, len(dockerfile.Args), 4)
h.AssertEq(t, dockerfile.Args[0].Name, "build_id")
Expand Down
37 changes: 12 additions & 25 deletions phase/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ func (g *Generator) Generate() (GenerateResult, error) {
}

var dockerfiles []buildpack.DockerfileInfo
var contexts []buildpack.ContextInfo
filteredPlan := g.Plan
for _, ext := range g.Extensions {
g.Logger.Debugf("Running generate for extension %s", ext)
Expand All @@ -112,7 +111,6 @@ func (g *Generator) Generate() (GenerateResult, error) {

// aggregate build results
dockerfiles = append(dockerfiles, result.Dockerfiles...)
contexts = append(contexts, result.Contexts...)
filteredPlan = filteredPlan.Filter(result.MetRequires)

g.Logger.Debugf("Finished running generate for extension %s", ext)
Expand Down Expand Up @@ -144,11 +142,6 @@ func (g *Generator) Generate() (GenerateResult, error) {
return GenerateResult{}, err
}

g.Logger.Debug("Copying Context directories")
if err := g.copyContexts(contexts); err != nil {
return GenerateResult{}, err
}

return GenerateResult{
AnalyzedMD: finalAnalyzedMD,
Plan: filteredPlan,
Expand All @@ -171,14 +164,21 @@ func (g *Generator) copyDockerfiles(dockerfiles []buildpack.DockerfileInfo) erro
targetDir := filepath.Join(g.GeneratedDir, dockerfile.Kind, launch.EscapeID(dockerfile.ExtensionID))
targetPath := filepath.Join(targetDir, "Dockerfile")

if g.PlatformAPI.AtLeast("0.13") {
targetDir = filepath.Join(g.GeneratedDir, launch.EscapeID(dockerfile.ExtensionID))
targetPath = filepath.Join(targetDir, filepath.Base(dockerfile.Path))
ignoreDockerfile := dockerfile.Kind == buildpack.DockerfileKindRun && dockerfile.Ignore
if ignoreDockerfile {
targetPath += ".ignore"
}

if dockerfile.Kind == buildpack.DockerfileKindRun && dockerfile.Ignore {
targetPath += ".ignore"
if g.PlatformAPI.AtLeast("0.13") {
if ignoreDockerfile {
if err := fsutil.RenameWithWindowsFallback(dockerfile.Path, dockerfile.Path+".ignore"); err != nil {
return fmt.Errorf("failed to rename Dockerfile at %s: %w", dockerfile.Path, err)
}
}

continue
}

if err := os.MkdirAll(targetDir, os.ModePerm); err != nil {
return err
}
Expand All @@ -197,19 +197,6 @@ func (g *Generator) copyDockerfiles(dockerfiles []buildpack.DockerfileInfo) erro
return nil
}

func (g *Generator) copyContexts(contexts []buildpack.ContextInfo) error {
for _, contextDir := range contexts {
targetPath := filepath.Join(g.GeneratedDir, launch.EscapeID(contextDir.ExtensionID), filepath.Base(contextDir.Path))

g.Logger.Debugf("Copying %s to %s", contextDir.Path, targetPath)
if err := fsutil.Copy(contextDir.Path, targetPath); err != nil {
return err
}
}

return nil
}

func (g *Generator) runImageFrom(dockerfiles []buildpack.DockerfileInfo) (newBase string, extend bool) {
var ignoreNext bool
for i := len(dockerfiles) - 1; i >= 0; i-- {
Expand Down
Loading

0 comments on commit 8c49831

Please sign in to comment.