Skip to content

Commit

Permalink
create register-buildpack command
Browse files Browse the repository at this point in the history
Co-authored-by: Joe Kutner <jpkutner@gmail.com>

Signed-off-by: Travis Longoria <longoria.public@gmail.com>
  • Loading branch information
elbandito committed Jun 30, 2020
1 parent d6b44d5 commit 7b4853b
Show file tree
Hide file tree
Showing 10 changed files with 575 additions and 5 deletions.
2 changes: 2 additions & 0 deletions cmd/pack/main.go
Expand Up @@ -76,6 +76,8 @@ func main() {
rootCmd.AddCommand(commands.Version(logger, cmd.Version))
rootCmd.AddCommand(commands.Report(logger))

rootCmd.AddCommand(commands.RegisterBuildpack(logger, cfg, &packClient))

rootCmd.AddCommand(commands.CompletionCommand(logger))

rootCmd.Version = cmd.Version
Expand Down
1 change: 1 addition & 0 deletions internal/commands/commands.go
Expand Up @@ -24,6 +24,7 @@ type PackClient interface {
CreateBuilder(context.Context, pack.CreateBuilderOptions) error
PackageBuildpack(ctx context.Context, opts pack.PackageBuildpackOptions) error
Build(context.Context, pack.BuildOptions) error
RegisterBuildpack(context.Context, pack.RegisterBuildpackOptions) error
}

func AddHelpFlag(cmd *cobra.Command, commandName string) {
Expand Down
44 changes: 44 additions & 0 deletions internal/commands/register_buildpack.go
@@ -0,0 +1,44 @@
package commands

import (
"github.com/spf13/cobra"

"github.com/buildpacks/pack"
"github.com/buildpacks/pack/internal/style"

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

type RegisterBuildpackFlags struct {
BuildpackRegistry string
}

func RegisterBuildpack(logger logging.Logger, cfg config.Config, client PackClient) *cobra.Command {
var opts pack.RegisterBuildpackOptions
var flags RegisterBuildpackFlags

cmd := &cobra.Command{
Use: "register-buildpack <image>",
Args: cobra.ExactArgs(1),
Short: "Register the buildpack to a registry",
RunE: logError(logger, func(cmd *cobra.Command, args []string) error {
defaultRegistry, err := cfg.GetRegistry(flags.BuildpackRegistry)
if err != nil {
return err
}
opts.ImageName = args[0]
opts.Type = defaultRegistry.Type
opts.URL = defaultRegistry.URL

if err := client.RegisterBuildpack(cmd.Context(), opts); err != nil {
return err
}
logger.Infof("Successfully registered %s", style.Symbol(opts.ImageName))
return nil
}),
}
cmd.Flags().StringVarP(&flags.BuildpackRegistry, "buildpack-registry", "R", "", "Buildpack Registry name")
AddHelpFlag(cmd, "register-buildpack")
return cmd
}
151 changes: 151 additions & 0 deletions internal/commands/register_buildpack_test.go
@@ -0,0 +1,151 @@
package commands_test

import (
"bytes"
"testing"

"github.com/buildpacks/pack/internal/commands"

"github.com/buildpacks/pack"

"github.com/golang/mock/gomock"
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
"github.com/spf13/cobra"

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

func TestRegisterBuildpackCommand(t *testing.T) {
spec.Run(t, "Commands", testRegisterBuildpackCommand, spec.Parallel(), spec.Report(report.Terminal{}))
}

func testRegisterBuildpackCommand(t *testing.T, when spec.G, it spec.S) {
var (
command *cobra.Command
logger logging.Logger
outBuf bytes.Buffer
mockController *gomock.Controller
mockClient *testmocks.MockPackClient
cfg config.Config
)

it.Before(func() {
logger = ilogging.NewLogWithWriters(&outBuf, &outBuf)
mockController = gomock.NewController(t)
mockClient = testmocks.NewMockPackClient(mockController)
cfg = config.Config{}

command = commands.RegisterBuildpack(logger, cfg, mockClient)
})

it.After(func() {})

when("#RegisterBuildpackCommand", func() {
when("no image is provided", func() {
it("fails to run", func() {
err := command.Execute()
h.AssertError(t, err, "accepts 1 arg")
})
})

when("image name is provided", func() {
var (
buildpackImage string
)

it.Before(func() {
buildpackImage = "buildpack/image"
})

it("should work for required args", func() {
opts := pack.RegisterBuildpackOptions{
ImageName: buildpackImage,
Type: "github",
URL: "https://github.com/buildpacks/registry",
}

mockClient.EXPECT().
RegisterBuildpack(gomock.Any(), opts).
Return(nil)

command.SetArgs([]string{buildpackImage})
h.AssertNil(t, command.Execute())
})

when("config.toml exists", func() {
it("should consume registry config values", func() {
cfg = config.Config{
DefaultRegistryRef: "berneuse",
Registries: []config.Registry{
{
Name: "berneuse",
Type: "github",
URL: "https://github.com/berneuse/buildpack-registry",
},
},
}
command = commands.RegisterBuildpack(logger, cfg, mockClient)
opts := pack.RegisterBuildpackOptions{
ImageName: buildpackImage,
Type: "github",
URL: "https://github.com/berneuse/buildpack-registry",
}

mockClient.EXPECT().
RegisterBuildpack(gomock.Any(), opts).
Return(nil)

command.SetArgs([]string{buildpackImage})
h.AssertNil(t, command.Execute())
})

it("should handle config errors", func() {
cfg = config.Config{
DefaultRegistryRef: "missing registry",
}
command = commands.RegisterBuildpack(logger, cfg, mockClient)
command.SetArgs([]string{buildpackImage})

err := command.Execute()
h.AssertNotNil(t, err)
})
})

it("should support buildpack-registry flag", func() {
buildpackRegistry := "override"
cfg = config.Config{
DefaultRegistryRef: "default",
Registries: []config.Registry{
{
Name: "default",
Type: "github",
URL: "https://github.com/default/buildpack-registry",
},
{
Name: "override",
Type: "github",
URL: "https://github.com/override/buildpack-registry",
},
},
}
opts := pack.RegisterBuildpackOptions{
ImageName: buildpackImage,
Type: "github",
URL: "https://github.com/override/buildpack-registry",
}
mockClient.EXPECT().
RegisterBuildpack(gomock.Any(), opts).
Return(nil)

command = commands.RegisterBuildpack(logger, cfg, mockClient)
command.SetArgs([]string{buildpackImage, "--buildpack-registry", buildpackRegistry})
h.AssertNil(t, command.Execute())
})
})
})
}
14 changes: 14 additions & 0 deletions internal/commands/testmocks/mock_pack_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 33 additions & 5 deletions internal/config/config.go
Expand Up @@ -9,11 +9,19 @@ import (
)

type Config struct {
RunImages []RunImage `toml:"run-images"`
DefaultBuilder string `toml:"default-builder-image,omitempty"`
DefaultRegistry string `toml:"default-registry-url,omitempty"`
Experimental bool `toml:"experimental,omitempty"`
TrustedBuilders []TrustedBuilder `toml:"trusted-builders,omitempty"`
RunImages []RunImage `toml:"run-images"`
DefaultBuilder string `toml:"default-builder-image,omitempty"`
DefaultRegistry string `toml:"default-registry-url,omitempty"`
DefaultRegistryRef string `toml:"default-registry,omitempty"`
Experimental bool `toml:"experimental,omitempty"`
TrustedBuilders []TrustedBuilder `toml:"trusted-builders,omitempty"`
Registries []Registry `toml:"registries,omitempty"`
}

type Registry struct {
Name string `toml:"name"`
Type string `toml:"type"`
URL string `toml:"url"`
}

type RunImage struct {
Expand Down Expand Up @@ -82,3 +90,23 @@ func SetRunImageMirrors(cfg Config, image string, mirrors []string) Config {
cfg.RunImages = append(cfg.RunImages, RunImage{Image: image, Mirrors: mirrors})
return cfg
}

func (cfg *Config) GetRegistry(registryName string) (Registry, error) {
if registryName == "" {
registryName = cfg.DefaultRegistryRef
}
if registryName != "" {
for _, registry := range cfg.Registries {
if registry.Name == registryName {
return registry, nil
}
}
return Registry{}, errors.Errorf("registry \"%s\" is not defined in your config file", registryName)
}

return Registry{
"original",
"github",
"https://github.com/buildpacks/registry",
}, nil
}
67 changes: 67 additions & 0 deletions internal/config/config_test.go
Expand Up @@ -174,4 +174,71 @@ func testConfig(t *testing.T, when spec.G, it spec.S) {
})
})
})

