diff --git a/client.go b/client.go index c1e7bd236..f5e6d40ad 100644 --- a/client.go +++ b/client.go @@ -14,7 +14,7 @@ import ( "runtime/debug" "time" - "github.com/mitchellh/go-homedir" + "knative.dev/kn-plugin-func/config" ) const ( @@ -27,11 +27,6 @@ const ( // includes an HTTP Handler ("http") and Cloud Events handler ("events") DefaultTemplate = "http" - // DefaultConfigPath is used in the unlikely event that - // the user has no home directory (no ~), there is no - // XDG_CONFIG_HOME set, and no WithConfigPath was used. - DefaultConfigPath = ".config/func" - // RunDataDir holds transient runtime metadata // By default it is excluded from source control. RunDataDir = ".func" @@ -207,7 +202,7 @@ func New(options ...Option) *Client { dnsProvider: &noopDNSProvider{output: os.Stdout}, progressListener: &NoopProgressListener{}, pipelinesProvider: &noopPipelinesProvider{}, - repositoriesPath: filepath.Join(ConfigPath(), "repositories"), + repositoriesPath: filepath.Join(config.Path(), "repositories"), transport: http.DefaultTransport, } for _, o := range options { @@ -220,35 +215,12 @@ func New(options ...Option) *Client { c.instances = newInstances(c) // Trigger the creation of the config and repository paths - _ = ConfigPath() // Config is package-global scoped + _ = config.Path() _ = c.RepositoriesPath() // Repositories is Client-specific return c } -// The default config path is evaluated in the following order, from lowest -// to highest precedence. -// 1. The static default is DefaultConfigPath (./.config/func) -// 2. ~/.config/func if it exists (can be expanded: user has a home dir) -// 3. The value of $XDG_CONFIG_PATH/func if the environment variable exists. -// The path will be created if it does not already exist. -func ConfigPath() (path string) { - path = DefaultConfigPath - - // ~/.config/func is the default if ~ can be expanded - if home, err := homedir.Expand("~"); err == nil { - path = filepath.Join(home, ".config", "func") - } - - // 'XDG_CONFIG_HOME/func' takes precidence if defined - if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" { - path = filepath.Join(xdg, "func") - } - - mkdir(path) // make sure it exists - return -} - // RepositoriesPath accesses the currently effective repositories path, // which defaults to [ConfigPath]/repositories but can be set explicitly using // the WithRepositoriesPath option when creating the client.. diff --git a/cmd/build.go b/cmd/build.go index eab204473..ad403aeb7 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/cobra" "knative.dev/kn-plugin-func/buildpacks" + "knative.dev/kn-plugin-func/config" "knative.dev/kn-plugin-func/s2i" fn "knative.dev/kn-plugin-func" @@ -50,9 +51,15 @@ and the image name is stored in the configuration file. PreRunE: bindEnv("image", "path", "builder", "registry", "confirm", "push", "builder-image", "platform"), } + // Config + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + cmd.Flags().StringP("builder", "b", builders.Default, fmt.Sprintf("build strategy to use when creating the underlying image. Currently supported build strategies are %s.", KnownBuilders())) cmd.Flags().StringP("builder-image", "", "", "builder image, either an as a an image name or a mapping name.\nSpecified value is stored in func.yaml (as 'builder' field) for subsequent builds. ($FUNC_BUILDER_IMAGE)") - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") cmd.Flags().StringP("image", "i", "", "Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry (Env: $FUNC_IMAGE)") cmd.Flags().StringP("registry", "r", GetDefaultRegistry(), "Registry + namespace part of the image to build, ex 'quay.io/myuser'. The full image name is automatically determined (Env: $FUNC_REGISTRY)") cmd.Flags().BoolP("push", "u", false, "Attempt to push the function image after being successfully built") diff --git a/cmd/create.go b/cmd/create.go index 86309c223..8b31a4623 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -13,6 +13,7 @@ import ( "github.com/spf13/cobra" fn "knative.dev/kn-plugin-func" + "knative.dev/kn-plugin-func/config" "knative.dev/kn-plugin-func/utils" ) @@ -74,11 +75,17 @@ EXAMPLES PreRunE: bindEnv("language", "template", "repository", "confirm"), } + // Config + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + // Flags - cmd.Flags().StringP("language", "l", "", "Language Runtime (see help text for list) (Env: $FUNC_LANGUAGE)") + cmd.Flags().StringP("language", "l", cfg.Language, "Language Runtime (see help text for list) (Env: $FUNC_LANGUAGE)") cmd.Flags().StringP("template", "t", fn.DefaultTemplate, "Function template. (see help text for list) (Env: $FUNC_TEMPLATE)") cmd.Flags().StringP("repository", "r", "", "URI to a Git repository containing the specified template (Env: $FUNC_REPOSITORY)") - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") // Help Action cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { runCreateHelp(cmd, args, newClient) }) diff --git a/cmd/create_test.go b/cmd/create_test.go index 56d3d2a9a..3cc6f1527 100644 --- a/cmd/create_test.go +++ b/cmd/create_test.go @@ -107,3 +107,27 @@ func TestCreateConfig_RepositoriesPath(t *testing.T) { t.Fatalf("expected repositories default path to be '%v', got '%v'", expected, cfg.RepositoriesPath) } } + +// TestCreate_ConfigOptional ensures that the system can be used without +// any additional configuration being required. +func TestCreate_ConfigOptional(t *testing.T) { + // Empty Home + // the func directory, and other static assets will be created here + // if they do not exist. + home, rm := Mktemp(t) + defer rm() + t.Setenv("XDG_CONFIG_HOME", home) + + // Immediately using "create" in a new empty directory should not fail; + // even when this home directory is devoid of config files. + _, rm2 := Mktemp(t) + defer rm2() + cmd := NewCreateCmd(NewClient) + cmd.SetArgs([]string{"--language=go"}) + if err := cmd.Execute(); err != nil { + t.Fatal(err) + } + + // Not failing is success. Config files or settings beyond what are + // automatically written to to the given config home are currently optional. +} diff --git a/cmd/delete.go b/cmd/delete.go index e028c6782..c823f52f3 100644 --- a/cmd/delete.go +++ b/cmd/delete.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" fn "knative.dev/kn-plugin-func" + "knative.dev/kn-plugin-func/config" ) func NewDeleteCmd(newClient ClientFactory) *cobra.Command { @@ -36,7 +37,14 @@ No local files are deleted. SilenceUsage: true, // no usage dump on error } - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") + // Config + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + + // Flag + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") cmd.Flags().StringP("all", "a", "true", "Delete all resources created for a function, eg. Pipelines, Secrets, etc. (Env: $FUNC_ALL) (allowed values: \"true\", \"false\")") setPathFlag(cmd) diff --git a/cmd/deploy.go b/cmd/deploy.go index f16c5ba75..3ceefa745 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -20,6 +20,7 @@ import ( fn "knative.dev/kn-plugin-func" "knative.dev/kn-plugin-func/builders" "knative.dev/kn-plugin-func/buildpacks" + "knative.dev/kn-plugin-func/config" "knative.dev/kn-plugin-func/docker" "knative.dev/kn-plugin-func/docker/creds" "knative.dev/kn-plugin-func/k8s" @@ -104,7 +105,14 @@ EXAMPLES PreRunE: bindEnv("confirm", "env", "git-url", "git-branch", "git-dir", "remote", "build", "builder", "builder-image", "image", "registry", "push", "platform", "path", "namespace"), } - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") + // Config + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + + // Flags + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") cmd.Flags().StringArrayP("env", "e", []string{}, "Environment variable to set in the form NAME=VALUE. "+ "You may provide this flag multiple times for setting multiple environment variables. "+ "To unset, specify the environment variable name followed by a \"-\" (e.g., NAME-).") diff --git a/cmd/deploy_test.go b/cmd/deploy_test.go index d8d396c1f..02e6997a3 100644 --- a/cmd/deploy_test.go +++ b/cmd/deploy_test.go @@ -285,7 +285,7 @@ func testBuilderPersists(cmdFn commandConstructor, t *testing.T) { t.Fatal(err) } if f.Build.Builder != builders.S2I { - t.Fatal("value of builder flag not persisted when provided") + t.Fatalf("value of builder flag not persisted when provided. Expected '%v' got '%v'", builders.S2I, f.Build.Builder) } // Build the function again without specifying a Builder @@ -316,19 +316,19 @@ func testBuilderPersists(cmdFn commandConstructor, t *testing.T) { t.Fatal(err) } if f.Build.Builder != builders.Pack { - t.Fatal("value of builder flag not persisted on subsequent build") + t.Fatalf("value of builder flag not persisted on subsequent build. Expected '%v' got '%v'", builders.Pack, f.Build.Builder) } // Build the function, specifying a platform with "pack" Builder cmd.SetArgs([]string{"--platform", "linux"}) if err := cmd.Execute(); err == nil { - t.Fatal("Expected error") + t.Fatal("Expected error using --platform without s2i builder was not received") } // Set an invalid builder cmd.SetArgs([]string{"--builder", "invalid"}) if err := cmd.Execute(); err == nil { - t.Fatal("Expected error") + t.Fatal("Expected error using an invalid --builder not received") } } diff --git a/cmd/invoke.go b/cmd/invoke.go index 62984ee7d..8197868ed 100644 --- a/cmd/invoke.go +++ b/cmd/invoke.go @@ -12,6 +12,7 @@ import ( "github.com/spf13/cobra" fn "knative.dev/kn-plugin-func" + "knative.dev/kn-plugin-func/config" "knative.dev/kn-plugin-func/utils" ) @@ -105,6 +106,12 @@ EXAMPLES PreRunE: bindEnv("path", "format", "target", "id", "source", "type", "data", "content-type", "file", "insecure", "confirm"), } + // Config + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + // Flags setPathFlag(cmd) cmd.Flags().StringP("format", "f", "", "Format of message to send, 'http' or 'cloudevent'. Default is to choose automatically. (Env: $FUNC_FORMAT)") @@ -116,7 +123,7 @@ EXAMPLES cmd.Flags().StringP("data", "", fn.DefaultInvokeData, "Data to send in the request. (Env: $FUNC_DATA)") cmd.Flags().StringP("file", "", "", "Path to a file to use as data. Overrides --data flag and should be sent with a correct --content-type. (Env: $FUNC_FILE)") cmd.Flags().BoolP("insecure", "i", false, "Allow insecure server connections when using SSL. (Env: $FUNC_INSECURE)") - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all options interactively. (Env: $FUNC_CONFIRM)") + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all options interactively. (Env: $FUNC_CONFIRM)") cmd.SetHelpFunc(defaultTemplatedHelp) diff --git a/cmd/repository.go b/cmd/repository.go index 049b11a88..ab79a7491 100644 --- a/cmd/repository.go +++ b/cmd/repository.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/cobra" fn "knative.dev/kn-plugin-func" + "knative.dev/kn-plugin-func/config" ) // command constructors @@ -140,7 +141,14 @@ EXAMPLES PreRunE: bindEnv("confirm"), } - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") + // Config + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + + // Flags + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") cmd.SetHelpFunc(defaultTemplatedHelp) @@ -177,7 +185,12 @@ func NewRepositoryAddCmd(newClient ClientFactory) *cobra.Command { PreRunE: bindEnv("confirm"), } - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") cmd.RunE = func(cmd *cobra.Command, args []string) error { return runRepositoryAdd(cmd, args, newClient) @@ -193,7 +206,12 @@ func NewRepositoryRenameCmd(newClient ClientFactory) *cobra.Command { PreRunE: bindEnv("confirm"), } - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") cmd.RunE = func(cmd *cobra.Command, args []string) error { return runRepositoryRename(cmd, args, newClient) @@ -211,7 +229,12 @@ func NewRepositoryRemoveCmd(newClient ClientFactory) *cobra.Command { PreRunE: bindEnv("confirm"), } - cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") + cfg, err := config.NewDefault() + if err != nil { + fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.ConfigPath(), err) + } + + cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all options interactively (Env: $FUNC_CONFIRM)") cmd.RunE = func(cmd *cobra.Command, args []string) error { return runRepositoryRemove(cmd, args, newClient) diff --git a/config.go b/config.go deleted file mode 100644 index 1aa405da9..000000000 --- a/config.go +++ /dev/null @@ -1,5 +0,0 @@ -package function - -// Config is local and global configuration which is not "part of the function" -// and is thus not likely to be tracked in source control. -type Config struct{} diff --git a/config/config.go b/config/config.go new file mode 100644 index 000000000..dc4b98d79 --- /dev/null +++ b/config/config.go @@ -0,0 +1,121 @@ +package config + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/mitchellh/go-homedir" + "gopkg.in/yaml.v2" +) + +const ( + // Filename into which Config is serialized + Filename = "config.yaml" + + // DefaultConfigPath is used in the unlikely event that + // the user has no home directory (no ~), there is no + // XDG_CONFIG_HOME set + DefaultConfigPath = ".config/func" + + // DefaultLanguage is intentionaly undefined. + DefaultLanguage = "" +) + +type Config struct { + // Language Runtime + Language string `yaml:"language"` + + // Confirm Prompts + Confirm bool `yaml:"confirm"` +} + +// New Config struct with all members set to static defaults. See NewDefaults +// for one which further takes into account the optional config file. +func New() Config { + return Config{ + Language: DefaultLanguage, + // ... + } +} + +// Creates a new config populated by global defaults as defined by the +// config file located in .Path() (the global func settings path, which is +// usually ~/.config/func) +func NewDefault() (cfg Config, err error) { + cfg = New() // cfg now populated by static defaults + p := ConfigPath() // applies ~/.config/func/config.yaml if it exists + if _, err = os.Stat(p); err != nil { + if os.IsNotExist(err) { + err = nil // config file is not required + } + return + } + bb, err := os.ReadFile(p) + if err != nil { + return + } + err = yaml.Unmarshal(bb, &cfg) // cfg now has applied config.yaml + return +} + +// Load the config exactly as it exists at path (no static defaults) +func Load(path string) (c Config, err error) { + if _, err = os.Stat(path); err != nil { + return + } + bb, err := os.ReadFile(path) + if err != nil { + return + } + err = yaml.Unmarshal(bb, &c) + return +} + +// Save the config to the given path +func (c Config) Save(path string) (err error) { + var bb []byte + if bb, err = yaml.Marshal(&c); err != nil { + return + } + return ioutil.WriteFile(path, bb, os.ModePerm) +} + +// Path is derived in the following order, from lowest +// to highest precedence. +// 1. The static default is DefaultConfigPath (./.config/func) +// 2. ~/.config/func if it exists (can be expanded: user has a home dir) +// 3. The value of $XDG_CONFIG_PATH/func if the environment variable exists. +// The path is created if it does not already exist. +func Path() (path string) { + path = DefaultConfigPath + + // ~/.config/func is the default if ~ can be expanded + if home, err := homedir.Expand("~"); err == nil { + path = filepath.Join(home, ".config", "func") + } + + // 'XDG_CONFIG_HOME/func' takes precidence if defined + if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" { + path = filepath.Join(xdg, "func") + } + + mkdir(path) + return +} + +// ConfigPath returns the full path at which to look for a config file. +func ConfigPath() string { + // TODO: It might be nice to include consideration of a FUNC_CONFIG_FILE + // which would allow explicitly setting a config file. + + // usually ~/.config/func/config.yaml + return filepath.Join(Path(), Filename) +} + +func mkdir(path string) { + if err := os.MkdirAll(path, os.ModePerm); err != nil { + fmt.Fprintf(os.Stderr, "Error creating '%v': %v", path, err) + } +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 000000000..ddc655a39 --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,94 @@ +package config_test + +import ( + "path/filepath" + "testing" + + "knative.dev/kn-plugin-func/config" + + . "knative.dev/kn-plugin-func/testing" +) + +// TestNewDefaults ensures that the default Config +// constructor yelds a struct prepopulated with static +// defaults. +func TestNewDefaults(t *testing.T) { + cfg := config.New() + if cfg.Language != config.DefaultLanguage { + t.Fatalf("expected config's language = '%v', got '%v'", config.DefaultLanguage, cfg.Language) + } +} + +// TestLoad ensures that loading a config reads values +// in from a config file at path. +func TestLoad(t *testing.T) { + cfg, err := config.Load("testdata/func/config.yaml") + if err != nil { + t.Fatal(err) + } + if cfg.Language != "custom" { + t.Fatalf("loaded config did not contain values from config file. Expected \"custom\" got \"%v\"", cfg.Language) + } +} + +// TestSave ensures that saving an update config persists. +func TestSave(t *testing.T) { + // mktmp + root, rm := Mktemp(t) + defer rm() + + // touch config.yaml + filename := filepath.Join(root, "config.yaml") + + // update + cfg := config.New() + cfg.Language = "testSave" + + // save + if err := cfg.Save(filename); err != nil { + t.Fatal(err) + } + + // reload + cfg, err := config.Load(filename) + if err != nil { + t.Fatal(err) + } + + // assert persisted + if cfg.Language != "testSave" { + t.Fatalf("config did not persist. expected 'testSave', got '%v'", cfg.Language) + } +} + +// TestPath ensures that the Path accessor returns +// XDG_CONFIG_HOME/.config/func +func TestPath(t *testing.T) { + home := t.TempDir() // root of all configs + path := filepath.Join(home, "func") // our config + + t.Setenv("XDG_CONFIG_HOME", home) + + if config.Path() != path { + t.Fatalf("expected config path '%v', got '%v'", path, config.Path()) + } +} + +// TestNewDefault ensures that the default returned from NewDefault includes +// both the static defaults (see TestNewDefaults), as well as those from the +// currently effective global config path (~/config/func). +func TestNewDefault(t *testing.T) { + // Custom config home results in a config file default path of + // ./testdata/func/config.yaml + home := filepath.Join(Cwd(), "testdata") + t.Setenv("XDG_CONFIG_HOME", home) + + cfg, err := config.NewDefault() // Should load values from above config + if err != nil { + t.Fatal(err) + } + + if cfg.Language != "custom" { + t.Fatalf("config file not loaded") + } +} diff --git a/config/testdata/func/config.yaml b/config/testdata/func/config.yaml new file mode 100644 index 000000000..66ab0826f --- /dev/null +++ b/config/testdata/func/config.yaml @@ -0,0 +1 @@ +language: custom diff --git a/docker/creds/credentials.go b/docker/creds/credentials.go index 479cd0be2..52ab25457 100644 --- a/docker/creds/credentials.go +++ b/docker/creds/credentials.go @@ -14,10 +14,10 @@ import ( "runtime" "strings" - fn "knative.dev/kn-plugin-func" + "knative.dev/kn-plugin-func/config" "knative.dev/kn-plugin-func/docker" - "github.com/containers/image/v5/pkg/docker/config" + dockerConfig "github.com/containers/image/v5/pkg/docker/config" containersTypes "github.com/containers/image/v5/types" "github.com/docker/docker-credential-helpers/client" "github.com/docker/docker-credential-helpers/credentials" @@ -167,7 +167,7 @@ func NewCredentialsProvider(opts ...Opt) docker.CredentialsProvider { } } - c.authFilePath = filepath.Join(fn.ConfigPath(), "auth.json") + c.authFilePath = filepath.Join(config.Path(), "auth.json") sys := &containersTypes.SystemContext{ AuthFilePath: c.authFilePath, } @@ -186,7 +186,7 @@ func NewCredentialsProvider(opts ...Opt) docker.CredentialsProvider { return getCredentialsByCredentialHelper(dockerConfigPath, registry) }, func(registry string) (docker.Credentials, error) { - creds, err := config.GetCredentials(sys, registry) + creds, err := dockerConfig.GetCredentials(sys, registry) if err != nil { return docker.Credentials{}, err } diff --git a/docker/creds/credentials_test.go b/docker/creds/credentials_test.go index 335279a5d..dae25e531 100644 --- a/docker/creds/credentials_test.go +++ b/docker/creds/credentials_test.go @@ -27,7 +27,7 @@ import ( "testing" "time" - fn "knative.dev/kn-plugin-func" + "knative.dev/kn-plugin-func/config" "knative.dev/kn-plugin-func/docker" "knative.dev/kn-plugin-func/docker/creds" . "knative.dev/kn-plugin-func/testing" @@ -536,7 +536,7 @@ func cleanUpConfigs(t *testing.T) { t.Fatal(err) } - os.RemoveAll(fn.ConfigPath()) + os.RemoveAll(config.Path()) os.RemoveAll(filepath.Join(home, ".docker")) } @@ -577,7 +577,7 @@ func withPopulatedFuncAuthConfig(t *testing.T) { var err error - authConfig := filepath.Join(fn.ConfigPath(), "auth.json") + authConfig := filepath.Join(config.Path(), "auth.json") err = os.MkdirAll(filepath.Dir(authConfig), 0700) if err != nil { t.Fatal(err) diff --git a/testing/testing.go b/testing/testing.go index b4521a070..e049bb826 100644 --- a/testing/testing.go +++ b/testing/testing.go @@ -221,3 +221,12 @@ func RunGitServer(t *testing.T, gitRoot string) (hostPort string) { return hostPort } + +// Cwd returns the current working directory or panic if unable to determine. +func Cwd() (cwd string) { + cwd, err := os.Getwd() + if err != nil { + panic(fmt.Sprintf("Unable to determine current working directory: %v", err)) + } + return cwd +}