Skip to content

Commit

Permalink
Merge pull request #637 from buildpacks/feature/635-google-builder
Browse files Browse the repository at this point in the history
Add Google builder to suggested builders
  • Loading branch information
jromero authored May 20, 2020
2 parents 2e4f900 + 738e287 commit 896eb4e
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 81 deletions.
45 changes: 25 additions & 20 deletions acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type testWriter struct {
}

func (w *testWriter) Write(p []byte) (n int, err error) {
w.t.Log(string(p))
w.t.Logf(string(p))
return len(p), nil
}

Expand Down Expand Up @@ -263,13 +263,14 @@ func testWithoutSpecificBuilderRequirement(

when("suggest-builders", func() {
it("displays suggested builders", func() {
cmd := subjectPack("suggest-builders")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("suggest-builders command failed: %s: %s", output, err)
}
h.AssertContains(t, string(output), "Suggested builders:")
h.AssertContains(t, string(output), "gcr.io/paketo-buildpacks/builder:base")
output := h.Run(t, subjectPack("suggest-builders"))

h.AssertContains(t, output, "Suggested builders:")
h.AssertMatch(t, output, `Google:\s+'gcr.io/buildpacks/builder'`)
h.AssertMatch(t, output, `Heroku:\s+'heroku/buildpacks:18'`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:base'`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:full-cf'`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:tiny'`)
})
})

Expand Down Expand Up @@ -496,6 +497,22 @@ func testWithoutSpecificBuilderRequirement(
})
})
})

when("build", func() {
when("default builder is not set", func() {
it("informs the user", func() {
cmd := subjectPack("build", "some/image", "-p", filepath.Join("testdata", "mock_app"))
output, err := h.RunE(cmd)
h.AssertNotNil(t, err)
h.AssertContains(t, output, `Please select a default builder with:`)
h.AssertMatch(t, output, `Google:\s+'gcr.io/buildpacks/builder'`)
h.AssertMatch(t, output, `Heroku:\s+'heroku/buildpacks:18'`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:base'`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:full-cf'`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:tiny'`)
})
})
})
}

func testAcceptance(
Expand Down Expand Up @@ -1432,18 +1449,6 @@ include = [ "*.jar", "media/mountain.jpg", "media/person.png" ]
})
})
})

when("default builder is not set", func() {
it("informs the user", func() {
cmd := subjectPack("build", repoName, "-p", filepath.Join("testdata", "mock_app"))
output, err := h.RunE(cmd)
h.AssertNotNil(t, err)
h.AssertContains(t, output, `Please select a default builder with:`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:base'`)
h.AssertMatch(t, output, `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:full-cf'`)
h.AssertMatch(t, output, `Heroku:\s+'heroku/buildpacks:18'`)
})
})
})

