Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement add-buildpack-registry #847

Merged
merged 6 commits into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type ConfigurableLogger interface {
// NewPackCommand generates a Pack command
func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) {
cobra.EnableCommandSorting = false
cfg, err := initConfig()
cfg, cfgPath, err := initConfig()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -85,6 +85,7 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) {

if cfg.Experimental {
rootCmd.AddCommand(commands.ListBuildpackRegistries(logger, cfg))
rootCmd.AddCommand(commands.AddBuildpackRegistry(logger, cfg, cfgPath))
rootCmd.AddCommand(commands.RegisterBuildpack(logger, cfg, &packClient))
rootCmd.AddCommand(commands.YankBuildpack(logger, cfg, &packClient))
}
Expand All @@ -99,17 +100,17 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) {
return rootCmd, nil
}

func initConfig() (config.Config, error) {
func initConfig() (config.Config, string, error) {
path, err := config.DefaultConfigPath()
if err != nil {
return config.Config{}, errors.Wrap(err, "getting config path")
return config.Config{}, "", errors.Wrap(err, "getting config path")
}

cfg, err := config.Read(path)
if err != nil {
return config.Config{}, errors.Wrap(err, "reading pack config")
return config.Config{}, "", errors.Wrap(err, "reading pack config")
}
return cfg, nil
return cfg, path, nil
}

func initClient(logger logging.Logger, cfg config.Config) (pack.Client, error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/blob/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (d *downloader) downloadAsStream(ctx context.Context, uri string, etag stri

return nil, "", fmt.Errorf(
"could not download from %s, code http status %s",
style.Symbol(uri), style.Symbol("%d", resp.StatusCode),
style.Symbol(uri), style.SymbolF("%d", resp.StatusCode),
)
}

Expand Down
74 changes: 74 additions & 0 deletions internal/commands/add_buildpack_registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package commands

import (
"strings"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/buildpacks/pack/internal/slices"
"github.com/buildpacks/pack/internal/stringset"
"github.com/buildpacks/pack/internal/style"
"github.com/buildpacks/pack/registry"

"github.com/buildpacks/pack/internal/config"
"github.com/buildpacks/pack/logging"
)

func AddBuildpackRegistry(logger logging.Logger, cfg config.Config, cfgPath string) *cobra.Command {
var (
setDefault bool
registryType string
)

cmd := &cobra.Command{
Use: "add-buildpack-registry <name> <url>",
Args: cobra.ExactArgs(2),
Short: "Adds a new buildpack registry to your pack config file",
RunE: logError(logger, func(cmd *cobra.Command, args []string) error {
newRegistry := config.Registry{
Name: args[0],
URL: args[1],
Type: registryType,
}

err := addRegistry(newRegistry, setDefault, cfg, cfgPath)
if err != nil {
return err
}

logger.Infof("Successfully added %s to buildpack registries", style.Symbol(newRegistry.Name))

return nil
}),
}
cmd.Example = "pack add-buildpack-registry my-registry https://github.com/buildpacks/my-buildpack"
cmd.Flags().BoolVar(&setDefault, "default", false, "Set this buildpack registry as the default")
cmd.Flags().StringVar(&registryType, "type", "github", "Type of buildpack registry [git|github]")
AddHelpFlag(cmd, "add-buildpack-registry")

return cmd
}

func addRegistry(newRegistry config.Registry, setDefault bool, cfg config.Config, cfgPath string) error {
if _, ok := stringset.FromSlice(registry.Types)[newRegistry.Type]; !ok {
return errors.Errorf(
"%s is not a valid type. Supported types are: %s.",
style.Symbol(newRegistry.Type),
strings.Join(slices.MapString(registry.Types, style.Symbol), ", "))
}

for _, r := range cfg.Registries {
if r.Name == newRegistry.Name {
return errors.Errorf(
"Buildpack registry %s already exists.",
style.Symbol(newRegistry.Name))
}
}

if setDefault {
cfg.DefaultRegistryName = newRegistry.Name
}
cfg.Registries = append(cfg.Registries, newRegistry)
return config.Write(cfg, cfgPath)
}
98 changes: 98 additions & 0 deletions internal/commands/add_buildpack_registry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package commands_test

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

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

"github.com/buildpacks/pack/internal/commands"
"github.com/buildpacks/pack/internal/config"
ilogging "github.com/buildpacks/pack/internal/logging"
h "github.com/buildpacks/pack/testhelpers"
)

func TestAddBuildpackRegistry(t *testing.T) {
color.Disable(true)
defer color.Disable(false)

spec.Run(t, "Commands", testAddBuildpackRegistryCommand, spec.Parallel(), spec.Report(report.Terminal{}))
}

func testAddBuildpackRegistryCommand(t *testing.T, when spec.G, it spec.S) {
when("AddBuildpackRegistry", func() {
var (
outBuf bytes.Buffer
logger = ilogging.NewLogWithWriters(&outBuf, &outBuf)
tmpDir string
configFile string
assert = h.NewAssertionManager(t)
)

it.Before(func() {
var err error
tmpDir, err = ioutil.TempDir("", "pack-home-*")
assert.Nil(err)

configFile = filepath.Join(tmpDir, "config.toml")
})

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

when("default is true", func() {
it("sets newly added registry as the default", func() {
command := commands.AddBuildpackRegistry(logger, config.Config{}, configFile)
command.SetArgs([]string{"bp", "https://github.com/buildpacks/registry-index/", "--default"})
assert.Succeeds(command.Execute())

cfg, err := config.Read(configFile)
assert.Nil(err)

assert.Equal(cfg.DefaultRegistryName, "bp")
})
})

when("validation", func() {
it("fails with missing args", func() {
command := commands.AddBuildpackRegistry(logger, config.Config{}, configFile)
command.SetOut(ioutil.Discard)
command.SetArgs([]string{})
err := command.Execute()
assert.ErrorContains(err, "accepts 2 arg")
})

it("should validate type", func() {
command := commands.AddBuildpackRegistry(logger, config.Config{}, configFile)
command.SetArgs([]string{"bp", "https://github.com/buildpacks/registry-index/", "--type=bogus"})
assert.Error(command.Execute())

output := outBuf.String()
h.AssertContains(t, output, "'bogus' is not a valid type. Supported types are: 'git', 'github'.")
})

it("should throw error when registry already exists", func() {
command := commands.AddBuildpackRegistry(logger, config.Config{
Registries: []config.Registry{
{
Name: "bp",
Type: "github",
URL: "https://github.com/buildpacks/registry-index/",
},
},
}, configFile)
command.SetArgs([]string{"bp", "https://github.com/buildpacks/registry-index/"})
assert.Error(command.Execute())

output := outBuf.String()
h.AssertContains(t, output, "Buildpack registry 'bp' already exists.")
})
})
})
}
1 change: 1 addition & 0 deletions internal/commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ func Build(logger logging.Logger, cfg config.Config, packClient PackClient) *cob
func buildCommandFlags(cmd *cobra.Command, buildFlags *BuildFlags, cfg config.Config) {
cmd.Flags().StringVarP(&buildFlags.AppPath, "path", "p", "", "Path to app dir or zip-formatted file (defaults to current working directory)")
cmd.Flags().StringVarP(&buildFlags.Builder, "builder", "B", cfg.DefaultBuilder, "Builder image")
//nolint:staticcheck
cmd.Flags().StringVarP(&buildFlags.Registry, "buildpack-registry", "R", cfg.DefaultRegistry, "Buildpack Registry URL")
if !cfg.Experimental {
cmd.Flags().MarkHidden("buildpack-registry")
Expand Down
1 change: 1 addition & 0 deletions internal/commands/create_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func CreateBuilder(logger logging.Logger, cfg config.Config, client PackClient)
}),
}

