diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index d0c5cab6c..ef29bf60f 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -642,6 +642,18 @@ func testAcceptance(t *testing.T, when spec.G, it spec.S) { }) }) + when("pack suggest-builders", func() { + it("displays suggested builders", func() { + cmd := packCmd("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), "cloudfoundry/cnb:bionic") + }) + }) + when("pack set-default-builder", func() { it("sets the default-stack-id in ~/.pack/config.toml", func() { cmd := packCmd("set-default-builder", "cloudfoundry/cnb:bionic") diff --git a/cmd/pack/main.go b/cmd/pack/main.go index 968b0ce33..e3e9461c4 100644 --- a/cmd/pack/main.go +++ b/cmd/pack/main.go @@ -51,6 +51,7 @@ func main() { rootCmd.AddCommand(commands.SetRunImagesMirrors(&logger)) rootCmd.AddCommand(commands.InspectBuilder(&logger, &cfg, &packClient)) rootCmd.AddCommand(commands.SetDefaultBuilder(&logger, &packClient)) + rootCmd.AddCommand(commands.SuggestBuilders(&logger)) rootCmd.AddCommand(commands.Version(&logger, Version)) diff --git a/commands/build.go b/commands/build.go index 48a0a3020..149bb7f4f 100644 --- a/commands/build.go +++ b/commands/build.go @@ -1,11 +1,6 @@ package commands import ( - "fmt" - "math/rand" - "text/tabwriter" - "time" - "github.com/spf13/cobra" "github.com/buildpack/pack" @@ -14,25 +9,6 @@ import ( "github.com/buildpack/pack/style" ) -type suggestedBuilder struct { - name string - image string - info string -} - -var suggestedBuilders = [][]suggestedBuilder{ - { - {"Cloud Foundry", "cloudfoundry/cnb:bionic", "small base image with Java & Node.js"}, - {"Cloud Foundry", "cloudfoundry/cnb:cflinuxfs3", "larger base image with Java, Node.js & Python"}, - }, - { - {"Heroku", "heroku/buildpacks", "heroku-18 base image with official Heroku buildpacks"}, - }, -} - -func init() { - rand.Seed(time.Now().UnixNano()) -} func Build(logger *logging.Logger, fetcher pack.ImageFetcher) *cobra.Command { var buildFlags pack.BuildFlags @@ -82,29 +58,6 @@ func Build(logger *logging.Logger, fetcher pack.ImageFetcher) *cobra.Command { return cmd } -func suggestSettingBuilder(logger *logging.Logger) { - logger.Info("Please select a default builder with:\n") - logger.Info("\tpack set-default-builder \n") - suggestBuilders(logger) -} - -func suggestBuilders(logger *logging.Logger) { - logger.Info("Suggested builders:\n") - tw := tabwriter.NewWriter(logger.RawWriter(), 10, 10, 5, ' ', tabwriter.TabIndent) - for len(suggestedBuilders) > 0 { - n := rand.Intn(len(suggestedBuilders)) - builders := suggestedBuilders[n] - for _, builder := range builders { - tw.Write([]byte(fmt.Sprintf("\t%s:\t%s\t%s\t\n", builder.name, style.Symbol(builder.image), builder.info))) - } - suggestedBuilders = append(suggestedBuilders[:n], suggestedBuilders[n+1:]...) - } - tw.Flush() - logger.Info("") - logger.Tip("Learn more about a specific builder with:\n") - logger.Info("\tpack inspect-builder [builder image]") -} - func buildCommandFlags(cmd *cobra.Command, buildFlags *pack.BuildFlags) { cmd.Flags().StringVarP(&buildFlags.AppDir, "path", "p", "", "Path to app dir (defaults to current working directory)") cmd.Flags().StringVar(&buildFlags.Builder, "builder", "", "Builder (defaults to builder configured by 'set-default-builder')") diff --git a/commands/commands.go b/commands/commands.go index 9270a79e1..c19daa291 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -3,9 +3,12 @@ package commands import ( "context" "fmt" + "github.com/buildpack/pack/style" + "math/rand" "os" "os/signal" "syscall" + "text/tabwriter" "github.com/docker/docker/client" "github.com/spf13/cobra" @@ -20,6 +23,23 @@ type PackClient interface { Rebase(context.Context, pack.RebaseOptions) error } + +type suggestedBuilder struct { + name string + image string + info string +} + +var suggestedBuilders = [][]suggestedBuilder{ + { + {"Cloud Foundry", "cloudfoundry/cnb:bionic", "small base image with Java & Node.js"}, + {"Cloud Foundry", "cloudfoundry/cnb:cflinuxfs3", "larger base image with Java, Node.js & Python"}, + }, + { + {"Heroku", "heroku/buildpacks", "heroku-18 base image with official Heroku buildpacks"}, + }, +} + func AddHelpFlag(cmd *cobra.Command, commandName string) { cmd.Flags().BoolP("help", "h", false, fmt.Sprintf("Help for '%s'", commandName)) } @@ -59,3 +79,28 @@ func createCancellableContext() context.Context { func dockerClient() (*client.Client, error){ return client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) } + + + +func suggestSettingBuilder(logger *logging.Logger) { + logger.Info("Please select a default builder with:\n") + logger.Info("\tpack set-default-builder \n") + suggestBuilders(logger) +} + +func suggestBuilders(logger *logging.Logger) { + logger.Info("Suggested builders:\n") + + tw := tabwriter.NewWriter(logger.RawWriter(), 10, 10, 5, ' ', tabwriter.TabIndent) + for _, i := range rand.Perm(len(suggestedBuilders)) { + builders := suggestedBuilders[i] + for _, builder := range builders { + _, _ = tw.Write([]byte(fmt.Sprintf("\t%s:\t%s\t%s\t\n", builder.name, style.Symbol(builder.image), builder.info))) + } + } + _ = tw.Flush() + + logger.Info("") + logger.Tip("Learn more about a specific builder with:\n") + logger.Info("\tpack inspect-builder [builder image]") +} \ No newline at end of file diff --git a/commands/suggest_builders.go b/commands/suggest_builders.go new file mode 100644 index 000000000..def1a870d --- /dev/null +++ b/commands/suggest_builders.go @@ -0,0 +1,22 @@ +package commands + +import ( + "github.com/buildpack/pack/logging" + "github.com/spf13/cobra" +) + +func SuggestBuilders(logger *logging.Logger) *cobra.Command { + cmd := &cobra.Command{ + Use: "suggest-builders", + Short: "Display list of recommended builders", + Args: cobra.NoArgs, + RunE: logError(logger, func(cmd *cobra.Command, args []string) error { + suggestBuilders(logger) + + return nil + }), + } + + AddHelpFlag(cmd, "suggest-builders") + return cmd +} diff --git a/commands/suggest_builders_test.go b/commands/suggest_builders_test.go new file mode 100644 index 000000000..6cb07ddd1 --- /dev/null +++ b/commands/suggest_builders_test.go @@ -0,0 +1,41 @@ +package commands_test + +import ( + "bytes" + "testing" + + "github.com/sclevine/spec" + "github.com/sclevine/spec/report" + "github.com/spf13/cobra" + + "github.com/buildpack/pack/commands" + "github.com/buildpack/pack/logging" + h "github.com/buildpack/pack/testhelpers" +) + +func TestSuggestBuilders(t *testing.T) { + spec.Run(t, "Commands", testSuggestBuildersCommand, spec.Parallel(), spec.Report(report.Terminal{})) +} + +func testSuggestBuildersCommand(t *testing.T, when spec.G, it spec.S) { + + var ( + command *cobra.Command + logger *logging.Logger + outBuf bytes.Buffer + ) + + it.Before(func() { + logger = logging.NewLogger(&outBuf, &outBuf, false, false) + command = commands.SuggestBuilders(logger) + }) + + when("#SuggestBuilders", func() { + it("display suggested builders", func() { + command.SetArgs([]string{}) + h.AssertNil(t, command.Execute()) + h.AssertContains(t, outBuf.String(), "Suggested builders:") + h.AssertContains(t, outBuf.String(), "cloudfoundry/cnb:bionic") + }) + }) +}