Skip to content

Commit

Permalink
Merge pull request #256 from BarDweller/release-2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
dmikusa committed Jun 27, 2023
2 parents f244221 + 0d0509a commit 1997908
Show file tree
Hide file tree
Showing 24 changed files with 926 additions and 603 deletions.
55 changes: 13 additions & 42 deletions bard/logger.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2020 the original author or authors.
* Copyright 2018-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,9 @@ package bard
import (
"fmt"
"io"
"os"
"strings"

"github.com/buildpacks/libcnb"
"github.com/buildpacks/libcnb/poet"
"github.com/buildpacks/libcnb/log"
"github.com/heroku/color"
)

Expand All @@ -34,7 +32,7 @@ func init() {

// Logger logs message to a writer.
type Logger struct {
poet.Logger
log.Logger

body io.Writer
header io.Writer
Expand All @@ -43,21 +41,18 @@ type Logger struct {
title io.Writer
}

// NewLogger creates a new instance of Logger. It configures debug logging if $BP_DEBUG is set.
func NewLogger(writer io.Writer) Logger {
var options []Option
return NewLoggerWithOptions(writer, options...)
}

// Option is a function for configuring a Logger instance.
type Option func(logger Logger) Logger

// WithDebug configures the debug Writer.
func WithDebug(writer io.Writer) Option {
return func(logger Logger) Logger {
logger.Logger = poet.WithDebug(writer)(logger.Logger)
return logger
}
}

// NewLoggerWithOptions create a new instance of Logger. It configures the Logger with options.
func NewLoggerWithOptions(writer io.Writer, options ...Option) Logger {
l := Logger{
Logger: poet.NewLogger(writer),
Logger: log.New(writer),
body: NewWriter(writer, WithAttributes(color.Faint), WithIndent(2)),
header: NewWriter(writer, WithIndent(1)),
terminalBody: NewWriter(writer, WithAttributes(color.FgRed, color.Bold), WithIndent(1)),
Expand All @@ -72,29 +67,6 @@ func NewLoggerWithOptions(writer io.Writer, options ...Option) Logger {
return l
}

// NewLogger creates a new instance of Logger. It configures debug logging if $BP_DEBUG is set.
func NewLogger(writer io.Writer) Logger {
var options []Option

// check for presence and value of log level environment variable
options = LogLevel(options, writer)

return NewLoggerWithOptions(writer, options...)
}

func LogLevel(options []Option, writer io.Writer) []Option {

// Check for older log level env variable
_, dbSet := os.LookupEnv("BP_DEBUG")

// Then check for common buildpack log level env variable - if either are set to DEBUG/true, enable Debug Writer
if level, ok := os.LookupEnv("BP_LOG_LEVEL"); (ok && strings.ToLower(level) == "debug") || dbSet {

options = append(options, WithDebug(writer))
}
return options
}

// Body formats using the default formats for its operands and logs a message to the configured body writer. Spaces
// are added between operands when neither is a string.
func (l Logger) Body(a ...interface{}) {
Expand Down Expand Up @@ -190,14 +162,13 @@ func (l Logger) IsTerminalErrorEnabled() bool {
return l.terminalHeader != nil && l.terminalBody != nil
}

// Title logs a message to the configured title writer.
func (l Logger) Title(buildpack libcnb.Buildpack) {
func (l Logger) Title(name string, version string, homepage string) {
if !l.IsTitleEnabled() {
return
}

l.printf(l.title, "\n%s", FormatIdentity(buildpack.Info.Name, buildpack.Info.Version))
l.Header(color.New(color.FgBlue, color.Faint, color.Italic).Sprint(buildpack.Info.Homepage))
l.printf(l.title, "\n%s", FormatIdentity(name, version))
l.Header(color.New(color.FgBlue, color.Faint, color.Italic).Sprint(homepage))
}

// TitleWriter returns the configured title writer.
Expand Down
63 changes: 11 additions & 52 deletions bard/logger_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2020 the original author or authors.
* Copyright 2018-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,7 +22,6 @@ import (
"os"
"testing"

"github.com/buildpacks/libcnb"
. "github.com/onsi/gomega"
"github.com/sclevine/spec"

Expand Down Expand Up @@ -53,7 +52,9 @@ func testLogger(t *testing.T, context spec.G, it spec.S) {

context("with BP_DEBUG", func() {
it.Before(func() {
Expect(os.Setenv("BP_DEBUG", "")).To(Succeed())
//libcnb defines BP_DEBUG as enabled if it has _any_ value
//this does not include empty string as previously tested here.
Expect(os.Setenv("BP_DEBUG", "true")).To(Succeed())
l = bard.NewLogger(b)
})

Expand Down Expand Up @@ -83,6 +84,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) {

context("with debug disabled", func() {
it.Before(func() {
Expect(os.Unsetenv("BP_LOG_LEVEL")).To(Succeed())
l = bard.NewLoggerWithOptions(b)
})

Expand All @@ -103,29 +105,15 @@ func testLogger(t *testing.T, context spec.G, it spec.S) {
it("indicates that debug is not enabled", func() {
Expect(l.IsDebugEnabled()).To(BeFalse())
})

it("writes info log", func() {
l.Info("test-message")
Expect(b.String()).To(Equal("test-message\n"))
})

it("writes info formatted log", func() {
l.Infof("test-%s", "message")
Expect(b.String()).To(Equal("test-message\n"))
})

it("returns info writer", func() {
Expect(l.InfoWriter()).NotTo(BeNil())
})

it("indicates that info is enabled", func() {
Expect(l.IsInfoEnabled()).To(BeTrue())
})
})

context("with debug enabled", func() {
it.Before(func() {
l = bard.NewLoggerWithOptions(b, bard.WithDebug(b))
Expect(os.Setenv("BP_LOG_LEVEL", "debug")).To(Succeed())
l = bard.NewLogger(b)
})
it.After(func() {
Expect(os.Unsetenv("BP_LOG_LEVEL")).To(Succeed())
})

it("writes body log", func() {
Expand Down Expand Up @@ -178,28 +166,6 @@ func testLogger(t *testing.T, context spec.G, it spec.S) {
Expect(l.HeaderWriter()).NotTo(BeNil())
})

it("indicates header body is enabled", func() {
Expect(l.IsHeaderEnabled()).To(BeTrue())
})

it("writes info log", func() {
l.Info("test-message")
Expect(b.String()).To(Equal("test-message\n"))
})

it("writes info formatted log", func() {
l.Infof("test-%s", "message")
Expect(b.String()).To(Equal("test-message\n"))
})

it("returns info writer", func() {
Expect(l.InfoWriter()).NotTo(BeNil())
})

it("indicates that info is enabled", func() {
Expect(l.IsInfoEnabled()).To(BeTrue())
})

it("writes terminal error", func() {
l.TerminalError(bard.IdentifiableError{Name: "test-name", Description: "test-description", Err: fmt.Errorf("test-error")})
Expect(b.String()).To(Equal("\x1b[31m\x1b[0m\n\x1b[31m\x1b[1mtest-name\x1b[0m\x1b[31m test-description\x1b[0m\n\x1b[31;1m test-error\x1b[0m\n"))
Expand All @@ -214,14 +180,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) {
})

it("writes title log", func() {
l.Title(libcnb.Buildpack{
Info: libcnb.BuildpackInfo{
Name: "test-name",
Version: "test-version",
Homepage: "test-homepage",
},
})

l.Title("test-name", "test-version", "test-homepage")
Expect(b.String()).To(Equal("\x1b[34m\x1b[0m\n\x1b[34m\x1b[1mtest-name\x1b[0m\x1b[34m test-version\x1b[0m\n \x1b[34;2;3mtest-homepage\x1b[0m\n"))
})

Expand Down
15 changes: 7 additions & 8 deletions build.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2020 the original author or authors.
* Copyright 2018-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,22 +24,21 @@ import (
)

// Build is called by the main function of a buildpack, for build.
func Build(builder libcnb.Builder, options ...libcnb.Option) {
libcnb.Build(buildDelegate{delegate: builder},
append([]libcnb.Option{
func Build(builder libcnb.BuildFunc, options ...libcnb.Option) {
libcnb.Build(buildDelegate{delegate: builder}.Build,
libcnb.NewConfig(append([]libcnb.Option{
libcnb.WithEnvironmentWriter(internal.NewEnvironmentWriter()),
libcnb.WithExitHandler(internal.NewExitHandler()),
libcnb.WithTOMLWriter(internal.NewTOMLWriter()),
}, options...)...,
)
}, options...)...))
}

type buildDelegate struct {
delegate libcnb.Builder
delegate libcnb.BuildFunc
}

func (b buildDelegate) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
result, err := b.delegate.Build(context)
result, err := b.delegate(context)
if err != nil {
err = bard.IdentifiableError{
Name: context.Buildpack.Info.Name,
Expand Down
28 changes: 21 additions & 7 deletions build_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2020 the original author or authors.
* Copyright 2018-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,7 +37,6 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect = NewWithT(t).Expect

applicationPath string
builder *mocks.Builder
buildpackPath string
buildpackPlanPath string
commandPath string
Expand All @@ -58,8 +57,6 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
applicationPath, err = filepath.EvalSymlinks(applicationPath)
Expect(err).NotTo(HaveOccurred())

builder = &mocks.Builder{}

buildpackPath = t.TempDir()
Expect(err).NotTo(HaveOccurred())

Expand All @@ -68,6 +65,8 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(f.Close()).NotTo(HaveOccurred())
buildpackPlanPath = f.Name()

Expect(os.Setenv("CNB_BP_PLAN_PATH", buildpackPlanPath)).To(Succeed())

commandPath = filepath.Join(buildpackPath, "bin", "build")

environmentWriter = &mocks.EnvironmentWriter{}
Expand All @@ -79,14 +78,23 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
layersPath = t.TempDir()
Expect(err).NotTo(HaveOccurred())

Expect(os.Setenv("CNB_LAYERS_DIR", layersPath)).To(Succeed())

platformPath = t.TempDir()
Expect(err).NotTo(HaveOccurred())

Expect(os.Setenv("CNB_PLATFORM_DIR", platformPath)).To(Succeed())

tomlWriter = &mocks.TOMLWriter{}
tomlWriter.On("Write", mock.Anything, mock.Anything).Return(nil)

Expect(os.Setenv("CNB_STACK_ID", "test-stack-id")).To(Succeed())

buildpackPath = t.TempDir()
Expect(err).NotTo(HaveOccurred())

Expect(os.Setenv("CNB_BUILDPACK_DIR", buildpackPath)).To(Succeed())

workingDir, err = os.Getwd()
Expect(err).NotTo(HaveOccurred())
Expect(os.Chdir(applicationPath)).To(Succeed())
Expand All @@ -95,25 +103,31 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
it.After(func() {
Expect(os.Chdir(workingDir)).To(Succeed())
Expect(os.Unsetenv("CNB_STACK_ID")).To(Succeed())
Expect(os.Unsetenv("CNB_BUILDPACK_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_LAYERS_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_PLATFORM_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_BP_PLAN_PATH")).To(Succeed())

Expect(os.RemoveAll(applicationPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPlanPath)).To(Succeed())
Expect(os.RemoveAll(layersPath)).To(Succeed())
Expect(os.RemoveAll(platformPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPath)).To(Succeed())
})

it("handles error from Builder", func() {
Expect(os.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"), []byte(`
api = "0.6"
api = "0.8"
[buildpack]
name = "test-name"
version = "test-version"`),
0644)).To(Succeed())
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), fmt.Errorf("test-error"))

libpak.Build(builder,
libpak.Build(func(ctx libcnb.BuildContext) (libcnb.BuildResult, error) {
return libcnb.BuildResult{}, fmt.Errorf("test-error")
},
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expand Down
19 changes: 1 addition & 18 deletions buildpack.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2020 the original author or authors.
* Copyright 2018-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -112,23 +112,6 @@ func (b1 BuildpackDependency) Equals(b2 BuildpackDependency) bool {
return reflect.DeepEqual(b1, b2)
}

// AsBOMEntry renders a bill of materials entry describing the dependency.
//
// Deprecated: as of Buildpacks RFC 95, use `BuildpackDependency.AsSyftArtifact` instead
func (b BuildpackDependency) AsBOMEntry() libcnb.BOMEntry {
return libcnb.BOMEntry{
Name: b.ID,
Metadata: map[string]interface{}{
"name": b.Name,
"version": b.Version,
"uri": b.URI,
"sha256": b.SHA256,
"stacks": b.Stacks,
"licenses": b.Licenses,
},
}
}

// AsSyftArtifact renders a bill of materials entry describing the dependency as Syft.
func (b BuildpackDependency) AsSyftArtifact() (sbom.SyftArtifact, error) {
licenses := []string{}
Expand Down
Loading

0 comments on commit 1997908

Please sign in to comment.