when("#GetRegistry", func() {
it("should return a default registry", func() {
cfg := config.SetRunImageMirrors(
config.Config{},
"some/run-image",
[]string{"some-other/run"},
)

h.AssertEq(t, len(cfg.RunImages), 1)
h.AssertEq(t, cfg.RunImages[0].Image, "some/run-image")
h.AssertSliceContainsOnly(t, cfg.RunImages[0].Mirrors, "some-other/run")
})

it("should return the corresponding registry", func() {
cfg := config.Config{
Registries: []config.Registry{
{
Name: "default",
Type: "github",
URL: "https://github.com/default/buildpack-registry",
},
},
}

registry, err := cfg.GetRegistry("default")

h.AssertNil(t, err)
h.AssertEq(t, registry, config.Registry{
Name: "default",
Type: "github",
URL: "https://github.com/default/buildpack-registry",
})
})

it("should return the first matched registry", func() {
cfg := config.Config{
Registries: []config.Registry{
{
Name: "duplicate registry",
Type: "github",
URL: "https://github.com/duplicate1/buildpack-registry",
},
{
Name: "duplicate registry",
Type: "github",
URL: "https://github.com/duplicate2/buildpack-registry",
},
},
}

registry, err := cfg.GetRegistry("duplicate registry")

h.AssertNil(t, err)
h.AssertEq(t, registry, config.Registry{
Name: "duplicate registry",
Type: "github",
URL: "https://github.com/duplicate1/buildpack-registry",
})
})

it("should return an error when mismatched", func() {
cfg := config.Config{}
_, err := cfg.GetRegistry("missing")
h.AssertError(t, err, "registry \"missing\" is not defined in your config file")
})
})
}
11 changes: 11 additions & 0 deletions internal/registry/registry.go
Expand Up @@ -24,6 +24,17 @@ const defaultRegistryURL = "https://github.com/buildpacks/registry-index"

const defaultRegistryDir = "registry"

const GithubIssueTitleTemplate = "{{ if .Yanked }}YANK{{else}}ADD{{end}} {{.Namespace}}/{{.Name}}@{{.Version}}"

const GithubIssueBodyTemplate = `
### Data
` + "```toml" + `
id = "{{.Namespace}}/{{.Name}}"
version = "{{.Version}}"
{{ if .Yanked }}{{else}}addr = "{{.Address}}"{{end}}
` + "```"

type Buildpack struct {
Namespace string `json:"ns"`
Name string `json:"name"`
Expand Down

0 comments on commit 7b4853b

Please sign in to comment.