//nolint:staticcheck
cmd.Flags().StringVarP(&flags.Registry, "buildpack-registry", "R", cfg.DefaultRegistry, "Buildpack Registry URL")
if !cfg.Experimental {
cmd.Flags().MarkHidden("buildpack-registry")
Expand Down
1 change: 1 addition & 0 deletions internal/commands/inspect_buildpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func InspectBuildpack(logger logging.Logger, cfg *config.Config, client PackClie
buildpackName := args[0]
registry := flags.Registry
if registry == "" {
//nolint:staticcheck
registry = cfg.DefaultRegistry
}

Expand Down
5 changes: 3 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import (
)

type Config struct {
RunImages []RunImage `toml:"run-images"`
DefaultBuilder string `toml:"default-builder-image,omitempty"`
RunImages []RunImage `toml:"run-images"`
DefaultBuilder string `toml:"default-builder-image,omitempty"`
// Deprecated: Use DefaultRegistryName instead. See https://github.com/buildpacks/pack/issues/747.
DefaultRegistry string `toml:"default-registry-url,omitempty"`
DefaultRegistryName string `toml:"default-registry,omitempty"`
Experimental bool `toml:"experimental,omitempty"`
Expand Down
9 changes: 9 additions & 0 deletions internal/slices/slices.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package slices

func MapString(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))
for i, v := range vs {
vsm[i] = f(v)
}
return vsm
}
31 changes: 31 additions & 0 deletions internal/slices/slices_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package slices_test

import (
"testing"

"github.com/sclevine/spec"

"github.com/buildpacks/pack/internal/slices"
h "github.com/buildpacks/pack/testhelpers"
)

func TestMapString(t *testing.T) {
spec.Run(t, "Slices", func(t *testing.T, when spec.G, it spec.S) {
var (
assert = h.NewAssertionManager(t)
)

when("#MapString", func() {
it("maps each value", func() {
input := []string{"hello", "1", "2", "world"}
expected := []string{"hello.", "1.", "2.", "world."}
fn := func(v string) string {
return v + "."
}

output := slices.MapString(input, fn)
assert.Equal(output, expected)
})
})
})
}
12 changes: 6 additions & 6 deletions internal/style/style.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import (
"github.com/heroku/color"
)

var Noop = func(format string, a ...interface{}) string {
return color.WhiteString("") + fmt.Sprintf(format, a...)
var Symbol = func(value string) string {
if color.Enabled() {
return Key(value)
}
return "'" + value + "'"
}

var Symbol = func(format string, a ...interface{}) string {
var SymbolF = func(format string, a ...interface{}) string {
if color.Enabled() {
return Key(format, a...)
}
Expand All @@ -30,9 +33,6 @@ var Step = func(format string, a ...interface{}) string {
}

var Prefix = color.CyanString

var TimestampColorCode = color.FgHiBlack

var Waiting = color.HiBlackString
var Working = color.HiBlueString
var Complete = color.GreenString
Expand Down
11 changes: 11 additions & 0 deletions registry/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package registry

const (
TypeGit = "git"
TypeGitHub = "github"
)

var Types = []string{
TypeGit,
TypeGitHub,
}
1 change: 1 addition & 0 deletions testhelpers/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ func (a AssertionManager) NotContainWithMessage(actual, expected, messageFormat
}
}

// Error checks that the provided value is an error (non-nil)
func (a AssertionManager) Error(actual error) {
a.testObject.Helper()

Expand Down