Unverified Commit 428c62dc authored by Bryan Liles's avatar Bryan Liles Committed by GitHub
Browse files

Merge pull request #386 from bryanl/registry-override

allow user to override registries locally
parents a24f4a59 72c41b84
......@@ -668,6 +668,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "bd48a9a8d4ee540e42428541efff20b6f32922f3994d0e2ddc40c980ffd02341"
inputs-digest = "6a3688925e4c4c6cc43e54ca791b705e438fad130a1c3f686d1cf9390715883a"
solver-name = "gps-cdcl"
solver-version = 1
......@@ -66,11 +66,12 @@ func mockNsWithName(name string) *cmocks.Namespace {
return m
}
func mockRegistry(name string) *rmocks.Registry {
func mockRegistry(name string, isOverride bool) *rmocks.Registry {
m := &rmocks.Registry{}
m.On("Name").Return(name)
m.On("Protocol").Return(registry.ProtocolGitHub)
m.On("URI").Return("github.com/ksonnet/parts/tree/master/incubator")
m.On("IsOverride").Return(isOverride)
return m
}
......@@ -43,17 +43,17 @@ func RunPkgList(ksApp app.App) error {
// PkgList lists available registries
type PkgList struct {
app app.App
rm registry.Manager
out io.Writer
app app.App
registryList func(ksApp app.App) ([]registry.Registry, error)
out io.Writer
}
// NewPkgList creates an instance of PkgList
func NewPkgList(ksApp app.App) (*PkgList, error) {
rl := &PkgList{
app: ksApp,
rm: registry.DefaultManager,
out: os.Stdout,
app: ksApp,
registryList: registry.List,
out: os.Stdout,
}
return rl, nil
......@@ -61,7 +61,7 @@ func NewPkgList(ksApp app.App) (*PkgList, error) {
// Run runs the env list action.
func (pl *PkgList) Run() error {
registries, err := pl.rm.List(pl.app)
registries, err := pl.registryList(pl.app)
if err != nil {
return err
}
......
......@@ -22,7 +22,6 @@ import (
"github.com/ksonnet/ksonnet/metadata/app"
amocks "github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/ksonnet/ksonnet/pkg/registry"
rmocks "github.com/ksonnet/ksonnet/pkg/registry/mocks"
"github.com/stretchr/testify/require"
)
......@@ -40,9 +39,6 @@ func TestPkgList(t *testing.T) {
var buf bytes.Buffer
a.out = &buf
rm := &rmocks.Manager{}
a.rm = rm
spec := &registry.Spec{
Libraries: registry.LibraryRefSpecs{
"lib1": &registry.LibraryRef{},
......@@ -50,11 +46,13 @@ func TestPkgList(t *testing.T) {
},
}
incubator := mockRegistry("incubator")
incubator := mockRegistry("incubator", false)
incubator.On("FetchRegistrySpec").Return(spec, nil)
registries := []registry.Registry{incubator}
rm.On("List", appMock).Return(registries, nil)
a.registryList = func(app.App) ([]registry.Registry, error) {
registries := []registry.Registry{incubator}
return registries, nil
}
err = a.Run()
require.NoError(t, err)
......
......@@ -24,33 +24,34 @@ import (
)
// RunRegistryAdd runs `registry add`
func RunRegistryAdd(ksApp app.App, name, uri, version string) error {
nl, err := NewRegistryAdd(ksApp, name, uri, version)
func RunRegistryAdd(ksApp app.App, name, uri, version string, isOverride bool) error {
ra, err := NewRegistryAdd(ksApp, name, uri, version, isOverride)
if err != nil {
return err
}
return nl.Run()
return ra.Run()
}
// RegistryAdd lists namespaces.
type RegistryAdd struct {
app app.App
name string
uri string
version string
rm registry.Manager
app app.App
name string
uri string
version string
isOverride bool
registryAdd func(a app.App, name, protocol, uri, version string, isOverride bool) (*registry.Spec, error)
}
// NewRegistryAdd creates an instance of RegistryAdd.
func NewRegistryAdd(ksApp app.App, name, uri, version string) (*RegistryAdd, error) {
func NewRegistryAdd(ksApp app.App, name, uri, version string, isOverride bool) (*RegistryAdd, error) {
ra := &RegistryAdd{
app: ksApp,
name: name,
uri: uri,
version: version,
rm: registry.DefaultManager,
app: ksApp,
name: name,
uri: uri,
version: version,
isOverride: isOverride,
registryAdd: registry.Add,
}
return ra, nil
......@@ -59,7 +60,7 @@ func NewRegistryAdd(ksApp app.App, name, uri, version string) (*RegistryAdd, err
// Run lists namespaces.
func (ra *RegistryAdd) Run() error {
uri, protocol := ra.protocol()
_, err := ra.rm.Add(ra.app, ra.name, protocol, uri, ra.version)
_, err := ra.registryAdd(ra.app, ra.name, protocol, uri, ra.version, ra.isOverride)
return err
}
......
......@@ -18,9 +18,10 @@ package actions
import (
"testing"
"github.com/ksonnet/ksonnet/metadata/app"
amocks "github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/ksonnet/ksonnet/pkg/registry"
"github.com/ksonnet/ksonnet/pkg/registry/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
......@@ -34,6 +35,7 @@ func TestRegistryAdd(t *testing.T) {
version string
expectedURI string
protocol string
isOverride bool
}{
{
name: "github",
......@@ -41,6 +43,13 @@ func TestRegistryAdd(t *testing.T) {
expectedURI: "github.com/foo/bar",
protocol: registry.ProtocolGitHub,
},
{
name: "github override",
uri: "github.com/foo/bar",
expectedURI: "github.com/foo/bar",
protocol: registry.ProtocolGitHub,
isOverride: true,
},
{
name: "fs",
uri: "/path",
......@@ -57,12 +66,18 @@ func TestRegistryAdd(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
a, err := NewRegistryAdd(appMock, name, tc.uri, tc.version)
a, err := NewRegistryAdd(appMock, name, tc.uri, tc.version, tc.isOverride)
require.NoError(t, err)
rm := &mocks.Manager{}
rm.On("Add", appMock, "new", tc.protocol, tc.expectedURI, tc.version).Return(nil, nil)
a.rm = rm
a.registryAdd = func(a app.App, name, protocol, uri, version string, isOverride bool) (*registry.Spec, error) {
assert.Equal(t, "new", name)
assert.Equal(t, tc.protocol, protocol)
assert.Equal(t, tc.expectedURI, uri)
assert.Equal(t, tc.version, version)
assert.Equal(t, tc.isOverride, isOverride)
return &registry.Spec{}, nil
}
err = a.Run()
require.NoError(t, err)
......
......@@ -18,6 +18,7 @@ package actions
import (
"io"
"os"
"sort"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/ksonnet/ksonnet/pkg/registry"
......@@ -36,17 +37,17 @@ func RunRegistryList(ksApp app.App) error {
// RegistryList lists available registries
type RegistryList struct {
app app.App
rm registry.Manager
out io.Writer
app app.App
registryList func(ksApp app.App) ([]registry.Registry, error)
out io.Writer
}
// NewRegistryList creates an instance of RegistryList
func NewRegistryList(ksApp app.App) (*RegistryList, error) {
rl := &RegistryList{
app: ksApp,
rm: registry.DefaultManager,
out: os.Stdout,
app: ksApp,
registryList: registry.List,
out: os.Stdout,
}
return rl, nil
......@@ -54,24 +55,34 @@ func NewRegistryList(ksApp app.App) (*RegistryList, error) {
// Run runs the env list action.
func (rl *RegistryList) Run() error {
registries, err := rl.rm.List(rl.app)
registries, err := rl.registryList(rl.app)
if err != nil {
return err
}
t := table.New(rl.out)
t.SetHeader([]string{"name", "protocol", "uri"})
t.SetHeader([]string{"name", "override", "protocol", "uri"})
var rows [][]string
for _, r := range registries {
override := ""
if r.IsOverride() {
override = "*"
}
rows = append(rows, []string{
r.Name(),
override,
r.Protocol(),
r.URI(),
})
}
sort.Slice(rows, func(i, j int) bool {
return rows[i][0] < rows[j][0]
})
t.AppendBulk(rows)
return t.Render()
......
......@@ -19,9 +19,9 @@ import (
"bytes"
"testing"
"github.com/ksonnet/ksonnet/metadata/app"
amocks "github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/ksonnet/ksonnet/pkg/registry"
rmocks "github.com/ksonnet/ksonnet/pkg/registry/mocks"
"github.com/stretchr/testify/require"
)
......@@ -33,13 +33,13 @@ func TestRegistryList(t *testing.T) {
var buf bytes.Buffer
a.out = &buf
rm := &rmocks.Manager{}
a.rm = rm
registries := []registry.Registry{
mockRegistry("incubator"),
a.registryList = func(app.App) ([]registry.Registry, error) {
registries := []registry.Registry{
mockRegistry("override", true),
mockRegistry("incubator", false),
}
return registries, nil
}
rm.On("List", appMock).Return(registries, nil)
err = a.Run()
require.NoError(t, err)
......
NAME PROTOCOL URI
==== ======== ===
incubator github github.com/ksonnet/parts/tree/master/incubator
NAME OVERRIDE PROTOCOL URI
==== ======== ======== ===
incubator github github.com/ksonnet/parts/tree/master/incubator
override * github github.com/ksonnet/parts/tree/master/incubator
......@@ -15,14 +15,17 @@
package cmd
var (
const (
flagEnv = "env"
flagFilename = "filename"
flagIndex = "index"
flagOutput = "output"
flagNamespace = "namespace"
flagOutput = "output"
flagOverride = "override"
flagVersion = "version"
shortFilename = "f"
shortIndex = "i"
shortOutput = "o"
shortOverride = "o"
)
......@@ -22,10 +22,6 @@ import (
"github.com/spf13/cobra"
)
const (
flagRegistryVersion = "version"
)
var regShortDesc = map[string]string{
"list": "List all registries known to the current ksonnet app.",
"describe": "Describe a ksonnet registry and the packages it contains",
......
......@@ -18,16 +18,21 @@ package cmd
import (
"fmt"
"github.com/spf13/viper"
"github.com/ksonnet/ksonnet/actions"
"github.com/spf13/cobra"
)
const (
vRegistryAddVersion = "registry-add-version"
vRegistryAddOverride = "registry-add-override"
)
var registryAddCmd = &cobra.Command{
Use: "add <registry-name> <registry-uri>",
Short: regShortDesc["add"],
RunE: func(cmd *cobra.Command, args []string) error {
flags := cmd.Flags()
if len(args) != 2 {
return fmt.Errorf("Command 'registry add' takes two arguments, which is the name and the repository address of the registry to add")
}
......@@ -35,12 +40,10 @@ var registryAddCmd = &cobra.Command{
name := args[0]
uri := args[1]
version, err := flags.GetString(flagRegistryVersion)
if err != nil {
return err
}
version := viper.GetString(vRegistryAddVersion)
isOverride := viper.GetBool(vRegistryAddOverride)
return actions.RunRegistryAdd(ka, name, uri, version)
return actions.RunRegistryAdd(ka, name, uri, version, isOverride)
},
Long: `
......@@ -54,12 +57,18 @@ A registry is uniquely identified by its:
1. Name (e.g. ` + "`incubator`" + `)
2. Version (e.g. ` + "`master`" + `)
Currently, only registries supporting the **GitHub protocol** can be added.
There are two supported registry protocols: **github** and **fs**.
GitHub registries expect a path in a GitHub repository, and filesystem based
registries expect a path on the local filesystem.
During creation, all registries must specify a unique name and URI where the
registry lives. Optionally, a version can be provided (e.g. the *Github branch
name*). If a version is not specified, it will default to ` + "`latest`" + `.
Registries can be overridden with ` + "`--override`" + `. Overridden registries
are stored in ` + "`app.override.yaml`" + ` and can be safely ignored using your
SCM configuration.
### Related Commands
......@@ -79,5 +88,9 @@ ks registry add databases github.com/example/tree/master/reg --version=0.0.1`,
func init() {
registryCmd.AddCommand(registryAddCmd)
registryAddCmd.PersistentFlags().String(flagRegistryVersion, "", "Version of the registry to add")
registryAddCmd.Flags().String(flagVersion, "", "Version of the registry to add")
viper.BindPFlag(vRegistryAddVersion, registryAddCmd.Flags().Lookup(flagVersion))
registryAddCmd.Flags().BoolP(flagOverride, shortOverride, false, "Store in override configuration")
viper.BindPFlag(vRegistryAddOverride, registryAddCmd.Flags().Lookup(flagOverride))
}
......@@ -15,12 +15,18 @@ A registry is uniquely identified by its:
1. Name (e.g. `incubator`)
2. Version (e.g. `master`)
Currently, only registries supporting the **GitHub protocol** can be added.
There are two supported registry protocols: **github** and **fs**.
GitHub registries expect a path in a GitHub repository, and filesystem based
registries expect a path on the local filesystem.
During creation, all registries must specify a unique name and URI where the
registry lives. Optionally, a version can be provided (e.g. the *Github branch
name*). If a version is not specified, it will default to `latest`.
Registries can be overridden with `--override`. Overridden registries
are stored in `app.override.yaml` and can be safely ignored using your
SCM configuration.
### Related Commands
......@@ -49,6 +55,7 @@ ks registry add databases github.com/example/tree/master/reg --version=0.0.1
```
-h, --help help for add
-o, --override Store in override configuration
--version string Version of the registry to add
```
......
......@@ -33,42 +33,105 @@ var _ = Describe("ks registry", func() {
})
Describe("add", func() {
Context("global", func() {
var add = func(path string) {
o := a.runKs("registry", "add", "local", path)
assertExitStatus(o, 0)
var add = func(path string) {
o := a.runKs("registry", "add", "local", path)
assertExitStatus(o, 0)
uri := convertPathToURI(path)
m := map[string]interface{}{
"uri": uri,
}
uri := convertPathToURI(path)
m := map[string]interface{}{
"uri": uri,
o = a.registryList()
tPath := filepath.Join("registry", "add", "output.txt.tmpl")
assertTemplate(m, tPath, o.stdout)
}
o = a.registryList()
Context("a filesystem based registry", func() {
Context("as a path", func() {
It("adds a registry", func() {
path, err := filepath.Abs(filepath.Join("testdata", "registries", "parts-infra"))
Expect(err).ToNot(HaveOccurred())
tPath := filepath.Join("registry", "add", "output.txt.tmpl")
assertTemplate(m, tPath, o.stdout)
}
add(path)
})
})
Context("as a URL", func() {
It("adds a registry", func() {
path, err := filepath.Abs(filepath.Join("testdata", "registries", "parts-infra"))
Expect(err).ToNot(HaveOccurred())
Context("a filesystem based registry", func() {
Context("as a path", func() {
It("adds a registry", func() {
path, err := filepath.Abs(filepath.Join("testdata", "registries", "parts-infra"))
Expect(err).ToNot(HaveOccurred())
uri := convertPathToURI(path)
add(uri)
})
})
})
})
Context("override", func() {
var add = func(name, path string) {
o := a.runKs("registry", "add", "--override", name, path)
assertExitStatus(o, 0)
}
add(path)
Context("a filesystem based registry", func() {
Context("as a path", func() {
It("adds a registry", func() {
path, err := filepath.Abs(filepath.Join("testdata", "registries", "parts-infra"))
Expect(err).ToNot(HaveOccurred())
add("local", path)
o := a.registryList()
uri := convertPathToURI(path)
m := map[string]interface{}{
"uri": uri,
}
tPath := filepath.Join("registry", "add", "override-output.txt.tmpl")
assertTemplate(m, tPath, o.stdout)
})
})
Context("as a URL", func() {
It("adds a registry", func() {
path, err := filepath.Abs(filepath.Join("testdata", "registries", "parts-infra"))
Expect(err).ToNot(HaveOccurred())
uri := convertPathToURI(path)
add("local", uri)
o := a.registryList()
m := map[string]interface{}{
"uri": uri,
}
tPath := filepath.Join("registry", "add", "override-output.txt.tmpl")
assertTemplate(m, tPath, o.stdout)
})
})
})
Context("as a URL", func() {
It("adds a registry", func() {
Context("an existing configuration", func() {
It("overrides the existing configuration", func() {
path, err := filepath.Abs(filepath.Join("testdata", "registries", "parts-infra"))
Expect(err).ToNot(HaveOccurred())
uri := convertPathToURI(path)
add("incubator", path)
add(uri)
o := a.registryList()
uri := convertPathToURI(path)
m := map[string]interface{}{
"uri": uri,
}
tPath := filepath.Join("registry", "add", "override-incubator.txt.tmpl")
assertTemplate(m, tPath, o.stdout)
})
})
})
})
......
NAME PROTOCOL URI
==== ======== ===
incubator github github.com/ksonnet/parts/tree/master/incubator
local fs {{ .uri }}
NAME OVERRIDE PROTOCOL URI
==== ======== ======== ===
incubator github github.com/ksonnet/parts/tree/master/incubator
local fs {{ .uri }}
NAME OVERRIDE PROTOCOL URI
==== ======== ======== ===
incubator * fs {{ .uri }}
NAME OVERRIDE PROTOCOL URI
==== ======== ======== ===
incubator github github.com/ksonnet/parts/tree/master/incubator
local * fs {{ .uri }}
NAME PROTOCOL URI
==== ======== ===
incubator github github.com/ksonnet/parts/tree/master/incubator
NAME OVERRIDE PROTOCOL URI
==== ======== ======== ===
incubator github github.com/ksonnet/parts/tree/master/incubator
......@@ -27,9 +27,12 @@ import (
const (
// appYamlName is the name for the app specification.
// appYamlName is the name for the app configuration.
appYamlName = "app.yaml"
// overrideYamlName is the name for the app overrides.
overrideYamlName = "app.override.yaml"
// EnvironmentDirName is the directory name for environments.
EnvironmentDirName = "environments"