when("inspect-builder", func() {
Expand Down
6 changes: 3 additions & 3 deletions acceptance/github_asset_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func NewGithubAssetFetcher(githubToken string, logger logging.Logger) (*GithubAs
// The return value is the location of the asset on disk, or any error encountered.
func (f *GithubAssetFetcher) FetchReleaseAsset(owner, repo, version string, expr *regexp.Regexp, extract bool) (string, error) {
if destPath, _ := f.cachedAsset(owner, repo, version, expr); destPath != "" {
f.logger.Infof("found %s in cache for %s/%s %s", destPath, owner, repo, version)
f.logger.Infof("found %s in cache for %s/%s@%s", destPath, owner, repo, version)
return destPath, nil
}

Expand Down Expand Up @@ -159,7 +159,7 @@ func extractType(extract bool, assetName string) string {

func (f *GithubAssetFetcher) FetchReleaseSource(owner, repo, version string) (string, error) {
if destDir, _ := f.cachedSource(owner, repo, version); destDir != "" {
f.logger.Infof("found %s in cache for %s/%s %s", destDir, owner, repo, version)
f.logger.Infof("found %s in cache for %s/%s@%s", destDir, owner, repo, version)
return destDir, nil
}

Expand Down Expand Up @@ -191,7 +191,7 @@ func (f *GithubAssetFetcher) FetchReleaseSource(owner, repo, version string) (st
// Ex: when n is -1, the latest patch of the previous minor version is returned.
func (f *GithubAssetFetcher) FetchReleaseVersion(owner, repo string, n int) (string, error) {
if version, _ := f.cachedVersion(owner, repo, n); version != "" {
f.logger.Infof("found %s in cache for %s/%s %d", version, owner, repo, n)
f.logger.Infof("found %s in cache for %s/%s n%d", version, owner, repo, n)
return version, nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/commands/inspect_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ Stack:
h.AssertNotNil(t, command.Execute())
h.AssertContains(t, outBuf.String(), `Please select a default builder with:
pack set-default-builder <builder image>`)
pack set-default-builder <builder-image>`)
h.AssertMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:base'`)
h.AssertMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:full-cf'`)
h.AssertMatch(t, outBuf.String(), `Heroku:\s+'heroku/buildpacks:18'`)
Expand Down
61 changes: 38 additions & 23 deletions internal/commands/suggest_builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,37 @@ import (
"github.com/buildpacks/pack/logging"
)

type suggestedBuilder struct {
Name string
type SuggestedBuilder struct {
Vendor string
Image string
DefaultDescription string
}

var suggestedBuilders = []suggestedBuilder{
var suggestedBuilders = []SuggestedBuilder{
{
Name: "Paketo Buildpacks",
Image: "gcr.io/paketo-buildpacks/builder:full-cf",
DefaultDescription: "Larger base image with buildpacks for Java, Node.js, Golang, .NET Core, & PHP",
Vendor: "Google",
Image: "gcr.io/buildpacks/builder",
DefaultDescription: "GCP Builder for all runtimes",
},
{
Name: "Paketo Buildpacks",
Vendor: "Heroku",
Image: "heroku/buildpacks:18",
DefaultDescription: "heroku-18 base image with buildpacks for Ruby, Java, Node.js, Python, Golang, & PHP",
},
{
Vendor: "Paketo Buildpacks",
Image: "gcr.io/paketo-buildpacks/builder:base",
DefaultDescription: "Small base image with buildpacks for Java, Node.js, Golang, & .NET Core",
},
{
Name: "Paketo Buildpacks",
Image: "gcr.io/paketo-buildpacks/builder:tiny",
DefaultDescription: "Tiny base image (bionic build image, distroless run image) with buildpacks for Golang",
Vendor: "Paketo Buildpacks",
Image: "gcr.io/paketo-buildpacks/builder:full-cf",
DefaultDescription: "Larger base image with buildpacks for Java, Node.js, Golang, .NET Core, & PHP",
},
{
Name: "Heroku",
Image: "heroku/buildpacks:18",
DefaultDescription: "heroku-18 base image with buildpacks for Ruby, Java, Node.js, Python, Golang, & PHP",
Vendor: "Paketo Buildpacks",
Image: "gcr.io/paketo-buildpacks/builder:tiny",
DefaultDescription: "Tiny base image (bionic build image, distroless run image) with buildpacks for Golang",
},
}

Expand All @@ -58,41 +63,51 @@ func SuggestBuilders(logger logging.Logger, client PackClient) *cobra.Command {
func suggestSettingBuilder(logger logging.Logger, client PackClient) {
logger.Info("Please select a default builder with:")
logger.Info("")
logger.Info("\tpack set-default-builder <builder image>")
logger.Info("\tpack set-default-builder <builder-image>")
logger.Info("")
suggestBuilders(logger, client)
}

func suggestBuilders(logger logging.Logger, client PackClient) {
sort.Slice(suggestedBuilders, func(i, j int) bool { return suggestedBuilders[i].Image < suggestedBuilders[j].Image })
WriteSuggestedBuilder(logger, client, suggestedBuilders)
}

func WriteSuggestedBuilder(logger logging.Logger, client PackClient, builders []SuggestedBuilder) {
sort.Slice(builders, func(i, j int) bool {
if builders[i].Vendor == builders[j].Vendor {
return builders[i].Image < builders[j].Image
}

return builders[i].Vendor < builders[j].Vendor
})

logger.Info("Suggested builders:")

// Fetch descriptions concurrently.
descriptions := make([]string, len(suggestedBuilders))
descriptions := make([]string, len(builders))

var wg sync.WaitGroup
for i, builder := range suggestedBuilders {
for i, builder := range builders {
wg.Add(1)

go func(i int, builder suggestedBuilder) {
go func(i int, builder SuggestedBuilder) {
descriptions[i] = getBuilderDescription(builder, client)
wg.Done()
}(i, builder)
}
wg.Wait()

tw := tabwriter.NewWriter(logger.Writer(), 10, 10, 5, ' ', tabwriter.TabIndent)
for i, builder := range suggestedBuilders {
fmt.Fprintf(tw, "\t%s:\t%s\t%s\t\n", builder.Name, style.Symbol(builder.Image), descriptions[i])
for i, builder := range builders {
fmt.Fprintf(tw, "\t%s:\t%s\t%s\t\n", builder.Vendor, style.Symbol(builder.Image), descriptions[i])
}
fmt.Fprintln(tw)

logging.Tip(logger, "Learn more about a specific builder with:\n")
logger.Info("\tpack inspect-builder [builder image]")
logging.Tip(logger, "Learn more about a specific builder with:")
logger.Info("\tpack inspect-builder <builder-image>")
}

func getBuilderDescription(builder suggestedBuilder, client PackClient) string {
func getBuilderDescription(builder SuggestedBuilder, client PackClient) string {
info, err := client.InspectBuilder(builder.Image, false)
if err == nil && info.Description != "" {
return info.Description
Expand Down
55 changes: 21 additions & 34 deletions internal/commands/suggest_builders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/heroku/color"
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
"github.com/spf13/cobra"

"github.com/buildpacks/pack"
"github.com/buildpacks/pack/internal/commands"
Expand All @@ -27,7 +26,6 @@ func TestSuggestBuilders(t *testing.T) {

func testSuggestBuildersCommand(t *testing.T, when spec.G, it spec.S) {
var (
command *cobra.Command
logger logging.Logger
outBuf bytes.Buffer
mockController *gomock.Controller
Expand All @@ -38,34 +36,24 @@ func testSuggestBuildersCommand(t *testing.T, when spec.G, it spec.S) {
mockController = gomock.NewController(t)
mockClient = testmocks.NewMockPackClient(mockController)
logger = ilogging.NewLogWithWriters(&outBuf, &outBuf)
command = commands.SuggestBuilders(logger, mockClient)
})

when("#SuggestBuilders", func() {
when("#WriteSuggestedBuilder", func() {
when("description metadata exists", func() {
it.Before(func() {
mockClient.EXPECT().InspectBuilder("gcr.io/paketo-buildpacks/builder:tiny", false).Return(&pack.BuilderInfo{
Description: "Tiny description",
}, nil)
mockClient.EXPECT().InspectBuilder("gcr.io/paketo-buildpacks/builder:base", false).Return(&pack.BuilderInfo{
Description: "Base description",
}, nil)
mockClient.EXPECT().InspectBuilder("gcr.io/paketo-buildpacks/builder:full-cf", false).Return(&pack.BuilderInfo{
Description: "CFLinuxFS3 description",
}, nil)
mockClient.EXPECT().InspectBuilder("heroku/buildpacks:18", false).Return(&pack.BuilderInfo{
Description: "Heroku description",
mockClient.EXPECT().InspectBuilder("gcr.io/some/builder:latest", false).Return(&pack.BuilderInfo{
Description: "Remote description",
}, nil)
})

it("displays descriptions from metadata", func() {
command.SetArgs([]string{})
h.AssertNil(t, command.Execute())
commands.WriteSuggestedBuilder(logger, mockClient, []commands.SuggestedBuilder{{
Vendor: "Builder",
Image: "gcr.io/some/builder:latest",
DefaultDescription: "Default description",
}})
h.AssertContains(t, outBuf.String(), "Suggested builders:")
h.AssertContainsMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:base'\s+Base description`)
h.AssertContainsMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:full-cf'\s+CFLinuxFS3 description`)
h.AssertContainsMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:tiny'\s+Tiny description`)
h.AssertContainsMatch(t, outBuf.String(), `Heroku:\s+'heroku/buildpacks:18'\s+Heroku description`)
h.AssertContainsMatch(t, outBuf.String(), `Builder:\s+'gcr.io/some/builder:latest'\s+Remote description`)
})
})

Expand All @@ -77,10 +65,13 @@ func testSuggestBuildersCommand(t *testing.T, when spec.G, it spec.S) {
})

it("displays default descriptions", func() {
command.SetArgs([]string{})
h.AssertNil(t, command.Execute())
commands.WriteSuggestedBuilder(logger, mockClient, []commands.SuggestedBuilder{{
Vendor: "Builder",
Image: "gcr.io/some/builder:latest",
DefaultDescription: "Default description",
}})
h.AssertContains(t, outBuf.String(), "Suggested builders:")
assertDefaultDescriptions(t, outBuf)
h.AssertContainsMatch(t, outBuf.String(), `Builder:\s+'gcr.io/some/builder:latest'\s+Default description`)
})
})

Expand All @@ -90,18 +81,14 @@ func testSuggestBuildersCommand(t *testing.T, when spec.G, it spec.S) {
})

it("displays default descriptions", func() {
command.SetArgs([]string{})
h.AssertNil(t, command.Execute())
commands.WriteSuggestedBuilder(logger, mockClient, []commands.SuggestedBuilder{{
Vendor: "Builder",
Image: "gcr.io/some/builder:latest",
DefaultDescription: "Default description",
}})
h.AssertContains(t, outBuf.String(), "Suggested builders:")
assertDefaultDescriptions(t, outBuf)
h.AssertContainsMatch(t, outBuf.String(), `Builder:\s+'gcr.io/some/builder:latest'\s+Default description`)
})
})
})
}

func assertDefaultDescriptions(t *testing.T, outBuf bytes.Buffer) {
h.AssertContainsMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:base'\s+Small base image with buildpacks for Java, Node.js, Golang, & .NET Core`)
h.AssertContainsMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:full-cf'\s+Larger base image with buildpacks for Java, Node.js, Golang, .NET Core, & PHP`)
h.AssertContainsMatch(t, outBuf.String(), `Paketo Buildpacks:\s+'gcr.io/paketo-buildpacks/builder:tiny'\s+Tiny base image \(bionic build image, distroless run image\) with buildpacks for Golang`)
h.AssertContainsMatch(t, outBuf.String(), `Heroku:\s+'heroku/buildpacks:18'\s+heroku-18 base image with buildpacks for Ruby, Java, Node.js, Python, Golang, & PHP`)
}
1 change: 1 addition & 0 deletions testhelpers/testhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func AssertContains(t *testing.T, actual, expected string) {
}
}

// AssertContainsMatch matches on content by regular expression
func AssertContainsMatch(t *testing.T, actual, exp string) {
t.Helper()
if !hasMatches(actual, exp) {
Expand Down

0 comments on commit 896eb4e

Please sign in to comment.