Skip to content

Commit

Permalink
Add general purpose config env var getter
Browse files Browse the repository at this point in the history
Similar to the existing one for active help, but generalized.
  • Loading branch information
scop committed Oct 24, 2023
1 parent daa2f6f commit 10e1583
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
29 changes: 29 additions & 0 deletions completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package cobra
import (
"fmt"
"os"
"regexp"
"strings"
"sync"

Expand Down Expand Up @@ -895,3 +896,31 @@ func CompError(msg string) {
func CompErrorln(msg string) {
CompError(fmt.Sprintf("%s\n", msg))
}

// configEnvVarGlobalPrefix should not be changed: users will be using it explicitly.
const configEnvVarGlobalPrefix = "COBRA"

var configEnvVarPrefixSubstRegexp = regexp.MustCompile(`[^A-Z0-9_]`)

// configEnvVar returns the name of the program-specific configuration environment
// variable. It has the format <PROGRAM>_<SUFFIX> where <PROGRAM> is the name of the
// root command in upper case, with all non-ASCII-alphanumeric characters replaced by `_`.
func configEnvVar(name, suffix string) string {
// This format should not be changed: users will be using it explicitly.
v := strings.ToUpper(fmt.Sprintf("%s_%s", name, suffix))
v = configEnvVarPrefixSubstRegexp.ReplaceAllString(v, "_")
return v
}

// GetEnvConfig returns the value of the configuration environment variable
// <PROGRAM>_<SUFFIX> where <PROGRAM> is the name of the root command in upper
// case, with all non-ASCII-alphanumeric characters replaced by `_`.
// If the value is empty or not set, the value of the environment variable
// COBRA_<SUFFIX> is returned instead.
func GetEnvConfig(cmd *Command, suffix string) string {
v := os.Getenv(configEnvVar(cmd.Root().Name(), suffix))
if v == "" {
v = os.Getenv(configEnvVar(configEnvVarGlobalPrefix, suffix))
}
return v
}
76 changes: 76 additions & 0 deletions completions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package cobra
import (
"bytes"
"context"
"os"
"strings"
"testing"
)
Expand Down Expand Up @@ -3277,3 +3278,78 @@ Completion ended with directive: ShellCompDirectiveNoFileComp
})
}
}

func TestGetEnvConfig(t *testing.T) {
testCases := []struct {
use string
suffix string
cmdVar string
globalVar string
cmdVal string
globalVal string
expected string
}{
{
use: "root",
suffix: "test",
cmdVar: "ROOT_TEST",
globalVar: "COBRA_TEST",
cmdVal: "cmd",
globalVal: "global",
expected: "cmd",
},
{
use: "root",
suffix: "test",
cmdVar: "ROOT_TEST",
globalVar: "COBRA_TEST",
cmdVal: "",
globalVal: "global",
expected: "global",
},
{
use: "root",
suffix: "test",
cmdVar: "ROOT_TEST",
globalVar: "COBRA_TEST",
cmdVal: "",
globalVal: "",
expected: "",
},
{
use: "foo.bar",
suffix: "test",
cmdVar: "FOO_BAR_TEST",
globalVar: "COBRA_TEST",
cmdVal: "cmd",
globalVal: "global",
expected: "cmd",
},
{
use: "quux-BAZ",
suffix: "test",
cmdVar: "QUUX_BAZ_TEST",
globalVar: "COBRA_TEST",
cmdVal: "cmd",
globalVal: "global",
expected: "cmd",
},
}

for _, tc := range testCases {
// Could make env handling cleaner with t.Setenv with Go >= 1.17
func() {
err := os.Setenv(tc.cmdVar, tc.cmdVal)
defer assertNoErr(t, os.Unsetenv(tc.cmdVar))
assertNoErr(t, err)
err = os.Setenv(tc.globalVar, tc.globalVal)
defer assertNoErr(t, os.Unsetenv(tc.globalVar))
assertNoErr(t, err)
cmd := &Command{Use: tc.use}
got := GetEnvConfig(cmd, tc.suffix)
if got != tc.expected {
t.Errorf("expected: %q, got: %q", tc.expected, got)
}
}()
}
}

0 comments on commit 10e1583

Please sign in to comment.