Repository: apigee/registry (go)

Issue:
Registry tool (configuration): `registry config set registry.project` feels awkward
I don't think we need to change the variable names, but wonder if we could support a default `registry.` prefix that is used when it's unspecified?

`registry config set project`
`registry config set address`
`registry config set insecure`

Pull request:
add default namespace "registry" to config props
Fixes #894

Patch:
diff --git a/cmd/registry/cmd/config/get.go b/cmd/registry/cmd/config/get.go
index 2099c46..90f8584 100644
--- a/cmd/registry/cmd/config/get.go
+++ b/cmd/registry/cmd/config/get.go
@@ -41,12 +41,12 @@ func getCommand() *cobra.Command {
 				return UnknownPropertyError{args[0]}
 			}
 
-			m, err := c.FlatMap()
+			v, err := c.Get(args[0])
 			if err != nil {
 				return fmt.Errorf("Cannot decode config: %v", err)
 			}
 
-			cmd.Println(m[args[0]])
+			cmd.Println(v)
 			return nil
 		},
 	}
diff --git a/pkg/config/configuration.go b/pkg/config/configuration.go
index 6d29f82..c5376e7 100644
--- a/pkg/config/configuration.go
+++ b/pkg/config/configuration.go
@@ -15,6 +15,7 @@
 package config
 
 import (
+	"fmt"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -40,6 +41,9 @@ type Registry struct {
 	Token    string `mapstructure:"token" yaml:"-"` // generated from TokenSource
 }
 
+// if a name is unqualified, attempt this namespace
+const default_namespace = "registry"
+
 // Write stores the Configuration in the passed file name.
 func (c Configuration) Write(name string) error {
 	if err := ValidateName(name); err != nil {
@@ -85,20 +89,40 @@ func (c Configuration) FlatMap() (map[string]interface{}, error) {
 	return flat, err
 }
 
-// Set sets a property from a qualified name.
+// Set sets a property from a qualified or default namespace name.
 func (c *Configuration) Set(k string, v interface{}) error {
+	if !strings.Contains(k, ".") {
+		k = default_namespace + "." + k
+	}
 	return c.FromMap(map[string]interface{}{
 		k: v,
 	})
 }
 
-// Unset removed a property by qualified name.
+// Unset removed a property by qualified or default namespace name.
 func (c *Configuration) Unset(k string) error {
+	if !strings.Contains(k, ".") {
+		k = default_namespace + "." + k
+	}
 	return c.FromMap(map[string]interface{}{
 		k: "",
 	})
 }
 
+// Get gets a property from a qualified or default namespace name.
+func (c *Configuration) Get(k string) (interface{}, error) {
+	m, err := c.FlatMap()
+	if err != nil {
+		return "", fmt.Errorf("Cannot decode config: %v", err)
+	}
+
+	if !strings.Contains(k, ".") {
+		k = default_namespace + "." + k
+	}
+
+	return m[k], nil
+}
+
 // FromMap populates a Configuration from a flat Map.
 // Existing values are overridden.
 func (c *Configuration) FromMap(m map[string]interface{}) error {


Test patch:
diff --git a/pkg/config/configuration_test.go b/pkg/config/configuration_test.go
index 5f18e29..490b9dc 100644
--- a/pkg/config/configuration_test.go
+++ b/pkg/config/configuration_test.go
@@ -94,6 +94,18 @@ func TestActiveSettings(t *testing.T) {
 	if diff := cmp.Diff(c, got); diff != "" {
 		t.Errorf("unexpected diff: (-want +got):\n%s", diff)
 	}
+
+	t.Setenv("APG_REGISTRY_ADDRESS", "ignore")
+	name, raw, err := config.ActiveRaw()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if name != "good" {
+		t.Errorf("want: %s, got: %s", "good", name)
+	}
+	if diff := cmp.Diff(raw, got); diff != "" {
+		t.Errorf("unexpected diff: (-want +got):\n%s", diff)
+	}
 }
 
 func TestSettingsEnvVars(t *testing.T) {
@@ -273,10 +285,29 @@ func TestManipulations(t *testing.T) {
 		t.Fatalf("unexpected diff: (-want +got):\n%s", diff)
 	}
 
+	if err = c.Set("location", "new location"); err != nil {
+		t.Fatal(err)
+	}
+	if m, err = c.FlatMap(); err != nil {
+		t.Fatal(err)
+	}
+	want["registry.location"] = "new location"
+	if diff := cmp.Diff(want, m); diff != "" {
+		t.Fatalf("unexpected diff: (-want +got):\n%s", diff)
+	}
+
+	l, err := c.Get("location")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if l != "new location" {
+		t.Errorf("want: %s, got: %s", "new location", l)
+	}
+
 	if err = c.Unset("registry.address"); err != nil {
 		t.Fatal(err)
 	}
-	if err = c.Unset("registry.insecure"); err != nil {
+	if err = c.Unset("insecure"); err != nil {
 		t.Fatal(err)
 	}
 	if m, err = c.FlatMap(); err != nil {
@@ -395,3 +426,35 @@ func TestWriteInvalidNames(t *testing.T) {
 		t.Errorf("expected error: %v", config.ErrReservedConfigName)
 	}
 }
+
+func TestProperies(t *testing.T) {
+	c := config.Configuration{}
+
+	got := c.Properties()
+	want := []string{
+		"registry.address",
+		"registry.insecure",
+		"registry.location",
+		"registry.project",
+		"registry.token",
+		"token-source",
+	}
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("unexpected diff: (-want +got):\n%s", diff)
+	}
+}
+
+func TestResolve(t *testing.T) {
+	c := config.Configuration{
+		TokenSource: "echo hello",
+	}
+
+	err := c.Resolve()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if c.Registry.Token != "hello" {
+		t.Errorf("want: %s, got: %s", "hello", c.Registry.Token)
+	}
+}